简体   繁体   中英

Why is smalltalk not a functional programming language?

With the renewed interest in functional programming languages, I've seen some similitudes between Smalltalk and FPL, namely closures ( BlockClosures in Smalltalk ) Yet, Smalltalk is not a FPL?

What would be needed to consider it as such?

There's no accepted definition of functional programming language.

If you define functional language as the language that supports first class functions, then yes, Smalltalk *is* a functional language.

If you also consider the factors like support for immutability, algebraic data types, pattern matching, partial application etc then no, Smalltalk *is not* a functional language.


I'd encourage you to read the following related blog posts (and also the comments below them):

Smalltalk might not be a "pure functional language" (whatever that might be). However, natural use of Smalltalk often results in functional code. (What I guess the Scala people would call "object-functional".)

For example, Squeak's Point class has a functional API: methods like 1@1 translateBy: 1@1 return new Points with the new state, instead of mutating internal state. (This makes Point practically immutable, since the only way to change the internal state of the object is through reflection mechanisms like #instVarAt:.)

It's quite normal to use higher order functions in Smalltalk like maps, filters, folds, and the like. Given that these are baked into the Collections API, it's often easier to write code that uses Collections in a functional way than not.

So many people have so many definitions of "functional programming language" that the question "is Foo a FPL" is as useless a question to ask as "is Foo an object oriented language".

Having said that, here's my two cents: a functional programming language is a language in which it is natural and idiomatic to employ functional techniques: first-class functions, avoidance of mutable state, side-effect free functions, higher-order functions.

By that description, Smalltalk is a functional programming language. It calls first-order functions "methods" or "blocks" depending on whether or they're named or anonymous. Objects store state in instance variables. Higher order functions are simply methods that take blocks as parameters.

Having said that, yes, you can write Smalltalk in a non-functional manner. It does allow for mutable state. Does that stop Smalltalk from being called a functional language? If so, neither are these languages functional: Common Lisp, Erlang (shared state through the process dictionary, ets/dets).

So, in brief, Smalltalk is an FPL because:

  • Functions are first-class entities (objects, in Smalltalk - CompiledMethods or BlockClosures, to be precise).
  • Smalltalk supports closures (it calls them blocks).
  • Smalltalk allows one to write functionally in a natural, idiomatic manner.

and Smalltalk is not an FPL because:

  • You as programmer must ensure that your data structures (objects) are immutable (by having setters/mutators return copies of the object with the mutated state).
  • You as programmer must ensure that your methods (functions) are side-effect free.

(Some Smalltalks do apparently support immutable objects. My experience is limited to Squeak, which does not support VM-level immutability.)

Edit: I don't understand igouy's need for named function definitions other than through defining methods on an object. But anyway, here we go:

Smalltalk at: #func put: [:x | x + 1].
func value: 1.

Programming with the Object Oriented paradigm is creating a program by identifying and modeling the Problem Domain Entities as objects, and then make them collaborate between themselves to solve each problem instance. Programming with the Functional paradigm is modeling the problem as a mathematical problem, and creating a mathematical function (by composing other functions) that for each problem instance, computes the problem solution.

In my opinion, a functional programming language is a language that given a solution for a problem solved using the functional programming paradigm, the language can express that solution exactly as it was thought. If you need to "transform" some part of your solution so it fits in what the language can express, then it doesn't fully support the paradigm you used to think the solution.

Smalltalk can express in most cases all the solutions created using the Object Oriented Programming paradigm, but it cannot expresss primitively a lot of solutions created using the Functional Programming paradigm. That's why I don't consider it a FPL. Despite not primitively be able to express every solution that a FPL can, Smalltalk is extremelly extensible, and you can extend it to be able to express all the solutions a FPL can.

Smalltalk is a purely Object Oriented Language, where almost all code is basically objects interchanging messages. Functional programming is oriented to function calls, and compositions between functions to create more complex behavior (avoiding state for data, as opposed to internal states that objects have in any Object Oriented language).

纯函数式语言通常具有不可变变量,使它们更像数学意义上的变量。

