63 comments

[ 4.6 ms ] story [ 122 ms ] thread
https://parleys.com/play/51c1994ae4b0d38b54f4621b/chapter33/...

After about 53-th minute Odersky gets lost in side effects in a very simple code.

This is why there's nothing elegant about Scala.

The OP points out that immutable code is the standard in Scala. You have picked an example where Odersky gets 'lost' in mutable code. If anything, this video (and your comment) makes the case for immutable and side-effect free code using Actors and FP, as apparently it can be confusing.
"Scala is the only language that I know of that marries the world of FP and OO"

You can do that in C#/F# too. There's nothing special about Scala from this point of view.

C# and F# are different languages..

Last I checked you could not mix the two easily [0]

[0]: http://stackoverflow.com/questions/14280001/why-cant-we-use-...

I think the poster means that c# has many functional features and F#, while being functional language at heart has lots of OO features integrated in it.

PS And the linked question only describes the limitations of Visual Studio where you can have only one language in a given project.

> I think the poster means that c# has many functional features

Yeah just like C++ or Java now have "functional features". That doesn't make them functional languages, they don't promote functional programming to the extent that Scala does.

Aside from that, their type systems are much too unexpressive to allow for the style functional programmers are used to, not to mention they promote mutability.

OCaml was doing that before any of them.
Although I find it interesting how Ocamlers only rarely reach for the OOP bits of the language. I think that this is in part due to the powerful module system that language has.
Indeed. Also, the object system doesn't have the reputation of being very fast. That said, it lets you use structural typing, which is extremely handy once in a while.
Nope. Scala allows for and promotes for functional programming with higher order functions all over the place, its more powerful type system, immutability, practices, standard library, and much more.

Having lambdas makes you about as functional as C++ these days.

Functional/non-functional is a fuzzy distinction but C# is definitely not a functional language.

