can I write this without the three if then;s

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

can I write this without the three if then;s

Pharo Smalltalk Users mailing list
Hello,

Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.

I solved it like this :


scoreX: anInteger y: anInteger2
    | distance |
    distance := (anInteger squared + anInteger2 squared) sqrt.
    distance > 10
        ifTrue: [ ^ 0 ].
    distance > 5
        ifTrue: [ ^ 1 ].
    distance > 1
        ifTrue: [ ^ 5 ].
    ^ 10


but now I use three if then and I think it's ugly code.

Is there a way I can make it more the smalltalk way ?


Regards,

Roelof

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

tbrunz
You might try Magnitude >> between: min and: max




--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Pharo Smalltalk Users mailing list
Thanks,

But it looks to me I still need the ifTrue because the between gives
also a true or false.

Roelof



Op 27-12-2019 om 20:38 schreef tbrunz:
> You might try Magnitude >> between: min and: max
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>
>


Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Kasper Osterbye
In reply to this post by Pharo Smalltalk Users mailing list
Hi

First, I think your code is readable and easy to understand.

I think the problem does not lend itself too much towards having “an object oriented solution”, as such.

If you are looking for a one-liner using smalltalk libraries, you could do:
({10 -> 0. 5 -> 1. 1 -> 5. 0 -> 10} detect: [ :dist | dist key < distance ]) value

but I really think your code is easier to read, which is what I appreciate the most.

Best,

Kasper

On 27 December 2019 at 20.18.38, Roelof Wobben via Pharo-users ([hidden email]) wrote:

Hello,

Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.

I solved it like this :


scoreX: anInteger y: anInteger2
    | distance |
    distance := (anInteger squared + anInteger2 squared) sqrt.
    distance > 10
        ifTrue: [ ^ 0 ].
    distance > 5
        ifTrue: [ ^ 1 ].
    distance > 1
        ifTrue: [ ^ 5 ].
    ^ 10


but now I use three if then and I think it's ugly code.

Is there a way I can make it more the smalltalk way ?


Regards,

Roelof

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Pharo Smalltalk Users mailing list
Hello Kasper

Thanks for the feedback.

I also like readable and  easy to understand code but I get the feeling that it;s good practice to use as minimal as possible if then's
So I wonder if and how I can achieve that here.

Roelof


Op 27-12-2019 om 20:47 schreef Kasper Østerbye:
Hi

First, I think your code is readable and easy to understand.

I think the problem does not lend itself too much towards having “an object oriented solution”, as such.

If you are looking for a one-liner using smalltalk libraries, you could do:
({10 -> 0. 5 -> 1. 1 -> 5. 0 -> 10} detect: [ :dist | dist key < distance ]) value

but I really think your code is easier to read, which is what I appreciate the most.

Best,

Kasper

On 27 December 2019 at 20.18.38, Roelof Wobben via Pharo-users ([hidden email]) wrote:

Hello,

Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.

I solved it like this :


scoreX: anInteger y: anInteger2
    | distance |
    distance := (anInteger squared + anInteger2 squared) sqrt.
    distance > 10
        ifTrue: [ ^ 0 ].
    distance > 5
        ifTrue: [ ^ 1 ].
    distance > 1
        ifTrue: [ ^ 5 ].
    ^ 10


but now I use three if then and I think it's ugly code.

Is there a way I can make it more the smalltalk way ?


Regards,

Roelof


Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

tbrunz
In reply to this post by Pharo Smalltalk Users mailing list
I would probably set up an array of associations whose keys are the boundary
limits and whose values are the target values (ordered, in this example,
from outer to inner).  

Then loop over the array's associations using inject:into:, testing for the
point where (each < key), at which point you return the previous
association's value.

-t




--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

tbrunz
Doing it the way I describe above eliminates repetitive if-then statements
('switch' or 'case' statements in other languages, which make for a
maintenance mess), automatically extends for additional rings, doesn't embed
"magic numbers" for defined rings within the decision logic, and takes
advantage of the naturally recursive nature of this kind of graduated
comparison test.

-t



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

tbrunz
You could also accomplish this with a simple 'do:' construct by creating the
associations with the the ring limits & points "staggered" (by one level),
so that when (each < key) you can return the 'current' association value...