A language does not become a functional language by having named functions - by that definition, C would be functional ! More important is the functional semantics in the mathematical sense, that the result depends on the arguments alone (in particular: no side effects). By this definition, objects which can be modified by setters are contrary to a functional programming style. However, as already pointed out, even objects can be used in a functional style (Rectangle example) if you forbid side effects. And, btw. there is a duality between objects with methods and a set of functions which are defined in a closure over a private state (see SICP for details). They can simulate each other mutually:

(def (make_foo initVal1 ... initValN)
   (let ((instVar1 initVal1) ... (instVarN initValN))
      (define (method1 args) ...)
      ...
      (define (methodN args) ...)
      (define (lookup selector)
          (cond ((eq? selector 'method1) method1)
             ...
             ((eq? selector 'methodN) methodN)
             (true doesNotUnderstandCode)))
      lookup)) ; returns the lookup function (provides "access into the closure") !

(defMacro (method1 receiver.args)
    ((receiver selector) args))

(define foo (make_foo 1 2 ...))
(method1 foo ...)

the above is a simulation of "pure" functional objects, and semantically the same as a lot of Smalltalk code! However, to implement a setter-method, you have to add a method which does a (set! instVar newValue). And, because set! is non-functional, breaks the "functionality" of the scheme.

Summary: look at the semantics, not the source, luke !

Thank you all for all the answers.

I'll add mine here which basically is my ( probably miss) understanding of yours.

I think the criteria to call something OO or FP is they way "stuff" is built using the language; not how easy or hard is to do it, I mean, the mental paradigm used.

For instance, as the links shown, it may be harder to type something in Scala than in OCaml, but that doesn't make it less FPL ( maybe incomplete or impure, but definitely functional ); because the aim of Scala is to use functions as primary building blocks, rather than objects.

On the other hand, making easy to write a function in a language doesn't make it functional, if the style or the aim is to use another artifacts. Smalltalk for instance, make it very easy to write an anonymous block or to provide a pluggable sorting comparator, but that doesn't make it ANY Functional at all, because the focus is to use objects and pass messages. Blockclosures are just a mechanism to encode these messages ( not functions ) even if they look like just like they were functions.

The confusion comes, because OO and FP are orthogonal ( as Rahul stated via twitter ) , so, what it looks like a encoded message in Smalltalk, looks pretty much like an anonymous function in Scala. But doing something similar doesn't converts a language of one paradigm into another.

To make it worst, Scala also uses the OO paradigm, to make it easier for mainstream ( Java, C++, C# ) programmers to give the jump, and if you see, it have had way more success than any of the others FPL's did. And of course this was thank to Java ( IMHO if Clojure has any success will be for exactly the same reason, the JVM )

In conclusion : A programming language may be classified by the paradigm it uses to build "things". There are languages that are pure like [Smalltalk : OO, Haskell: Functional, C: Procedural], or hybrids, like Scala or multi paradigm , like C++, Ruby, Python.

The fact you can write one style with the other language, doesn't make it that language of that style. Like simulating Objects with Lisp doesn't make it OO nor using functions with Java make it Functional.

To answer the question, to be considered functional, Smalltalk would need to use functions as building blocks, which it doesn't because it uses objects.

I've seen some similitudes between Smalltalk and FPL, namely closures

There's a more basic similarity - every Smalltalk message always returns a value.

But now look at the Design Principles Behind Smalltalk

[Smalltalk] sends the name of the desired operation, along with any arguments, as a message to the number, with the understanding that the receiver knows best how to carry out the desired operation.

Does that describe what you think of as Functional Programming?

@Frank Shearar - That describes Erlang too. Is Erlang now non-functional?

Erlang is something of a chimera - sequential programming is based on functions, but concurrent programming is based on message passing between processes. So Erlang is not multi paradigm or hybrid in the way that other languages allow different styles to be used to achieve the same purpose - it uses different styles for different purposes.

What would be needed to consider it as such?

  • a way to declare functions rather than a way to declare methods in a class

  • a way to structure a program around functions rather than around objects

@Missing Faktor - but isn't func in this example a named function?

|func v|
func := [:x | x + 1].
v := func value: 5.

No func is a local variable. You've bound an anonymous function to the local variable func .

|func v|
func := [:x | x + 1].
func := 2.
v := func value: 5.

To see the difference, look at this Erlang example which shows both an anonymous function and a named function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM