Можно ли назначить сообщение переменной?
Я изучаю различные виды языков программирования, чтобы понять, чем они отличаются, а также их достоинства / недостатки.
В настоящее время меня особенно интересуют языки, которые используют сообщения для вызовов методов; и мне было интересно, можно ли как-то назначить сообщение переменной в Squeak/Pharo/Smalltalk/etc.
Так скажем, оба класса A
а также B
есть сообщение foo:
; как я могу тогда сделать что-то вроде этого:
|msg|
msg := foo: 12.
a msg.
b msg.
куда a
а также b
являются примерами A
а также B
соответственно
2 ответа
Фаро имеет Message
учебный класс. Таким образом, вы можете создать его как
Message selector: #foo: argument: 12
Но в настоящее время Message
не используется в целях исполнения.
То, что вы ищете perform:
Сообщения.
Так что вы можете делать то, что вам нужно, вот так:
| 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 }
Что касается причудливого синтаксиса
msg := foo: 12.
не имеет никакого смысла в соответствии с Smalltalk. Но то, что вы можете сделать, это определить класс как GenericMessage
с 2 переменными экземпляра: selector
а также arguments
, Тогда вы переопределяете doesNotUnderstand:
на стороне класса, как это:
GenericMessage class >> doesNotUnderstand: aMessage
^ self new
selector: aMessage selector;
arguments: aMessage arguments;
yourself
Затем вы также определяете метод для Object
:
Object>>#performMessage: aGenericMessage
^ self
perform: aGenericMessage selector
withArguments: aGenericMessage arguments
Тогда ваш код будет выглядеть так:
|msg|
msg := GenericMessage foo: 12.
a performMessage: msg.
b performMessage: msg.
В зависимости от того, хотите ли вы просто отправить сообщение по его имени или сохранить функциональность для дальнейшего использования, у вас есть разные варианты. В последнем случае вы можете использовать блоки, являющиеся версией замыканий Smalltalk. Вы определяете блок как:
block = [ :arg | arg foo: 12 ]
это означает, что всякий раз, когда вы оцениваете аргумент с блоком foo: 12
будут отправлены в Арг.
Ваш код будет выглядеть так:
|block|
block := [ :arg | arg foo: 12 ].
block value: a.
block value: b
PS Бьюсь об заклад, у вас то же самое в Objective-C, и они также называются блоками