smalltalk block - can I explicitly set the returning value and stop executing the block? - block

The return value of #value: message, when sent to a block, is the value of the last sentence in that block. So [ 1 + 2. 3 + 4. ] value evaluates to 7.
I find that hard to use sometimes. Is there a way to explicitly set the returning value and stop executing the block?
For exercise, try rewriting this block without using my imaginary #return: message and see how ugly it gets. I must be missing something.
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [ self return: nil ] ifFalse: [ self return: true ] ].
two ifNil: [ self return: false ].
(one > two)
ifTrue: [ self return: true ]
ifFalse: [ (one < two)
ifTrue: [ self return: false ]
ifFalse: [ self return: nil ]
].
]
EDIT: self return: sth really is nonsense, but it does make sense at some level :)

There's nothing like a guard clause - blah ifTrue: [^ foo] - inside a block, because ^ is a non-local return, returning from the method calling the block rather than the block itself.
Big blocks - like big anythings - should be refactored into smaller, more understandable/tractable subparts, but sometimes that's not always possible. I mean this answer to suggest options to try when you can't really simplify in the usual ways.
If your block is really that complicated, and you can't get it simpler (splitting it up delocalises the information too much, for instance) then perhaps you can use an explicit return value. In particular, if your block doesn't return nil you could do something like
[:one :two | | result |
result := (one isNil and: [two isNil]) ifTrue: [false].
result ifNil: ["do one thing, possibly setting result"].
result]
If your block can return nil, you'll need another sentinel value:
[:one :two | | result marker |
result := marker := Object new.
(result == marker) ifTrue: ["do one thing, possibly setting result"].
result]
Lastly - and I hesitate to suggest this - you could do this:
[1 + 2.
thisContext return: 5.
3 + 4] value
which returns 5.
(Verifying how this interacts with ^ and inlined selectors like #ifTrue:ifFalse: left as an exercise for the reader.)

It seems that your code tries to handles nil like an infinity value when comparing one and two. The following code may be more readable depending on the context:
a := [:one :two |
| x y |
x := one ifNil: [Float infinity].
y := two ifNil: [Float infinity].
(x = y) ifTrue: [nil] ifFalse: [x > y]]
A useful feature of #ifTrue:ifFalse:, #ifNil:ifNotNil: and similar testing methods is that they return the value of the block that gets evaluated. e.g. (4 > 1) ifTrue: ['greater'] ifFalse: ['not-greater'] evaluates to 'greater'. This feature often makes it possible to return a value from a nested block in tail position.
When the code inside a block gets too complicated I suggest your refactor it to a method. But see Frank's answer for workarounds.
Edit:
As pointed out in the comments the code above assumes numbers. I also came up with something that works with other comparable objects:
a:=
[ :one :two |
true caseOf: {
[one = two]->[nil].
[one isNil]->[true].
[two isNil]->[false]
} otherwise: [one>two]]
That #caseOf: construct is rarely used but it's certainly better than thisContext return:

You'd like to implement some break, continue, exit...
The usual way to control flow in Smalltalk is with blocks.
So one funny solution is to use a helper method with a Block return value to break the flow, like described here .
Object>>exitThru: aBlock
^aBlock value: [:result | ^result]
Now, let see how to use it:
| aBlock |
aBlock := [ :one :two |
self exitThru: [:exit |
one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ].
two isNil ifTrue: [ exit value: false ].
one > two ifTrue: [ exit value: true ].
one < two ifTrue: [ exit value: false ].
exit value: nil] ].
#(('abc' nil) (nil nil) (nil 'def') ('y' 'abc') ('y' 'y') ('y' 'z'))
collect:
[:pair |
aBlock value: pair first value: pair last ]
-> #(false nil true true nil false)
EDIT my first version was unnecessarily complex, can't remember what lead me to an additional indirection:
| aBlock |
aBlock := [:wrapOne :wrapTwo |
self exitThru: [:exit |
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ].
two isNil ifTrue: [ exit value: false ].
one > two ifTrue: [ exit value: true ].
one < two ifTrue: [ exit value: false ].
exit value: nil ]
value: wrapOne value: wrapTwo ] ].
Well, more funny than usefull, I hope you will find more simple and expressive way to code.

Related

Generate test method with their body in pharo

I advanced a little in my code but I find myself facing another problem for two days. I would like to generate a test method using only the source code. But I have no idea how to do it.
I have a method that allows me to build the name of a test method but I can't write in it.
buildSelectorFor: aMethod
^ String streamContents: [:i || capitalize |
capitalize := true.
i << 'test'.
aMethod selector do: [:charactar |
charactar= $:
ifTrue: [ capitalize := true ]
ifFalse: [ capitalize
ifTrue: [
capitalize := false.
i << charactar asUppercase. ]
ifFalse:[ i << charactar ]]]]
so if I execute this method with this for example:
buildSelectorFor:Car>>#speed:mark:
I get this:
testSpeedMark
my goal is to get something like
testSpeedMark
self assert:....equals:...
I added a method writeTestMethod.
writeTestMethod: aMethod with: anObject
^(self buildTestSelectorFor: aMethod),'
|classMethod setter instObject method|
classMethod := aMethod methodClass.
setter := (classMethod allSelectorsInProtocol: #setter) asArray.
instObject := classMethod new.
(setter with: anObject do: [:set :ivar | instObject perform: set with: ivar]).
self assert: instObject class equals: (classMethod new) class.'
So here is what I get:
I don't know how to integrate the parameters of writetestMethod in the code I want to generate

Smalltalk - is there something similar to && from C?

I have to write a pure-object Smalltalk program, in which I need to evaluate conditions until one of them fails. I know that in C, we can use the && operator for this, and conditions only get evalutated if necessary.
Is there something similar in Smalltalk?
Conditional "anding" can be achieved by using the & message, or the and: message.
firstBooleanExpression & secondBooleanExpression
ifTrue: [ 'do something' ].
Using & as show above, the second part of the condition (secondBooleanExpression) is evaluated regardless of whether the first half evaluates to true or false.
(firstBooleanExpression and: [secondBooleanExpression])
ifTrue: [ 'do something' ].
Using and:, on the other hand, the second part is only evaluated if the first half evaluates to true. Typically you'd use this form, unless you explicitly wanted to evaluate the second half.
The same principle applies to or:.
If I understand your question, you're looking for something like this:
[ <condition> ] whileTrue: [ <loop body> ].
#whileTrue: is not a keyword of course and you could implement it yourself (look at the implementation in your Smalltalk of choice and be enlightened :)).
If you don't need a loop but are simply looking for a way to express conditionals then #ifTrue:, #ifFalse:, #ifTrue:ifFalse: and #ifFalse:ifTrue: are your friends. Examples:
myCollection isEmpty ifTrue: [ Transcript open; show: 'empty'; cr ].
myCollection isEmpty ifFalse: [ Transcript open; show: 'not empty' cr ].
myBoolean
ifTrue: [ Transcript open; show: 'true'; cr ]
ifFalse: [ Transcript open; show: 'false'; cr ].

Can a block in Smalltalk be run by itself?

I know blocks can be passed and used in that way.
But is there any way to call a block, just by having a block? Something like this?
aBlock := [ ... ].
aBlock run.
I tried searching for the BlockClosure class in the System browser, but couldn't find it.
Yes! And in fact, you can do pretty interesting things with them, like activating them within themselves. For example, this block computes factorial recursively calling itself:
factorialBlock := [:n |
n <= 1
ifTrue: [n]
ifFalse: [n * (factorialBlock value: n - 1)]
]
and to try it:
factorialBlock value: 5
That would not be an example of a very good coding practice, but it is of the power of block closures!
Let's add that besides value, if your block has arguments, you can also use
[:f | <do something with f>] value: a
where f is a formal argument (an unbound variable name) and a is an actual object that will bind to f when #value: is sent.
For two arguments use value:value: and for many valueWithArguments:, which receives an Array.
Examples
[:x | x squared - 1] value: 3
-> 3 squared - 1 (i.e., 8)
[:x :y | x + 2 / (y - 4)] value: 2 value: 0
-> 2 + 2 / (0 - 4) (i.e., -1)
Exercise
What's the result of evaluating the following?:
block := [:x | x value: 2].
block value: [:y | y + 1]
Yes it can. Also, you send the message 'value' to it to evaluate the block, not 'run'. In fact, you do not have to assign it to a variable. You can just do this:
[ ... ] value.
Check this one:
Lambda Calculus in Pharo
Yes, the Y Combinator is useful in normal programs
https://medium.com/concerning-pharo/lambda-calculus-in-pharo-a4a571869594#.2a78xp31s
From the article:
ycombinator := [ :f |
[ :g | g value: g ] value: [ :g |
f value: [ :x |
(g value: g) value: x ] ] ]
The force is strong in this one.

Can not call "function" in GNU Smalltalk

I want to define block and call it in this way:
add := [ :a :b |
^(a+b).
].
n := add value: 1 value: 2.
But when I try it, I get an error:
$ gst 3.1.st
Object: 3 error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151)
SmallInteger(Object)>>badReturnError (Object.st:1389)
UndefinedObject>>executeStatements (3.1.st:3)
How can I call a function in GNU Smalltalk?
Well, I dropped the return statement, and this code works fine. But when I try to define more complicated function, for example:
nod := [ :a :b |
(a=b) ifTrue: [a].
(a>b) ifTrue: [nod value: (a-b) value: b].
(a<b) ifTrue: [nod value: a value: (b-a)].
].
n := nod value: 1 value: 2.
n printNl.
It prints nil. And if I define with "early exit":
nod := [ :a :b |
(a=b) ifTrue: [^a].
(a>b) ifTrue: [nod value: (a-b) value: b].
(a<b) ifTrue: [nod value: a value: (b-a)].
].
n := nod value: 1 value: 2.
n printNl.
It gives me the same error: return from a dead method context.
I solve this problem in this way:
nod := [ :a :b |
(a=b) ifTrue: [
a
] ifFalse: [
(a>b) ifTrue: [nod value: (a-b) value: b] ifFalse: [nod value: a value: (b-a)].
]
].
n := nod value: 1 value: 2.
n printNl.
But I think, it is not beautiful way.
Drop the return statement (^) from your code and it will work fine.
In smalltalk, returning exits the method in which the return statement appears. It's used for early exits, for example a < b ifTrue: [^a] ifFalse:[^b].
In this case, you don't want the block to exit the containing method, you just want it to evaluate to something when sending it value:value:. A block evaluates to the last statement in it, so just make it a regular statement there and it will do the trick.
The error message you got, by the way, also explains the problem: you're trying to return 3 from a method which is already dead.
Remove non-local return (^), parenthesis, and period inside a block. And try doing it again.
You've already accepted an answer to your original question, then redefined your question.
To answer your updated question, you could use the fact that a block returns the value of its last statement, and use a local variable:
nod := [ :a :b | |r|
(a = b) ifTrue: [r := a].
(a > b) ifTrue: [r := nod value: (a-b) value: b].
(a < b) ifTrue: [r := nod value: a value: (b-a)].
r
].
I am curious, though, about the context. I suspect this might more appropriately be defined as a selector/method for a class.
By the way, the above implementation will go into an infinite recursion if either argument is negative.
The simplest way to get the results you're after would be:
nod := [ :a :b | a gcd: b ].
:)

Smalltalk and Assertions

Tryng out some smalltalk + TDD + "good practices" I've run into a kinda ugly block:
How do I do an assertion in GNU Smalltalk?
I'm just looking for a simple ifFalse: [Die] kind of thing
This is the code for assert: from Squeak (which I recommend you use rather than GNU):
assert: aBlock
"Throw an assertion error if aBlock does not evaluates to true."
aBlock value
ifFalse: [AssertionFailure signal: 'Assertion failed']
as well as
self assert: [ ... some block ]
works for blocks & non-blocks, since sending #value to Object returns self.
It has been suggested above to add #assert: to Object, but rather I'd add #assert to BlockClosure (or whatever [] class is in GNU Smalltalk).
assert
this value ifFalse: [AssertionFailure signal: 'Assertion failed']
and thus use as in
[ value notNil ] assert.
[ value > 0 ] assert.
[ list isEmpty not ] assert.
etcetera.
It is simple. In your test methods you write:
self assert: 1 + 1 = 2
But first you need to create a test class as a subclass of TestCase (in Squeak), for example:
TestCase subclass: #MyTest
Here you write testing methods, which names must always start with 'test', for instance :
testBasicArithmetics
self assert: 1 + 1 = 2