Electric Coffee
Electric Coffee

Reputation: 12144

Is it possible to assign a message to a variable?

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

Upvotes: 3

Views: 542

Answers (2)

Uko
Uko

Reputation: 13396

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

Upvotes: 1

Uko
Uko

Reputation: 13396

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.

Upvotes: 3

Related Questions