Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining keyword messages

Tags:

smalltalk

Let's suppose that I have an object, x, which can accept any one of the selectors, s1, s2, ..., sn. Let's further suppose that the result of any one of these selectors operating on the object is an updated object of the same type. I could then "chain" these selectors (as long as they are unary messages) as I wish, such as:

x s1 s2 ... sn

This will take the result of x s1 and apply selector s2, then apply selector s3 to that result, and so on. I would want to apply one or more of these selectors in some order for various results:

x s8 s2

In Smalltalk I can do this if the selectors are unary messages. However, if my selectors are keyword messages, I can no longer do this. If x individually accepts selectors, s1:, s2:, ..., sn:, then the following doesn't work:

x s1: a1 s2: a2 ... sn: an

There is the ; operator:

x s1: a1 ; s2: a2 ; ... ; sn: an

But using the cascading: each stage modifies the original x along the way, and I do not wish to modify x in this case.

To chain keyword messages, I think I'm left using the following syntax with parentheses:

(...(((x s1: a1) s2: a2) ... sn: an)

Which makes me feel like I'm programming in LISP if I have 3 or more keywrod messages. A specific example of this could be a multidimensional array. If foo is a 3 dimensional array, and you wanted to access an object at location 2,3,5 in the array, I think it would look like:

(((foo at: 2) at: 3) at: 5) some_object_selectors

That's a trivial example, of course, but illustrates the case. One might have other kinds of embedded objects, or other chain of consecutive object operations where you are interested in the end result.

Is there a more syntactically appealing way to do this in Smalltalk? I'm supposing there isn't another operator, perhaps a cousin to the ; operator (say we use & for example), which would chain them, such as:

x s1: a1 & s2: a2 & ... & sn: an

Since I would like to apply the selectors in any, or nearly any, desired order (for possibly different results), the selector form, s1:s2:s3:... is too confining. Also, this gives a facility which already exists in other languages, such as Ruby, where it would be equivalently expressed as:

x.s1(a1).s2(a2)...sn(an)

Lacking a special operator, an alternative could be to pass an array of selector-argument pairs, or perhaps a lookup table of selector-argument pairs. The lookup table requires setup for passing literals (it has to be created and populated), which makes me lean toward an array since I can simply write it as:

x { {s1. a1}. {s2. a2}. ... {sn. an} }

This is still a bit clunky, and I'm not so sure this is any more elegant than just using all the parentheses. I'm afraid my question may be at least partly subjective, but I am interested knowing what the best practice might be, and whether an operator exists that I'm not aware of which may help, or whether one is being entertained by a Smalltalk standards body.

like image 422
lurker Avatar asked Aug 08 '15 19:08

lurker


1 Answers

There seems to be some confusion here.

  1. Cascading is done using ;, where each message is sent to the same argument.
  2. Your x s1 s2... example (which you called "cascading") is called message chaining, where each message is sent to the result of the previous message (due to the beautiful and elegant nature of Smalltalk's syntax, which is simply Object message and always returns a result). And no, you can't always put them in any order. Imagine s1 is multiplyByTwo and s2 is addTwo, with x having an instance variable modified by these methods that starts as 1. Order may matter. (Please note that I'm very reluctant to use such awfully short names as examples - it's not very Smalltalk-like. ;-)
  3. If your n is so large that using parentheses makes it look awkward, then, uhm... sorry, but you're doing it wrong.
    • Consider creating a method on your object to accept multiple arguments.
    • Consider creating a wrapper object to carry your parameters.
    • Consider using a design pattern to decouple your object from the operations you want to perform on it. (Which pattern you need will depend on what you want to achieve; here's a good starting point.)

Rather than looking for an operator to bend Smalltalk to your will (of how you may be used to doing things in other languages), I'd recommend bending to Smalltalk's will instead (explicit naming, not being afraid to create more objects and methods, etc.). You'll get more out of it in the long run, and I dare say you'll get to the point where you wish other language had Smalltalk's simplicity and power.

like image 108
Amos M. Carpenter Avatar answered Sep 29 '22 13:09

Amos M. Carpenter