[Update]Be sure to also read the comments to this article. There’s a lot of good stuff being discussed there – you’d miss the best part[/Update]
Functional Programming Languages like Scala, F# or Clojure have gained quite some momentum in the IT world over the last few years. The main reasons for this may be the fact that functional programming makes multithreading easier than classical programming models. Unfortunately, this leads some people to think that multithreading is much easier with a functional programming language that in others. But this is not completely true. When it comes to synchronisation between threads, you face the same problems as in other languages. But that’s not what I want to write about today.
You may find it interesting that Smalltalk provides many of the concepts of functional programming languages. While Smalltalk surely cannot be classified as a “purely functional language”, it supports the main constructs for functional programming.
Let’s take a look at the two most important concepts of functional programming languages:
- Higher Order Functions (Closures)
- Immutability of Data
On Wikipedia, we learn that
Which is exactly what Smalltalk Blocks are: Functions in the form of an object. By implementing a Block like [:arg1 | Transcript show: arg1], we implement a function in Smalltalk. This Block can be passed to a method as an argument. So if you implement a method like this:
^aFunction value: ‘Hello world’
You can hand in any one-argument block to this function and have it evaluated with the argument ‘Hello World’. So the result of handing the above-mentioned Block into the evaluateFunction: method will be the result of doing a Transcript show:.
Smalltalk’s mighty class library is in fact built heavily on the use of Blocks (Functions). Even the simplest language constructs like ifTrue:/IfFalse: or the mighty Collection classese are making heavy use of Functional Programming.
If you look at this expression:
#(c b a t q) asSortedCollection: [:a :b| a < b]
what you see is the use of a function to sort a list of characters. The function will be repeatedly applied to two neighboring elements of the list until the function returns true for all elements.
The second concept to look at is Immutability. Immutability means that a purely functional language does not support variables. There are only values and results of functions that use values to create new values, which in turn can be used in other functions, until some value is the desired result. In a functional language, you cannot change the value of a variable, because there are no variables. Most functional languages do not follow this rule, because for many programs the complete lack of variables would make things extremely hard.
Smalltalk (or at least most Smalltalk implementations) also follow the immutability rule to a certain extent: you typically cannot assign a new value to method or Block arguments, but if a Block argument is a Collection, nobody keeps you from adding to or removing from it. So even though Smalltalk supports Closures very well, it completely fails on being a purely functional language in this discipline.
With Higher-Order Functions and Immutability in place, it is relatively easy to make a program multithreading-enabled. If the data within a Closure is absolutely independent of the world around it, most of the synchronisation problems in typical multithreading applications become irrelevant. When a function is called, it works on values that it will under no circumstances change, and therefor nobody needs to protect herself from changes to values from another thread. So it’s easy to kick of a function and have it run in its own thread and come back with a new result value whenever it may have finished with what it does. It is guaranteed that a function will not modify any data that is not its own (or its own copy). This is what functional programmers mean if they speak of side-effects: A function does create ne values, but not modify any.
This immediately brings up the question whether a functional programming language can help make every program thread-safe at no-cost.
Well, you may have guessed it already: the answer is no.
Just by using Scala or F#, your program is not magically thread-safe and can run on all four cores of your machine at light-speed. If your problem is not dividable into completely separable threads that operate on their own set of objects with no need to synchronize with other threads, a functional language can still help a lot, but it will not take the burden of finding ways of synchronizing your data. The problem itself will still be hard.
Coming back to Smalltalk, the fact that a Block can access any data and modify it (with the exception of Block arguments) , disqualifies it for the term “purely functional language”. But still Blocks make Smalltalk a very powerful and expressive language, in which you can achieve a lot with very little code. If you write Blocks that do not modify any objects, you have all the benefits of functional programming. The only problem here is that the language doesn’t really support you in writing Blocks that are free of side-effects. While functional languages keep you from modifying data outside of the function, Smalltalk lets you do that and will not even warn you.
So is it better to use a functional language or Smalltalk?
I don’t really know. I’d say the real hard problem is to make your domain problem dividable into functions that can operate completely independent of each other. If you know exactly how to formulate a Function or Block that will not have any side-effects, you can surely do so in both Smalltalk and Scala.
A disadvantage of Smalltalk may be that it doesn’t support multithreading on the operating system level. While its green thread model is very lightweight and performant, it’s still running in one single OS process, so its scalability is somewhat limited as compared to OS threads when it comes to multicore processors etc.
On the other hand, the problems you run into when you need side-effects or synchronization between threads the use of a functional language will probably not give you much benefit over other languages. I am not saying that a functional language will do any harm in that case.
But if you have a problem that can be formulated in functions, there is nothing keeping you from using a functional programming style in Smalltalk. The most important building Blocks (what a nice word play😉 ) are right there in the class library and have been in use for decades.