There be no true Scottsmen here. Scala is also great as an imperative language and an OO language. In fact, I would say Scala has one of the most powerful natively supported object systems out there (mostly because the rest of the statically typed language world can't be bothered to support mixins, grr...).

If it wasn't for nerfed imperative collection classes (to encourage functional solutions) in the standard library, you could totally just ignore the fact that Scala was a functional language at all; it is not in your face about it like Haskell.

It would probably be more correct to say that "Scala is the only language that does both FP and OOP very well." On marrying the paradigms....why not just use both as needed anyways? That is completely doable in C# as well, just not as well as in Scala.

In CLOS.
Why there are so many ignorant idiots in the world?

According to Alan Kay, the essence of OO approach (or paradigm if you wish) is a synthesis of a few fundamental concepts (like a Lisp itself) where not a single one can be removed because harmony (or balance) would be destroyed, and an ugly, mediocre construction would emerge instead (Java).

The concepts are:

* First-class closures - isolated, share-nothing abstractions.

* Nesting of closures, so they could have an internal structure.

* Message passing as the only way of communication among closures.

As long as you follow these three principles, you have "generics" for free, because all the operations are mere messages.

These are three of four principles upon which Smalltalk has been built upon.

Here is an illustration, assuming that we are implementing message passing as simple as a procedures call.

   (define (kons x y)
      (lambda (m)
        (cond ((eq? m 'car) x)
              ((eq? m 'cdr) y)
              (else (error "bottom!")))))

   (define (kar x)
      (x 'car))

   (define (kdr x)
      (x 'cdr))
Notice that using only these abstractions we could implement a unified list structure of Lisps (recall Escher's hands).

This is (surprise!) the "core" of Erlang - extending of closure-based language with immutable data with explicit message-passing, to create first-class agents (servers, etc).

Where is inheritance? Inheritance is just a protocol which specifies what to do with unknown message instead of signaling an error or returning a bottom like in Haskell.

What is MOP could be found in Wikipedia. Smalltalk was its ancestor.

What is CLOS? It is a DSL embedded in a Lisp (based on structures made out of closures) which implements some or other subset of MOP. MIT Scheme, for example, has SOS.

So FP meet OP in CLOS.

> Where is inheritance? Inheritance is just a protocol which specifies what to do with unknown message instead of signaling an error or returning a bottom like in Haskell.

Care to explain? Doesn't make any sense to me...

Assume a class Run that inherits from class Action.

If a message is sent to an instance of run Run that the Run class has no knowledge of, the message will be sent to the parent.

Thus, if message m is unknown to Run, see if the parent classes know it.

A protocol is like a set of rules. It it specifies, for example, that each object (a closure) has special bindings, which holds references to its class (which is also a closure) and to itself, so it could send a massage to its super or to self. Classes could have its own methods (inner closures).

Basically, when you send a message, you have to specify a symbol, that corresponds to a method name, and parameters. The protocol specifies the "routing", like if there is no method that corresponds to this name, then send (forward) the very same message to your superior (exactly like they do in army, which is an implementation of the actor model).

If supers doesn't know what to do with the message, then there is panic - an exception.

The protocol also specifies the rules of shadowing of symbols, such that a method could be redefined (shadowed) within a closure, so it "overrides" a method with the same name from its ancestors.

Object methods (inner closures) could send messages to classes (invoking class methods) and then doing something with a returned value. Usually, there is some syntactic sugar for that.

In short, inheritance is a set of rules, and these rules could be implemented using various mechanism, like explicit message-passing (a-la Erlang) or implicitly, using procedures calls.

Brian Harvey in classic Berkeley CS61A explained these ideas much better than me.

https://www.youtube.com/watch?v=7u3pp7JCAIU

yes, that part makes sense, but in Haskell, an unknown "message" is a compiler error, and bottom represents abnormal termination (e.g exception or even non termination), I don't really understand how that's related to inheritance.
I am not sure that an unknown message could be caught at compile time, because we don't know everything in advance. I also don't think that static type checking is the only way to program.

In that toy example I should return an error, because '() is a legit value.

I'm not sure that OO-ness is a desired property.

Alexander Stepanov, original creator of the STL:

"I find OOP technically unsound. It attempts to decompose the world in terms of interfaces that vary on a single type. To deal with the real problems you need multisorted algebras - families of interfaces that span multiple types. I find OOP philosophically unsound. It claims that everything is an object. Even if it is true it is not very interesting - saying that everything is an object is saying nothing at all. I find OOP methodologically wrong. It starts with classes. It is as if mathematicians would start with axioms. You do not start with axioms - you start with proofs. Only when you have found a bunch of related proofs, can you come up with axioms. You end with axioms. The same thing is true in programming: you have to start with interesting algorithms. Only when you understand them well, can you come up with an interface that will let them work."

More discussion:

http://www.quora.com/Was-object-oriented-programming-a-failu...

OO is more about naming and relating things than the fundamental truthiness of math (and likewise FP). They are just as much about communicating with humans when coming up with a solution as they are about actually getting the computer to act on the solution.

Algorithms don't even come into much play in many typical programming tasks, so the premise of Stepanov's observation is probably flawed (or assumes certain tasks).

I don't agree with that. Naming things and communicating well is something you have to do in every programming paradigm and is not specific to OOP.

IMO, if you want to see what OOP is really about you should focus on its unique features: inheritance, subtype polymorphism, etc.

To me, OOP is, first and foremost, about messages. Everything else is negotiable.
Messages, across boundaries is more FP than OO though... it actually adds complexity to do this in an OO paradigm.
Messages, communication, aren't they same thing, no? I don't agree with Alan Kay on this point; or perhaps I don't understand it correctly (it is just one sentence, he never really elaborates on it anywhere as far as I can find, the best I have found is [1]).

[1] http://c2.com/cgi/wiki?AlanKayOnMessaging

You mean, objects aren't really about objects, since every programming paradigm has them? Well yah, that is kind of the point: it is hard to not think in terms of them, that is what 100k years of evolved linguistic capabilities have given us.

If you want to focus on unique features, then do that instead; Stepanov's argument was focused on thinking, not checkmarks.

"You do not start with axioms - you start with proofs. Only when you have found a bunch of related proofs, can you come up with axioms. You end with axioms."

Um, what? You have no FACTS to do proofs with without axioms; they are the fundamental statements one assumes to be true to define a logical system.

Somebody who insists that they need "multisorted algebras" while misunderstanding a fundamental definition in mathematical logic is exceptionally confused...

I interpreted this to be a top down vs bottom up argument.

In mathematics, we certainly have ZFC as an axiom system now, but mathematics was performed for thousands of years without a "stable" axiomatic base. For example, calculus was developed before the axiomatic delta-epsilon definition for limits was created. The math was developed first, and it was only after the fact that mathematicians went back and set the theory on a stable theoretical footing.

Therefore, I believe Stepanov suggests a bottom up approach: You write an algorithm that performs your work first, and then once you have that, you can refactor the code into classes that encapsulate the various parts of your existing algorithm.

The axioms were found much much later than a lot of the work had already been done. When Euclid wrote down his list of axioms do you think he was laying the ground for work yet to be done? No, the axioms were the synthesis he came up with by observing the work that had been done before by others.
The original article referred to "true OO" which actually does't start with classes, but rather objects. The OP is talking about using functions that are grouped together in objects, so it's a different model than standard OO or class-based OO
Scala is the only language that I know of that marries the world of FP and OO and thus does not need to “throw the baby out with the bathwater”.

Have you had chance to try Swift yet. It could do with Tail Call Optimisation but I do think it can already be used for functional programming.

I think LiveScript does a good job too.

But it's a bit of a niche product, not a LISP and more like Python.

If it doesn't have tail call optimizations then it's about as far away from functional as you can get. They're essential for basic functional abstraction.
While I'm reasonably open-minded about using some parts of OO at higher levels of organization (or at least just genuine modules), I'm not sure Akka is the right place to land there. Functions which are just typed as `a -> ()` have lost (or hidden) all their interesting structure.
Then it's a good thing Akka 3.0 will be typed.
Certainly Haskell, for example, is one of the few languages richly endowed with a non-existent module system, but I personally don't know of a distributed computing environment that does preserve types across machine boundaries in any language. I must be missing something, please enlighten.

If type preservation in distributed computing was a trivial engineering problem it would have already been solved and widely used. As it stands Akka is enjoying fairly widespread enterprise adoption in the distributed computing market, untyped-ness notwithstanding.

Interestingly, as saryant points out, Akka 3.0 apparently will be typed, although I was under the impression that the typed actor project was experimental/a long way off/not a sure thing. Guess things have changed for the better...

I don't think the typed actors in 3.0 are related to the old typed actors feature. It's still in a state of flux but there's a very preliminary preview in Roland Kuhn's github repo.
I'm not claiming it's a solved problem; I'm claiming that the current solutions are lacking.

You can take it as standing on the outside and throwing stones, but it's not malicious. I want something better.

Yeah, I know, same deal with type safe database query DSLs, none have hit the mark yet, including M$'s Linq to Sql, Scala's Slick, Haskell's Esqueleto and Opaleye, etc.

Seems we're on the brink of a completely type safe distributed stack, but argghingly not quite there. Maybe in another couple of years the computing community will have turned the corner.

FWIW, from the outside looking in Haskell seems to be kicking ass in terms of language evolution (7.8 and 7.10 in particular). Here on the Scala side of the fence we've got a ways to go, probably 4 years or so until the dust settles with various compiler forks and research work brings a (hopefully) vastly improved Scala into being.

Yeah! I want to see an EDSL impl of a nicely typed Tutorial D sometime already!

Personally, I don't know that I care about the distributed part of the stack. I want something like Erlang's actor model in Haskell even on one machine. I think if there was a nicely typed way to do that (and see pipes-concurrent and mvc for nice examples) there'd be some fantastic "large scale" application operating space that would get opened up.

Akka does this somewhat below par with Erlang. I'd wonder if a GHC implementation of straightforward single machine Erlang's semantics could do better with typed effects and true asynchronous exceptions. This would be nice even with just effect typing (e.g. untyped channels and lots of living in some IO-alike) and could be a good interpreter target for simpler strongly-typed organizational designs.

I started fiddling with this (under the name hotep) a few months ago and got sidetracked but it keeps coming up!

I would be interested in what you think is missing from Opaleye. Of course there is plenty of Postgres functionality that hasn't been ported across yet, but I'm wondering what you think is missing conceptually.
Ruby is pretty FP/OO friendly.
Am I the only one who finds the goalposts gave moved for FP? it used to be lambdas/lexical closures that were the big must-have FP feature, then it was immutability. Now that we're seeing traditionally-OO languages sport a raft of immutable types and good support for lexical closures, now it's all about higher-kinded-types.

For a while, the big feature was homoiconicity and tail-call-optimization until lisp fell out of favour with language geeks.

Does FP just mean "has features of my favorite self-proclaimed-functional-language"?

FP isn't a technical definition—it's a social phenomenon. As soon as you see it that way you'll never be confused by the use of the term again.
I've just tried not to be dogmatic about it... You can use a functional style without relying on immutable types or tail call optimization.

I think it comes down more to a personal style... we tend to conflate programming to engineering, which it rarely is. More often it is a craft discipline. It's more style, taste and personal preference.

That said, when you have to grow something past a few million users a day, or start to hit C10K/C10M barriers. Even then, there are ways to do that... to break up the load.

Functional Programming is just composing a program with pure functions, nothing else.

Immutability and closures are required for that, because mutability may break homoiconicity (which is required for purity), and lack of closures means you can't pass state around.

Higher-kinded types are very useful for helping with lots of functional abstractions, but they are a type system feature and have nothing to do with FP. If someone claims that, this person doesn't understand FP or type systems.

OCaml and Standard ML are two examples of languages without higher kinded types but are just as good as Haskell for FP.

(Although they have a powerful module system to compensate for that).

> because mutability may break homoiconicity (which is required for purity)

Are you sure you meant that? My (admittedly weak) understanding of homoiconicity is that it's unrelated to either purity or (im)mutability. Isn't homoiconicity related to the program text and its AST? Aren't there languages such as Haskell which encourage pure functions but are not homoiconic?

I'm pretty sure you meant something else...

I bet "referentiality" was meant. It would make sense as a replacement for "homoiconicity".
I bet "referential transparency" was meant. It would make sense as a replacement for "referentiality". oops :(
Yes, that's what I meant, I don't know why I got it wrong.
> they are a type system feature and have nothing to do with FP

I suggested in a sibling reply that the use of type-theoretic notions in FP is a natural out growth of the initial motives of the FP paradigm. While I wouldn't think that FP languages must incorporate type-theoretic notions, it does seem to me fitting that many would, since type systems have been involved with the functional understanding of computation since quite early on. Do think that line of reasoning make sense?

Mutability directly breaks purity whether or not it breaks homoiconicity. This should be obvious because on of the best known and oldest FP language families is both homoiconic and impure due to mutation (the Lisp family.) So homoiconicity is a non-sequitur.
I'm not an expert or professional, but I'll offer some few cents here.

I think your feeling that the "goalposts have moved" is a result of mistaking 'Functional Programing' as the name for a set of language features. Instead, I understand FP to designate a far reaching paradigm encompassing language design, computer science research, and the design and development of particular programs.

As I understand it, the initial motive for FP was the development of an elegant, mathematically grounded programming style in which the human readable forms of expression neatly reflect the underlying computational model. This is evident in John McCarthy's 1962 "A basis for a mathematical theory of computation"[0], where he presents

> a formalism based on conditionals forms and recursive functions whereby the functions computable in terms of certain base functions can be simply expressed.

The same principles seem to persist right through to the current wikipedia article on FP:

> In computer science, functional programming is a programming paradigm, a style of building the structure and elements of computer programs, that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.

Of course, over the course of 50+ years of ongoing research into FP, and roughly 80 years of research into the functional expression of mathematical foundations, there have been lots of developments and plenty of emergent insights that have altered the reigning implementations of FP languages. The fact that OO languages can keep incorporating features that emerge in FP languages is simply a testament to the fertility of the paradigm.

The advent of type-theoretic constructs (like higher-kinded-types) in FP is directly related to the central motives and inspirations of FP. It continues to draw inspiration from developments in maths. Contemporary FP incorporating ideas from type-theory is just like LISP incorporating ideas form the lambda calculus. Since both FP is an ongoing research and design paradigm, the features and approaches associated with it continue to develop. And unless the implementation of FP languages ever overtakes the ongoing research into functional foundations of mathematics, FP will continue to incorporate findings that emerge in the latter.

I may be mistaken, but I don't believe homoiconicity was ever a central feature of the FP paradigm. And, as you note, is is only associated with FP because LISPs were the paradigmatic FP language for so long. But homoiconicity is always a feature of the primordial OO and LP languages, SmallTalk and Prolog.

[0] - http://dspace.mit.edu/bitstream/handle/1721.1/6099/AIM-031.p...

(Too late to edit, but, in the last line, s/always/also).
OCaml also has both, and its object system is probably more powerful.
How come?
Besides the object system, OCaml has a powerful module system, with first-class modules and functors (which is already basically very equivalent to what you'd expect from objects).

Besides that, objects have structural typing, and you can even create objects without classes (somewhat similarish to anonymous classes, except instead of interfaces you have the structural typing to give you something like statically typed duck typing).

OCaml also has multiple inheritance and friend classes.

Alan Kay was inspired by the real world, mostly biology back when psychotropic substances were rather popular. That's were the problems start. The real world systems are: 1) unpredictable - except for those who can forecast the future. 2) Unreliable 3) Slow 4) Uncoordinated - except if you believe someone runs the world. 5) Unmaintainable - just ask someone on human maintenance (drug research etc). 6) Naturally autonomous

Point 6 is very critical, because in von-neumann architectures you will end up having a shared memory and trying to give an autonomous memory to each agent, will end up very suboptimal, and no zipper, COW of any other FP trick can change that.

You just cannot afford to write your software like the real world, and you don't even have intelligent agents of human ability as building blocks...

For point 6, that wasn't Kay but the simula crowd who invented OOP before Kay.

FP is like math: it isn't based on biology or natural human thought, but rather the truth of math. OOP is much more fuzzy, you can say things that you can't nescessarily prove are true via biased naming and relating (just like you could say and think as a person). Math is great and useful, but there is a reason we haven't evolved into straight up Vulcans yet.

(comment deleted)
Well seems that simula OOP was a bit more like java/c++. It was Kay who had the message passing idea, and the smalltalk people still don't consider java/c++/simula-derivatives as true OOP languages because they miss that.

http://c2.com/cgi/wiki?AlanKaysDefinitionOfObjectOriented http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...

I think you have it backwards: OOP in Simula was more bizarre since all objects basically ran as co-routines. It isn't until Smalltalk where we get the non-autonomous objects that we are familiar with today.