Which, now that I'm looking closely at your solution, Kasper, seems to be
what you already proposed...  Either should work.



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Richard O'Keefe
In reply to this post by Pharo Smalltalk Users mailing list
Myself, I see only one issue in your code, and that is the pointless
use of sqrt.
scoreX: anInteger y: anInteger2
    | radiusSquared |
    radiusSquared := anInteger squared + anInteger2 squared.
    radiusSquared > 100
        ifTrue: [ ^ 0 ].
    radiusSquared > 25
        ifTrue: [ ^ 1 ].
    radiusSquared > 1
        ifTrue: [ ^ 5 ].
    ^ 10

Make that two issues.  The names anInteger and anInteger2.
How about
scoreHorizontal: horizontal vertical: vertical
  ...

The OO dogma about "if' that you refer to is about not using
"if" to make decisions based on TYPE.  Making decisions based
on NUMERIC RANGES is perfectly OK.

You could introduce a 'HalfOpenRangeDictionary" class
[K1,K2) -> V1
[K2,K3) -> V2
...
[Kn,infinity) -> Vn
But "You Ain't Gonna Need It", so don't.

On Sat, 28 Dec 2019 at 08:18, Roelof Wobben via Pharo-users
<[hidden email]> wrote:

>
> Hello,
>
> Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.
>
> I solved it like this :
>
>
> scoreX: anInteger y: anInteger2
>     | distance |
>     distance := (anInteger squared + anInteger2 squared) sqrt.
>     distance > 10
>         ifTrue: [ ^ 0 ].
>     distance > 5
>         ifTrue: [ ^ 1 ].
>     distance > 1
>         ifTrue: [ ^ 5 ].
>     ^ 10
>
>
> but now I use three if then and I think it's ugly code.
>
> Is there a way I can make it more the smalltalk way ?
>
>
> Regards,
>
> Roelof
>

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Pharo Smalltalk Users mailing list
Hello Richard,

Thanks for the feedback. I was using it because the challenge was
talking about it, that yu have the use the formula
a ^2  +  b ^2  =  c ^2   and the challenge was talking about the
distance and not the distance squared.

I think a better name schould be then x or xCoordinate and y or
Y_Coordinate.

Roelof



Op 27-12-2019 om 22:48 schreef Richard O'Keefe:

> Myself, I see only one issue in your code, and that is the pointless
> use of sqrt.
> scoreX: anInteger y: anInteger2
>      | radiusSquared |
>      radiusSquared := anInteger squared + anInteger2 squared.
>      radiusSquared > 100
>          ifTrue: [ ^ 0 ].
>      radiusSquared > 25
>          ifTrue: [ ^ 1 ].
>      radiusSquared > 1
>          ifTrue: [ ^ 5 ].
>      ^ 10
>
> Make that two issues.  The names anInteger and anInteger2.
> How about
> scoreHorizontal: horizontal vertical: vertical
>    ...
>
> The OO dogma about "if' that you refer to is about not using
> "if" to make decisions based on TYPE.  Making decisions based
> on NUMERIC RANGES is perfectly OK.
>
> You could introduce a 'HalfOpenRangeDictionary" class
> [K1,K2) -> V1
> [K2,K3) -> V2
> ...
> [Kn,infinity) -> Vn
> But "You Ain't Gonna Need It", so don't.
>
> On Sat, 28 Dec 2019 at 08:18, Roelof Wobben via Pharo-users
> <[hidden email]> wrote:
>> Hello,
>>
>> Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.
>>
>> I solved it like this :
>>
>>
>> scoreX: anInteger y: anInteger2
>>      | distance |
>>      distance := (anInteger squared + anInteger2 squared) sqrt.
>>      distance > 10
>>          ifTrue: [ ^ 0 ].
>>      distance > 5
>>          ifTrue: [ ^ 1 ].
>>      distance > 1
>>          ifTrue: [ ^ 5 ].
>>      ^ 10
>>
>>
>> but now I use three if then and I think it's ugly code.
>>
>> Is there a way I can make it more the smalltalk way ?
>>
>>
>> Regards,
>>
>> Roelof
>>


Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Dennis Schetinin
In reply to this post by Pharo Smalltalk Users mailing list
It would be an overkill to do it for this particular case, but Smalltalk makes it possible to implement a case-like construction:

[ expression ] 
     when: [ :value | condition1 ] do: [-0do :value | ... ]; 
     when: [ :value | condition2 ] do: [ :value | ... ]; 
     otherwiseDo: [ :value | ... ];
     evaluate


I am sure, something like this has been implemented already somewhere (maybe in Squeak?). Still not sure it is practical as compared to simple if-s, and for sure not widely used :)
...On the other hand, sometimes the case-like construction can be considered a more intension-revealing style. 

пт, 27 дек. 2019 г., 22:18 Roelof Wobben via Pharo-users <[hidden email]>:
Hello,

Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.

I solved it like this :


scoreX: anInteger y: anInteger2
    | distance |
    distance := (anInteger squared + anInteger2 squared) sqrt.
    distance > 10
        ifTrue: [ ^ 0 ].
    distance > 5
        ifTrue: [ ^ 1 ].
    distance > 1
        ifTrue: [ ^ 5 ].
    ^ 10


but now I use three if then and I think it's ugly code.

Is there a way I can make it more the smalltalk way ?


Regards,

Roelof

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

EstebanLM
The “Kent Beck approved solutions” here are two: 

1) To use a dictionary (or ordered dictionary).


case := OrderedDictionary newFromPairs: {
  [ cond ]. [ do ].
[ cond ]. [ do ].
[ true ]. [ otherwise do ] }

case keysAndValuesDo: [  :cond :do | 
(cond value: expression)  ifTrue: [
“you need to break here"
^ do value ].

2) To use a “case method”

caseMethod: expression 

expression = cond1 ifTrue: [ ^ do1 ].
expression = cond2 ifTrue: [ ^ do2 ].
^ otherwise

Personally, I prefer the second one because is more concise, performant and easy to understand.

Esteban


On 28 Dec 2019, at 11:58, Dennis Schetinin <[hidden email]> wrote:

It would be an overkill to do it for this particular case, but Smalltalk makes it possible to implement a case-like construction:

[ expression ] 
     when: [ :value | condition1 ] do: [-0do :value | ... ]; 
     when: [ :value | condition2 ] do: [ :value | ... ]; 
     otherwiseDo: [ :value | ... ];
     evaluate


I am sure, something like this has been implemented already somewhere (maybe in Squeak?). Still not sure it is practical as compared to simple if-s, and for sure not widely used :)
...On the other hand, sometimes the case-like construction can be considered a more intension-revealing style. 

пт, 27 дек. 2019 г., 22:18 Roelof Wobben via Pharo-users <[hidden email]>:
Hello,

Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.

I solved it like this :


scoreX: anInteger y: anInteger2
    | distance |
    distance := (anInteger squared + anInteger2 squared) sqrt.
    distance > 10
        ifTrue: [ ^ 0 ].
    distance > 5
        ifTrue: [ ^ 1 ].
    distance > 1
        ifTrue: [ ^ 5 ].
    ^ 10


but now I use three if then and I think it's ugly code.

Is there a way I can make it more the smalltalk way ?


Regards,

Roelof


Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Richard Sargent
Administrator
In reply to this post by Pharo Smalltalk Users mailing list
Pharo Smalltalk Users mailing list wrote

> Hello,
>    
>     Im trying to solve a challenge from exercism where  I have to
>     calculate the points somehow gets on a very simple darts board.
>    
>     I solved it like this :
>    
>      
>       scoreX: anInteger y: anInteger2
>           | distance |
>           distance := (anInteger squared + anInteger2 squared) sqrt.
>           distance &gt; 10
>               ifTrue: [ ^ 0 ].
>           distance &gt; 5
>               ifTrue: [ ^ 1 ].
>           distance &gt; 1
>               ifTrue: [ ^ 5 ].
>           ^ 10
>      
>      
>       but now I use three if then and I think it's ugly code.
>      
>       Is there a way I can make it more the smalltalk way ?

Roelof, this example is too simple to "really do it the Smalltalk way".

In a more realistic scenario, you would have classes for each "rule" with
corresponding differences in behaviour. In the above example, you could get
away with a single class with two instance variables and configure three
instances of it appropriately.

In more complex scenarios, your start up code instantiates the various
rules, with precedence determined by the order of the rule instances. Then
when you need to determine which rule to apply, you use #detect:ifNone: to
find the rule that applies with the #ifNone: block providing the fallback
result.

Sometimes, you work with classes themselves to determine which class to use,
but I have described working with instances for the general concept. (After
all, classes are instances.)

Using rules with a #select: allows you to handle a scenario where multiple
rules apply. A good example is rules to provide the default coverages for an
auto insurance policy, where each possible coverage can have one or more
rules to assess the many characteristics of the applicants and so determine
the one rule that applies for each possible coverage. (And yes, it is
reasonable that a possible coverage has no rule applicable, in which case
the coverage is not included in the default offering.)


As mentioned, you /could/ apply this to your scenario, as an exercise. You
might be tempted to utilize an existing class with two instance variables.
That would be a bad design practice, but reasonable for a /disposable/
experiment to quickly study how it works. Always (create and) use classes
which truly reflect their purpose and have named properties which truly
reflect the objects they hold. In your scenario, #distance and #score seem
appropriate.

     

>      
>       Regards,
>      
>       Roelof





--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

ponyatov
In reply to this post by Pharo Smalltalk Users mailing list
What Smalltalk has for full-sized pattern matching?
Is it possible to make in message-only syntax?



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: can I write this without the three if then;s

Richard O'Keefe
In reply to this post by Dennis Schetinin
Start with
scoreX: anInteger y: anInteger2
    | distance |
    distance := (anInteger squared + anInteger2 squared) sqrt.
    distance > 10
        ifTrue: [ ^ 0 ].
    distance > 5
        ifTrue: [ ^ 1 ].
    distance > 1
        ifTrue: [ ^ 5 ].
    ^ 10

(1) Use better argument names.
(2) Forget about the square root.
(3) Note the repetitive pattern.
So
scoreX: x y: y
    | distanceSquared |
    distanceSquared := x squared + y squared.
    #((100 0) (25 1) (1 5)) do: [:each |
        distanceSquared > each first ifTrue: [^each last]].
    ^10

But I'd say that apart from the argument names and pointless square root,
your original code is about as clear as it gets.
The "ifs stink" dogma is about *type* testing, not *range* testing,
and this is range testing.  It is also a tiny piece of code which
can only be made *less* readable by trying to avoid the ifs.
Remember the slogan YAGNI?  You Ain't Gonna Need it?
The time to go for a more elaborate solution is when you HAVE to.
Do The Simplest Thing That Could Possibly Work.

On Sat, 28 Dec 2019 at 23:59, Dennis Schetinin <[hidden email]> wrote:

>
> It would be an overkill to do it for this particular case, but Smalltalk makes it possible to implement a case-like construction:
>
> [ expression ]
>      when: [ :value | condition1 ] do: [-0do :value | ... ];
>      when: [ :value | condition2 ] do: [ :value | ... ];
>      otherwiseDo: [ :value | ... ];
>      evaluate
>
>
> I am sure, something like this has been implemented already somewhere (maybe in Squeak?). Still not sure it is practical as compared to simple if-s, and for sure not widely used :)
> ...On the other hand, sometimes the case-like construction can be considered a more intension-revealing style.
>
> пт, 27 дек. 2019 г., 22:18 Roelof Wobben via Pharo-users <[hidden email]>:
>>
>> Hello,
>>
>> Im trying to solve a challenge from exercism where  I have to calculate the points somehow gets on a very simple darts board.
>>
>> I solved it like this :
>>
>>
>> scoreX: anInteger y: anInteger2
>>     | distance |
>>     distance := (anInteger squared + anInteger2 squared) sqrt.
>>     distance > 10
>>         ifTrue: [ ^ 0 ].
>>     distance > 5
>>         ifTrue: [ ^ 1 ].
>>     distance > 1
>>         ifTrue: [ ^ 5 ].
>>     ^ 10
>>
>>
>> but now I use three if then and I think it's ugly code.
>>
>> Is there a way I can make it more the smalltalk way ?
>>
>>
>> Regards,
>>
>> Roelof
>>