Можно ли назначить сообщение переменной?

Я изучаю различные виды языков программирования, чтобы понять, чем они отличаются, а также их достоинства / недостатки.

В настоящее время меня особенно интересуют языки, которые используют сообщения для вызовов методов; и мне было интересно, можно ли как-то назначить сообщение переменной в 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, и они также называются блоками

Другие вопросы по тегам