This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Smalltalk Evolution: An alternative to #perform:
Feed Title: Richard Demers Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/rademers-rss.xml
Feed Description: Richard Demers on Smalltalk
In The Art of the Minimal, Avi Bryant talks about an experimental language called Sorrow, in which "functions are passed around as simple lists of symbols... represented by Smalltalk arrays." An example he provides is
#((1 2 3) 0 ( ) inject:into:)
.
His language "implements a postfix stack language, so there are no variable references or scopes." Evaluating it results in the value 6.
Lets look at this as a candidate for addition to Smalltalk itself. The expression can be written in standard Smalltalk as
#(1 2 3) inject: 0 into: [:r :i | r i]
and if we want to make the functions dynamic, we can write
#(1 2 3)
perform: #inject:into:
with: 0
with: [: r :i | r perform: # with: i]
#performs can be nested in the block arguments of #performs, but this lacks the simplicity and flexibility of the original array expression. Let's say we wanted to evolve Smalltalk to include Avi's functional arrays.
Send #value to the functional array to evaluate it; for example,
#((1 2 3) 0 ( ) inject:into:) value
.
Assume that the first element of the array is the initial receiver of the implied messages.
Always prepend # to symbols in functional arrays to distinguish them from named variables.
Allow block literals to be specified in functional arrays.
Avi's example is incomplete in that the block argument of the #inject:into: message needs to be specified; for example,
#((1 2 3) 0 (# )
[:r :i | r i] #inject:into:) value
.
But this is not right either, because some way is needed to say where the # function is to appear in the block expression. So something like this would be needed:
#((1 2 3) 0 (# )
[:r :i | r :f i] #inject:into:) value
.
This is a bit more complex than Avi's original example, but it is still worth considering as an addition to Smalltalk.
It replaces the #perform:, #perform:with:, etc, messages with a more elegant syntax in which functional nesting is more easily expressed.
Any message of the form receiver perform: #selector can be recoded as #(receiver #selector) value,
and any message of the form receiver perform: #selector with: argument can be recoded as #(receiver argument #selector) value.
It effectively introduces something Smalltalk has been sorely lacking, the ability to code literal arrays that include variables and expressions as array elements; for example,
#(1 2 varX (#(2 varY # ) #value)) value
.
Note: This assumes that a functional array that contains no functions simply returns itself.
Some arguments for not adding this to the Smalltalk language are:
More syntax, especially one that introduces postfix notation, makes the language harder to learn and to read.
Smalltalk already has the same capabilities via the #perform: messages. Why introduce a second way to do something?
These are the kinds of arguments that can be used against any proposed addition. But the question to ask is "Does it make the language better for some set of programming problems?" The proponents of functional languages can provide better answers than I can. My experience with the APL functional language is very old.