Smalltalk, A Functional Programming Language
Tuesday 9 February 2016 at 08:00 GMT
I was watching Sandi Metz’s talk, Nothing is Something, recommended to me by Pawel Duda in the comments of my post, Why Couple Data to Behaviour?. In the talk, she said something that I’ve always found fascinating.
In the talk, Sandi compares booleans in Ruby (and other “object-oriented” programming languages) to booleans in Smalltalk. She points out that Smalltalk has six keywords, and if
isn’t one of them. So how do you branch, without an if
keyword?
It’s very simple, truth be told. In Smalltalk, just like Ruby, true
and false
are objects—in Ruby, instances of TrueClass
and FalseClass
respectively. You could, if you prefer static languages, pretend these classes implement a fictional Boolean
interface. However, unlike Ruby, Smalltalk provides two extra messages (methods) that solve our riddle.
Here’s the first. Apologies if I’m off with the syntax; I’m not actually a Smalltalk developer, just a fan.
(magnitude > 9000) ifTrue: [ ^self display: 'Over 9000!!!1111oneoneoneeleven' ]
And now in Ruby syntax, in case you’re not familiar with the above:
(magnitude > 9000).if_true { display 'Over 9000!!!1111oneoneoneeleven' }
And, of course, you have the ifFalse:
message too:
(magnitude >= 0) ifFalse: [ ^self error: 'A negative magnitude is ridiculous.' ].
These are standard library functions, not language-level primitives. One implementation might be to have an abstract superclass, Boolean
, that wraps some native branching behaviour, but that would defeat the point of not having such functionality in the first place. Instead, Smalltalk uses polymorphism as its sole native branching mechanism.
In Smalltalk, true
and false
are singleton instances of the True
and False
classes. Here’s what the implementation of ifTrue:
and ifFalse:
look like in GNU Smalltalk’s True
class:
Boolean subclass: True [
...
ifTrue: trueBlock [
"We are true -- evaluate trueBlock"
<category: 'basic'>
^trueBlock value
]
ifFalse: falseBlock [
"We are true -- answer nil"
<category: 'basic'>
^nil
]
...
]
And, as you might imagine, False
has exactly the opposite behaviour.
And now for something completely different. Let’s take a look at some Lisp, courtesy of Racket:
(if (> magnitude 9000) "Over 9000!!!1111oneoneoneeleven" (format "~a" magnitude))
(format "~a"
is Racket’s toString
/to_s
.)
Notice that if
in Racket (and every other Lisp I’ve seen) is most definitely something separate from booleans in general. In fact, it’s not even a function, it’s a macro—it modifies the code at compilation/interpretation-time to make the then and else expressions lazy, so they’re not evaluated unless we go down that branch. Smalltalk, on the other hand, simply allows you to pass blocks, or functions, as part of the ifTrue:
and ifFalse:
messages.
This behaviour highlights the difference between functional and object-oriented programming style, but I found it interesting that of the two, Smalltalk is the one making use of higher-order functions, which is, some would say, the hallmark of a functional programming language. I don’t necessarily agree (and see the previous link for an explanation), but I still think it’s fascinating that Smalltalk, the original OOP language, recognises that functions as method/message arguments is a perfectly reasonable thing do do.
So, if a Java programmer tells you that lambdas and higher-order functions weren’t encouraged in the language for so long because they’re not object-oriented, point them towards Smalltalk.
If you enjoyed this post, you can subscribe to this blog using Atom.
Maybe you have something to say. You can email me or toot at me. I love feedback. I also love gigantic compliments, so please send those too.
Please feel free to share this on any and all good social networks.
This article is licensed under the Creative Commons Attribution 4.0 International Public License (CC-BY-4.0).