Elements of Goodthink: Setter Sends

Smalltalkers are in a pretty good position to understand Newspeak code out of the box. Unfamiliar constructs such as nested classes and the related message lookup semantics need some experience to internalize, but they are usually only an obstacle to understanding the higher-level design. Within a method everything should look familiar, except perhaps for setter sends.

A setter send is an expression like

foo:: a doSomethingWith: b

For a Smalltalker, the short explanation would be to say it’s just like

foo := a doSomethingWith: b

Like most short explanations, it’s a useful lie. Typically when you see something like the above, there is indeed a variable or a slot named “foo” somewhere in the scope, and the expression sets the value of that slot. But it doesn’t have to always be the case.

One half of the true story is that the expression is more like

foo: (a doSomethingWith: b)

It is a message send to an implicit receiver, and the message is a plain keyword message “foo:” with a single colon. Doubling the colon makes it get parsed at a lower precedence so we don’t have to parenthesize the argument (without parentheses that would be an implicit receiver send of “foo:doSomethingWith:”).

Remember that there is no assignment operator in Newspeak. To set a slot, you invoke its setter method using an expression like the above. Without this syntax, most of those would need parentheses. We set slots quite often, so that would be a lot of parentheses. This is why the syntax is called a setter send, even though strictly speaking it does not have to invoke a setter of a slot. It’s a regular message send going through the regular message lookup procedure.

The second half of the story has to do with the value returned by the send. The value of

foo: bar

is the value returned by “foo:” The value of

foo:: bar

is “bar”. The value returned by “foo:” is thrown away. So after all, while a setter send is a regular message send as far as message lookup goes, its value is different from a regular message send. This is to recognize the fact that a setter send is usually used in place of an a assignment. Assignments can be chained, and this behavior guarantees that a chain of setter sends

foo:: bar:: baz

passes the same value to “foo:” regardless of now “bar:” is implemented.

To condense all of the above into a true short story,

foo:: a doSomethingWith: b

is just like

[:v | foo: v. v] value: (a doSomethingWith: b)

Comments (4) left to “Elements of Goodthink: Setter Sends”

  1. Travis Griggs wrote:

    I think the stacking of colons is cool. Is it arbitrary? IOW can I use it on any message? And can I stack them as deep as I want? Could I hypothetically do something like

    sequence add::: Customer name:: String with: ‘Me’

    ? Or is it just for setter sends?

  2. Vassili Bykov wrote:

    No, the syntax is explicitly <identifier>:: <expression>. No receiver, no stacking of colons, and no multiple keywords.

  3. Maurice Rabb wrote:

    Hi Vassili, many moons ago when, I present this exact idea (including Travis’ extension) when I was working on Microlingua. Great minds think a like. ;-) Makes me want to pull all that stuck back out. I need to check out your blog more often. :-)

  4. Brian T. Rice wrote:

    Slate provides a special class of binary operator which is expanded like a Lisp macro. So := and ::= (immutable binding) and =:= (pattern match) expand into the appropriate message sends, with the special operators themselves having the precedence that “we expect” from assignment. Having this be an extensible class has been helpful, and having them be macros means that they’re just performing normal source operations which usually don’t violate encapsulation.