I want to create a method that gets a block as an argument, and the block gets a parameter as well.
If the block returns true it should do something ( for example return 1), and if it returns false it should do something else.
this is what I did.. but I am getting syntax error on the ifTrue...
is this the way I should get as a parameter a block that receives an argument?
Mymethod: Block
Block value: 'argument'
ifTrue: [ ^1].
ifFalse: [^2].
and the call to the method :
object := myClass new.
argument :=1
boolValue := object Mymethod : [:argument | argument ==1 ]
the way you wrote it means that #value:ifTrue: message to the Block, and then you are sending #ifFalse: message to nothing (which is not possible at all. If you want to do it in one line, you should use parenthesis:
(Block value: 'argument')
ifTrue: [ ^1]
ifFalse: [^2]
Also in smalltalk it's a convention to name variables with uncapitalized, like block or aBlock
Related
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
I have a scenario where a class holds two instance variables that are mutually exclusive. That is only one can be instantiated at a time. To be precise, I have a Promise class (trying to add promises to Pharo) and it holds promiseError and promiseValue instance variables. I then want to implement the method "then: catch:".
This method should work as follows:
promiseObject := [10/0] promiseValue.
promiseObject then : [ : result | Transcript crShow : result ]
catch : [ : failure | Transcript crShow : failure ] .
I got an idea on how to implement methods that take a block as an argument from method that accepts a block and the block accepts an argument.
My attempt below will obviously not work but I have no idea on how to make it work.
then:aBlock catch: anotherBlock
|segment|
promiseValue ifNil: [ segment := promiseError ] ifNotNil: [ segment := promiseValue ].
promiseValue ifNil: [ segment := promiseValue ] ifNotNil: [ segment := promiseError ].
aBlock value:segment.
anotherBlock value: segment
This should work analogously to a try-catch block.
Have you tried something like this?
then: aBlock catch: anotherBlock
promiseError notNil ifTrue: [^anotherBlock value: promiseError].
^aBlock value: promiseValue
Note that the code does not rely on promiseValue being nil or not because nil could be a valid answer of the promise. However, if there is some promiseError, we know the promise failed, and succeeded otherwise.
Of course, here I'm assuming that this message will get sent once the promise has been successfully or unsuccessfully finished. If this is not the case, then the code should be waiting on the promise semaphore.
I'm studying different kinds of programming languages to see how they differ and their advantages/disadvantages.
I'm currently particularly interested in languages that use messages for method calls; and I was wondering if it's possible to somehow assign a message to a variable in Squeak/Pharo/Smalltalk/etc.
So let's say both class A and B have the message foo:; how can I then do something like this:
|msg|
msg := foo: 12.
a msg.
b msg.
Where a and b are instances of A and B respectively
Pharo has Message class. So you can create it as
Message selector: #foo: argument: 12
But currently Message is not used for execution purposes.
What you are looking for are perform: messages.
So you can do what you need like this:
| selector arg |
selector := #foo:.
arg := 12.
a perform: selector with: arg.
b perform: selector with: arg
"for messages of other `shape`"
a perform: selector.
a perform: selector with: arg with: arg. "up to 3 args"
a perform: selector withArguments: { arg . arg }
As for fancy syntax
msg := foo: 12.
does not make any sense according to Smalltalk. But what you can do is to define a class like GenericMessage with 2 instance variables: selector and arguments. Then you redefine doesNotUnderstand: on the class side like this:
GenericMessage class >> doesNotUnderstand: aMessage
^ self new
selector: aMessage selector;
arguments: aMessage arguments;
yourself
Then you also define a method for Object:
Object>>#performMessage: aGenericMessage
^ self
perform: aGenericMessage selector
withArguments: aGenericMessage arguments
Then your code will look like this:
|msg|
msg := GenericMessage foo: 12.
a performMessage: msg.
b performMessage: msg.
Depending whether you want just to send a message by it's name or store functionality for later use, you have different options. In the latter case you can use blocks which are Smalltalk's version of closures. You define a block as:
block = [ :arg | arg foo: 12 ]
this means that whenever you evaluate an arg with the block foo: 12 will be sent to the arg.
Your code will look like this then:
|block|
block := [ :arg | arg foo: 12 ].
block value: a.
block value: b
P.S. I bet you have the same thing in Objective-C and they are also called blocks
Is there a way to write a block ( which does not get any parameters) which does something only at the first call.
I want to initialize a local block variable only at the first time and then change its value each time the user call that block by : Block value.
My block will be defined in a method A inside a class B.
and the method returns the block.
so each time I call method A it should do the initialization. but every time I call the block it should continue from the same point.
for example: I want i to be initialized to 0.
A
^[i:=i+1]
ob1 = B new.
res= obj1 A.
Transcript show: res value. // should print 1
Transcript show: res value. // should print 2
res2= obj1 A.
Transcript show: res2 value. // should print 1
Here's your modified code snippet.
A
| first |
first := true.
^[first ifTrue: [i := 0. first := false].
i := i+1]
or more simply:
A
| i |
i := 0.
^[i := i+1]
Technically the second example initializes the variable before the block is even executed. If that's ok, then this works. If you really want the variable initialized on first call, use the first example.
You can use the outer context of the block to do that:
MyClass>>myBlock
| init |
init := false.
^ [init
ifTrue: [1]
ifFalse: [
init := true.
2]].
This gives different results for the first and the second time the block is accessed:
| block |
block := MyClass new myBlock
{ block value . block value } "=> #( 2 1 )"
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