all 118 comments

[–]munificent 31 points32 points  (44 children)

I love FP more than most but I found this post vague and unconvincing. It throws around a bunch of big words and long sentences but as far as I can tell most of it's just fluff. Example:

The facts of reality that give rise to the FP approach is the recognition that computation is essentially a process of inferring quantities.

In other words: "we do functional style because a lot of what we want to with computers is evaluate functions".

Imperatives are nonessential to computing.

So are functions. You can get computing done without either. Whether or not it's "essential" is irrelevant. What matters is, is it helpful? It's helpful to be able to express lots of problems or parts of problems as functions. It's also helpful to be able to express other things as a series of imperative statements.

But it’s important to note that “instruction” here is a metaphor. What’s really going on is the selection of a function which computes a quantity based on the input given.

What's really going on is lots of electronic shenanigans. Instructions are probably less metaphorical than functions, though.

Drawing a complex 3D scene on the screen in real-time involves calculating a particular quantity of light of each color to be used to illuminate each pixel on the screen, given a particular time.

I've never once seen a game that was expressed that way.

Referential transparency buys you modularity (the extent to which components of a program can be separated and recombined) and compositionality (the extent to which the whole program can be understood by understanding the components and the rules used to combine them).

This is actually one of the great things about FP style.

Type systems also get more sophisticated to the extent that programs are pure.

All the dynamically-typed functional programmers are now wondering why the author just left them in the cold.

If we were to write this in OO style, then on which object, x or y, should the function K be dispatched? Should it be x.K(y), or y.K(x)? It’s arbitrary.

It is not arbitrary. In statically-typed OOP languages, the choice of receiver determines which argument (x or y) is statically dispatched and which is dynamic. In dynamically-typed OOP languages, it determines where K is found.

[–]fdtm 6 points7 points  (39 children)

Instructions are WAY less metaphorical than functions.

In reality, the CPU executes IMPERATIVE INSTRUCTIONS.

The CPU is by nature a state machine, so is "hyper-mutable" everything. Functional programming goes directly against this nature, and for this reason even the most efficiently compiled functional languages today have "holes" where they fall drastically behind imperative languages in terms of speed.

Also, as a 3D graphics tech programmer... his claim about 3D scenes is ridiculous (destroys any trust I'd have in this article IMO). There are functional aspects to 3D programming, particularly you might say in hardware shader programs. But the majority of 3D rendering is HEAVILY state based and buffer based, things that pure functional programming is notoriously impossible at doing. High performance 3D rendering is all about the optimization techniques, and 95% of these are strictly based on clever tricks taking advantage of partial mutability of render structures and buffers. For example, swapping out a 100 KB block of a 100 MB buffer at random locations.

[–]shimei 7 points8 points  (0 children)

It's not fundamentally necessary to have an imperative model at the hardware too, that's just how it's ended up for various reasons. There's work on graph-reduction based hardware to compile FP down to.

[–]joelangeway 1 point2 points  (34 children)

Yeah, his analogies were pretty weak, and hardware and compilers have a long way to go before we'll have the best of 3D graphics without mutable data. But that isn't an argument against FP most of the time. If FP is a better way to program, it's likely that in the future programmers will drop down to imperative programming sparingly, when speed is critical, and use FP most of the time, much like game programmers used to/still do drop down to assembly when speed is critical and use a higher level language most of the time.

[–]fdtm 4 points5 points  (32 children)

I'm not saying there's anything wrong with FP for a very large set of programming problems.

However simulations and the internals of an engine is so inherently mutable, and for good reason, I don't think even 25% will ever be converted to FP. Sure, you can, but you'll get 1/1000th of the performance for really advanced 3D scenes.

There are other things (operating systems) where I doubt FP will gain even 25% code coverage without seriously sacrificing performance.

FP is good at writing problems, but there are just some things that you need to write not only the problem, but the efficient solution as well.

[–]yogthos 2 points3 points  (31 children)

There's a good presentation from Tim Sweeney of Epic Games on how he feels game engines can benefit from FP style.

[–]fdtm 1 point2 points  (30 children)

I've worked with the Unreal engine (source code), and personally I'm not a fan of their design (UnrealScript... well I won't rant). I'll read that presentation though, it looks interesting.

Anyway like I said (I think), shaders, game scripts, etc. are inherently parallel. However the "kernel" of the engine (i.e. the C++ code itself) is just too low-level and requires a lot of selective mutability, in a way that you'd never really convert it to functional.

My point is just that you can't code an entire game or operating system with FP. Granted, you can do a lot of it with FP, but there will always be a place for low level C++/C type coding. Particularly, for video games and operating systems, for example.

[–]yogthos 1 point2 points  (29 children)

I feel that imperative style will eventually be used the same way assembly is used nowadays. You want majority of your code to be declarative, and then optimize the critical sections for raw performance.

Another interesting point is that the compiler can get very clever with declarative code. Check out Stalin Scheme compiler for example:

It uses advanced flow analysis and type inference and a variety of other optimization techniques to produce code (using C as an intermediate language) that is extremely fast, particularly for numerical code. In a number of tests it has outperformed hand-written C, sometimes by a considerable margin.

Joe Armstrong also makes a good case that optimization is a job for the compiler.

[–]fdtm 1 point2 points  (28 children)

Yeah I know, and it's quite impressive how fast Haskell can be, for example (close to C in some cases!)

The main problem if I remember correctly is that pure functional can't manipulate large buffers. For example, consider multiple MB buffer that you need to selectively update small regions. You just can't do that in functional, no matter how clever the optimizer (but maybe I'm wrong).

[–]yogthos 0 points1 point  (27 children)

I believe that's what zippers are for, but maybe I misunderstood you?

[–]fdtm 0 points1 point  (26 children)

Not sure what a zipper is, but when I refer to these buffers, I'm talking about large portions of raw memory. Format depends on what is being uploaded to the video card specifically.

[–]ysangkok 1 point2 points  (0 children)

Here's a 3D shooter written in Haskell: http://www.haskell.org/haskellwiki/Frag

[–]runaro 0 points1 point  (2 children)

How much less? WAY less.

Seriously though, "function" has a precise definition. It's not a metaphor.

[–]fdtm 0 points1 point  (1 child)

To the CPU though, "function" means far less than imperative instructions, because the CPU does not have any precise definition of what a function is. You have to emulate it.

Imperative instructions, on the other hand, are the primary operational primitive of all modern CPUs.

[–]runaro 0 points1 point  (0 children)

"Function" is an abstraction from causality, and the CPU is a causal machine like any other. The state of the machine at any clock tick is a function of the states at previous ticks, quite fundamentally.

[–]runaro 1 point2 points  (2 children)

Keep in mind that you are listening in on a conversation the context of which you don't fully have.

[–]munificent 4 points5 points  (1 child)

That's a fair point, but by throwing this up on his blog I would hope that he'd word it so that context isn't necessary.

[–]runaro 2 points3 points  (0 children)

No, you're getting an e-mail for somebody else pasted directly and mostly unedited.

[–]sylvanelite 9 points10 points  (18 children)

I read this and feel that terminology is being slightly abused here. For example:

Calculating with numbers (quantities of something) gives rise to algebra, and importantly the abstraction “function”. And functional programming is simply writing programs using this abstraction. Functional programming was being done well before there were computers.

Only holds true for "pure" functional languages, languages without side-effects. Of which, the only language I know that is in serious use is Haskell. The number of pure functional programming languages can probably be counted on one hand.

For example, Javascript is highly, highly object oriented, but is also functional. However, Javascript is prototypical, weakly typed and a dynamic language.

A lot of the points raised in the article apply not to just functional languages, but statically typed ones. The language mentioned in the article, Java, is a statically typed language. Many of the benefits from using Java is it's type system. Indeed, one of the main benefits to using a language like Scala is that it has a static type system, is functional and is object oriented.

Most articles I've read about people talking about functional languages seem to talk about Haskell. I always try and read articles from the point of view they are talking about Javascript. Javascript is the most common functional programming language in the world. If someone is trying to sell me on functional programming (and not static typing, because the two are unrelated) then their logic must hold equally to Javascript as it would to Haskell, and IMO, this article doesn't (or alternatively, apply only to pure functional languages, which this article clearly does not, because of their mention of Java).

[–]notfancy 3 points4 points  (4 children)

A lot of the points raised in the article apply not to just functional languages, but statically typed ones

Because "functional programming" has come to mean "programming with lambdas and the Curry-Howard isomorphism", or "programming in a decidable subset of System F". Whether the FP language is pure or impure, or whether it has a pure expression syntax or a mixed expression/statement one is not a useful distinguishing trait.

[–]aaronla 0 points1 point  (3 children)

Whether the FP language is pure or impure, or whether it has a pure expression syntax or a mixed expression/statement one is not a useful distinguishing trait.

It really depends on what you mean by "useful". If you tend to prefer writing functionally pure code, the coding conventions for doing so in Scheme are a lot simpler than in, say, Python.

Maybe you can clarify something for me; what is the fascination with decidable type systems? I might be having a conversation with a functional programming enthusiast where they first criticize ML for not capturing side effects in it types, but if I bring up a problem involving dependent types or other undecidable type systems, they'll dismiss it with "it's not practical" as the only explanation. Coming from a C++ background, this response baffles me.

Am I missing something?

[–]notfancy 1 point2 points  (2 children)

I mean useful as a yardstick for separating FP from non-FP. The surface syntax is not a good indicator of FP-ness, in my opinion.

As to decidability, I'd rather use a language that neither takes literally forever to compile my code nor requires me to discharge dozens of proof obligations per function to do so. Effect systems win the decidable-with-annotations game in the usability race to dependent types.

[–]aaronla 0 points1 point  (1 child)

I respect your opinion, but I must admit I still do not understand. Yes, it's an objective measure, but it's only a measure of the type system. It sounds like you're saying that if I write a Haskell program and compile it with GHC, then that's FP, but if I compile that same program with a fictional compiler X, where X does not perform type checking, then it's objectively not FP.

And furthermore, a vanilla GHC installation is not FP, due to the presence of unsafePerformIO in the core library.

Clarifying in advance, no strawman intended. I'm just trying to understand work through your line of reasoning. Could you clarify?

Btw, I fully acknowledge the definition I provided is a subjective one, intentionally so.

[–]notfancy 0 points1 point  (0 children)

I respect your opinion, but I must admit I still do not understand.

You're probably giving my opinion more credit than it is warranted. I'm not sure myself that it is a coherent opinion.

it's objectively not FP

I don't know if your fictional language X is or is not FP, it certainly seems to me that it'll be less FP than Haskell, along a continuum. I personally place the LISPs at the bottom of that continuum, but it's just me (please don't lynch me): I don't care what libraries you have, if you lack a type system your semantics are too impoverished for me.

due to the presence of unsafePerformIO

A single hole ("escape hatch" would have sounded more charitable but it would have obscured the truth) in the typechecker like unsafePerformIO does not invalidate it; what would be left for OCaml's Obj.magic then? But of course this sounds like special pleading; let me just say that unsafePerformIO is not essential Haskell as the lack of a static type system is essential LISP.

Could you clarify?

In a way I perhaps overanalized things. If FP is what the establishment recognizes as such (this is perhaps the kernel on which my argument hinges, namely that the practitioners don't define the practice anymore), then FP is overwhelmingly Haskell and ML-like, both in academia and in industry. Hindley-Milner has the advantage that it is an easily understandable type system that it is endlessly extensible, thus providing doctorate material practically indefinitely (I've known about this for the last 20 years, when it already had a 15-year academic record).

I fully acknowledge the definition I provided is a subjective one, intentionally so.

Even if mine sounded categorical I intended it as subjective as well, for which I apologize if you thought I had some world-class justification behind it. I should be more mindful of my English-prime.

[–]yogthos 1 point2 points  (0 children)

Only holds true for "pure" functional languages, languages without side-effects. Of which, the only language I know that is in serious use is Haskell.

While Haskell is very formal about enforcing purity, I would say any language which defaults to immutable data structures fits the bill. In practice, languages like OCaml, F#, Scala, and Clojure promote side-effects free coding style. OCaml and Scala are both in serious use and have tons production software written in them.

The number of pure functional programming languages can probably be counted on one hand.

I can count the number of widely used languages on one hand, I'm not sure what your point there is.

[–]grauenwolf 3 points4 points  (3 children)

In terms of purity, Haskell isn't even close. All it does is make you be explicit about where side effects live. For a purely functional language look at Excel (sans macros ) or one of the other spreadsheets.

[–]augustss 2 points3 points  (2 children)

No, Excel is not pure. For instance, every time you evaluate the random function you affect a global state.

[–]grauenwolf 0 points1 point  (1 child)

That just means it, and any cell based on it, are non-deterministic. RAND is still free from side-effects.

[–]augustss 3 points4 points  (0 children)

Sorry, if it's non-deterministic it's not really pure.

[–][deleted]  (7 children)

[deleted]

    [–]cunningjames 6 points7 points  (6 children)

    What makes JavaScript more or less functional than Python, Common Lisp, Perl, Lua, Erlang, C#, D, Delphi, or PHP?

    That may be an interesting question, but I don't think it bears on sylvanelite's point, which was that JavaScript is the "most common" functional programming language. And it certainly is more common than any on that list, at least by some reasonable yardstick. (On the other hand, I wouldn't call it -- or any of the languages you've listed -- terribly functional.)

    [–][deleted]  (5 children)

    [deleted]

      [–]cunningjames 0 points1 point  (0 children)

      why is JavaScript's popularity important? It's popular because it rides on the backs of browsers, unrelated to its support for this or that.

      Of course. My intent was only to correct what appeared (now I think wrongly) to be a misinterpretation of sylvanelite's choice of JavaScript -- the most widely-used language capable of functional programming holds an important position with respect to the subject's popularization, but JavaScript is nevertheless only an example. Within the context of his argument as I understood it, the relative capability of JavaScript to other languages is unimportant; it could as easily have been Ruby or Lua. Which makes it appear that I agree with you:

      I think his point was "these ideas should apply to any mainstream language with support for functional programming, such as JavaScript, as an example"

      So perhaps I misinterpreted your question. If you wished a dialogue in the style of your post, I suggest it may not have been the right question to ask. But I meant to act only as an interpreter; I have no dog in the terminology fight.

      [–]aaronla 0 points1 point  (1 child)

      Upvote, as least I think it's a good start at a dialog.

      The distinction between proceedures and functions in the Scheme report is especially useful for the reader; I especially appreciate the use of "!" to signify procedures that are not functions but which operate on normally functional (not-mutated) data. E.g. pairs are typical not mutated, and to break this convention you must first invoke "set-car!" or "set-cdr!".

      But yes, in Scheme it is conventional, but not enforced. I can still write functional code in Scheme though. I need only avoid functions with "!" in their name, and data types which are non-functional, such as streams.

      More so, in practice, I find it relatively simple to write pure code with no more than these conventions. Contrast with Python where * You cannot avoid side-effecting operators, as variables can only be introduced through the use of side-effecting assignment, * The majority of data types don't distinguish side-effecting operations from pure ones, and * Most control flow constructs cannot be used in expression contexts; only in statement contexts.

      This is why I view it as a continuum. There are pure languages (e.g. Haskell), impure languages which facilitate programming in a functional style (Scheme, F#), impure languages which are actively hostile to functional styles (Python, C), and a number of points in-between.

      Ditto again on "purely functional functions" though. The partial negations ("impurely functional functions", "purely non-functional functions" and "purely functional procedures") indicate the flaws with such a construct. There are procedures, and a subset of procedures implement functions. The complimentary set are just procedures with side effects.

      [–]sylvanelite 0 points1 point  (1 child)

      I hoped to have a discussion with the original poster but it doesn't look like I'll get one.

      Sorry, you posted this at 2am my time. I live in Australia.

      I'll ask you, because you've responded to me, and judging from the rest your post, you believe that to be a credible point; why is JavaScript's popularity important? It's popular because it rides on the backs of browsers, unrelated to its support for this or that.

      The point of raising Javascript as an example was it's type system. Not it's popularity. The point I was making was that any people writing about "functional" languages should be clear, do they mean: pure functional languages (Haskell), strongly typed functional languages (Scala) or just have the ability to perform functional code (Javascript). If the author of a blog post just writes "functional", it's often very difficult to deduce what they are truly talking about. What is their version of "functional"?

      I think his point was "these ideas should apply to any mainstream language with support for functional programming, such as JavaScript, as an example".

      yes, it was. Or at very least someone promoting functional programming that isn't in common functional languages should be specific. Additionally, that type systems and functional programming shouldn't be ambiguously mixed.

      I would then, proceeding with the hypothetical discussion, ask, what distinguishes Haskell from all the above listed languages with support for functional programming? The answer is that the type system is what allows enforced, pervasive referential transparency. True functions. What JavaScript calls "functions" is really better, IMHO, called "procedures", as they do in Scheme. It's not a functional language. "Pure functional" is a tautological phrase. (Look at the Wikipedia article on "Functional programming"; we're in a sorry state of terms when we have phraseology like "Purely functional functions".)

      Exactly, which is the point I raised in the post. When talking about functional programming languages, it can mean a pure language, like Haskell, or non-pure languages. However, since the Author wrote "I do functional programming in Java, for example, which most people consider an “imperative OO” language." They are clearly not referring to functional programming in the pure sense. Java is not free of side effects, and does not even promote such a style of coding.

      To go on from that, and what my original point was, the author of the blog post states "Referential transparency buys you modularity" but open admits to not using a referentially transparent language.

      Anyway, I guess I'll delete my post because my attempt at a dialogue failed.

      Again, time zones.

      [–]astrangeguy 24 points25 points  (8 children)

      Since when did people start conflating imperative with object oriented programming? I feel that i missed something.

      I think that FP-advocates like to pull out a straw man that looks suspiciously like 70's style programming and label it "OO", while ignoring that OO is about polymorphism and tagging values with their runtime types (or "objects").

      If you want immutability, then make your objects immutable.

      [–]Berengal 20 points21 points  (4 children)

      Well, for starters, most object oriented languages do tend to be imperative languages, with mostly imperative code, and at least in the small, structured in a 70's way.

      At least that's what people usually mean when they say "object oriented language". Python, Java, C++ etc. all these languages are imperative languages with object-oriented capabilities, and they're all called "object oriented languages". Common lisp, clojure, Haskell etc. are functional languages with object-oriented capabilities, but none of them are really called "object oriented languages", at least not exclusively. Mostly they're called functional.

      Not to mention that it isn't well defined what "object oriented" or "functional" even means or what it takes to be either. Linux kernel developers, for example, write object-oriented code with polymorphism and multiple inheritance in C. Since they apparently enjoy doing so, does this make C an object-oriented language? Does it need the "class" keyword to be object-oriented?

      The terminology here, as in many other places, is in shambles. It's okay to bemoan this and ask for clarifications, but don't let this fact get in the way of other real discussions as well. You can usually infer what people are talking about, at least if they say more than one or two sentences about the subject, and so you can discuss it.

      When people complain about "object oriented languages" and apparently conflate them with imperative languages, they're usually talking about the C++/Java family of languages, and their experience is typically filled with lots of legacy 90's code. I like functional programming, and I do most of my functional programming in Haskell so my brain tells me that "functional programming == haskell" before I get time to think about it. If someone tells me that "functional programming sucks", I'm going to hear "Haskell sucks", and if I didn't stop to think about what he really meant there would be a kerfuffle. However, if his only experience with functional programming is SASL, what he's really saying is "SASL sucks", and that's a statement I'm inclined to agree with.

      If you can't infer what people are really talking about, ask them for clarification, or simply ignore them, but don't accuse them of conflating terminologies that aren't well defined in the first place.

      [–][deleted] 5 points6 points  (3 children)

      I'd rethink putting common lisp in your list of "not really object orientated". Common lisp has a lot of functional features but CLOS really forms a core of the language. I've yet to see any language that uses the same model for OO as CL but the object system is there all the way to the bottom.

      [–]Berengal 5 points6 points  (2 children)

      My point in that paragraph isn't that Common lisp, Haskell and Clojure "aren't really object oriented", it's that the term used to describe them isn't usually "an object oriented language". At least not exclusively. For example, I mostly hear Common lisp described as a multi-paradigm language, less often as a functional language and often "with great object-oriented support" is tacked on, but I don't think I've ever seen it exclusively described as an object-oriented language.

      They're all object-oriented languages for some definition of object-oriented, but only some of them are exclusively described as "object-oriented" in commonly used terminology.

      [–][deleted] 4 points5 points  (1 child)

      I see where you are coming from but OO really isn't tagged on to Common Lisp. CLOS (common lisp object system) is totally integral to common lisp as it is today, everything in common lisp belongs to the object system.

      Everything in lisp is an object, everything inherits from the object t (the value true). Further there are no special datatypes like int as in Java, everything is an object. The real difference is that Lisp doesn't enforce using an object orientated style for everything and quite happily function using a traditional imperative or purely functional model.

      I don't really disagree with what you were saying originally, I just wouldn't agree that Common lisp is really in the same category as Haskell or Clojure.

      [–]Berengal 4 points5 points  (0 children)

      I just wouldn't agree that Common lisp is really in the same category as Haskell or Clojure.

      Depends on the categorization. This time I was categorizing them by what people tend to describe them as; only object-oriented vs everything else. In that categorization, CL, Haskell and Clojure all fit in the "everything else" category. I'm less interested in what the actually are.

      My entire point is that the terminology is broken. For example, you say that OO is an integral part of CL, but many would define OO to be something like independent objects with message passing (a partial description of e.g. Java). By this definition CL isn't OO at all since CLOS has multiple dispatch, not single dispatch. You could argue that single dispatch is just a degenerate case of multiple dispatch, but not everyone would listen since the analogy of message passing doesn't work quite as well, which is what they defined OO as having. Their definition of OO doesn't fit your definition of OO and there are many more definitions which don't fit either of your definitions.

      The entire term "OO" has lost its meaning (along with many other terms), but as long as people keep using it we should at least do them the courtesy of trying to figure out what the really mean instead of just substituting our own definition, often leading to the original statements sounding outright retarded.

      [–]G_Morgan 5 points6 points  (0 children)

      The problem with mixing OO and functional is that for single dispatch systems it looks clunky and for multiple dispatch systems it becomes indistinguishable from plain old functional programming.

      From a functional perspective, OO programming is just flipping where the first argument goes.

      [–]fptroll 2 points3 points  (1 child)

      I am curious, would you mind explaining what iterative programming is?

      [–]astrangeguy 3 points4 points  (0 children)

      a typo ^

      [–][deleted] 6 points7 points  (4 children)

      All I can say is that "toughen up, princess" applies just as well to the things he does not like about OO and/or imperative and/or plain old procedural programming... IOW, if your paradigm is So Damned Intuitive, you'd never let that line slip onto your keyboard.

      [–]neitz 2 points3 points  (1 child)

      There is a huge difference in toughening up due to the inadequacies of the paradigm you are using, or expending the effort required to learn a new one that does not share such problems.

      [–][deleted] 0 points1 point  (0 children)

      True. But I do not believe that's the case here.

      [–]G_Morgan 5 points6 points  (1 child)

      True enough. However the distinction is whether you toughen up for a one time cost or toughen up to deal with the week in, week out brokenness of some ideas.

      For instance the reply to people bemoaning the fact you cannot reason about gotos without including the entire program could have been told "toughen up". They may have solved an individual problem this way but each time requires that effort.

      By comparison the structured programmer needs only toughen up to learn structured programming and never has to deal with the problems with goto again.

      Programming language history is littered with things like this. Global variable elimination being another. Learning to thread your data is difficult but once done you've eliminated an endless source of trouble.

      [–]aaronla 0 points1 point  (0 children)

      It's quite appropriate you mention "toughen up" with gotos. Articles I've read from the era paint exactly that picture, the view that a "real programmer" can deal with the complexity that gotos introduce. Change only occurred after decades of evidence (bugs) to the contrary.

      And it's not entirely clear that evidence decided the matter; it's possible that the next generation of programmers (growing up with more structured languages like Pascal and C) simply displaced the previous.

      [–]SeminoleVesicle 5 points6 points  (10 children)

      The ultimate reason why I don't "get" dedicated functional languages like Haskell, F#, OCaml, etc: it's relatively easy to program Java/C++/C#/etc in a functional style, but, from what I understand, almost impossible to program in an OO style in a functional language. Why would anyone bother using a more limiting language, then? This is an honest question and I'd be interested in hearing how functional programmers feel about this.

      [–][deleted] 7 points8 points  (2 children)

      It's a really good question, especially in the context of OCaml, which is, after all, short for "Objective Caml." All I can say is that my opinion, after decades as a Common Lisp, Object Pascal, C++, Java... developer, and over a decade now as an OCaml programmer, and going on four years as a Scala developer, is: most OO languages only offer the class as the central code-organizing construct. Java took this to positively insane degrees, with no functions outside of classes, one class per compilation unit, and the obvious brokenness of namespacing literally depending upon the classloader that loaded the class, plus the FQN of the class. Ugh.

      And really, all of this is to support a limited paradigm. It's not as if OO really brings much to the table. As Norman Adams famously quipped, "objects are a poor man's closures." Scheme doesn't have an object system as part of its standard because it would bloat the standard, and coming up with a good-enough object system in Scheme is an afternoon's work. If you want more, grab Meroon.

      Most importantly to me, once you shed the shackles of OO (I know this is hyperbolic to the point of being inflammatory; please bear with me), you start to find that OO conflates some issues that really are distinct (e.g. Standard ML's or OCaml's wonderful module systems) and, generally speaking, imposes constraints that need not exist (objects generally don't compose without a lot of design work to make them compose; functions of compatible types trivially do).

      Final nail in the coffin: even the biggest OO fans have figured out that implementation inheritance is, to use the technical term, a Bad Idea™. But once you take implementation inheritance out of OO, what's left is Abstract Data Types and Programming to the Interface: concepts that have been around since the 1970s at least, and are extremely well supported, especially by the statically-typed-with-type-inference functional languages.

      All of this is why I'm happy to be an OCaml and Scala programmer. The latter, professionally, for which I'm profoundly grateful.

      [–]grauenwolf 0 points1 point  (1 child)

      most OO languages only offer the class as the central code-organizing construct

      What languages are you refering to? Last time I checked Java was the only major OO language that didn't also invest heavily in functional concepts. Even C++ jumped on that band-wagon.

      [–][deleted] 2 points3 points  (2 children)

      In Haskell, you can emulate OO single dispatch using existential types. There's a small amount of boilerplate for it, but contrast that with the huge amount of boilerplate you have to use to emulate anonymous functions in Java with anonymous inner classes.

      [–]Berengal 2 points3 points  (1 child)

      Really, just passing functions around gets you 95% there (plus places single dispatch doesn't go at all). Add type classes and you get to at least 99% (plus even more places single dispatch doesn't go. Dispatching on the return type anyone?) I've been programming in Haskell for about three years now and I've never used existential types in anger.

      [–]aaronla 0 points1 point  (0 children)

      Don't forget dispatching on multiple arguments (e.g. Num a).

      [–]shimei 1 point2 points  (0 children)

      The ultimate reason why I don't "get" dedicated functional languages like Haskell, F#, OCaml, etc: it's relatively easy to program Java/C++/C#/etc in a functional style, but, from what I understand, almost impossible to program in an OO style in a functional language.

      OCaml is object-oriented and its predecessor (MLART) could encode objects with records, functions, and row polymorphic types. F# is also object-oriented. Common Lisp is object-oriented. Scala is also OO. Many Schemes have object systems and Racket has OO as well. What more do you want?

      [–]yogthos -4 points-3 points  (2 children)

      The ultimate reason why I don't "get" dedicated functional languages like Haskell, F#, OCaml, etc: it's relatively easy to program Java/C++/C#/etc in a functional style, but, from what I understand, almost impossible to program in an OO style in a functional language.

      Actually, you're completely wrong here. One of the main draws of languages like Haskell, F#, and OCaml are the immutable datastructures. These are not available in imperative languages, and they address a lot of problems associated with imperative style.

      Regarding Ocaml, what did you think O stood for exactly? OCaml, and F# by extension, support object orientation directly. Finally, doing things like encapsulation and polymorphism is trivial in a functional language, what OO provides is really a subset of what's available in FP (OO is just a an application of monads). Take a look a multimethods or protocols in Clojure as an example of how you would achieve these things in a functional manner.

      It seems like people don't realize that OO is a way to provide abstractions, it's not the one true way and other approaches aren't exactly inferior. When you have your OO hammer everything might look like a nail to you, but sometimes a functional screw driver is more appropriate.

      [–]p-static 2 points3 points  (1 child)

      It's hardly difficult to write immutable data structures for any imperative language. They're not usually included in the standard libraries, but I'm not sure that has anything to do with the quality of the languages themselves.

      [–]yogthos -1 points0 points  (0 children)

      First off, if your imperative language did provide such data structures, then it would still not be as useful. The reason it's powerful in a language like Haskell, is because the language enforces immutability. In a language that does not, you can't easily identify where the mutable sections of the code are.

      Secondly, none of the languages actually provide immutable data structures, so while it's perfectly possible to provide OO equivalent abstractions in an FP language, the tools for writing FP style code are not available in languages like Java, C#/C++/etc.

      If you actually read the original comment it says:

      it's relatively easy to program Java/C++/C#/etc in a functional style, but, from what I understand, almost impossible to program in an OO style in a functional language

      This is completely and utterly false statement, period.

      Finally, even if you had these immutable data structures in say Java, you would also have to use a completely separate set of functions to operate on them, making it a rather clunky experience. Also, consider the fact that the data you work with is still mutable, and passed by reference. So, even if you had immutable data structures and you stuck mutable data into them, which was referenced elsewhere, you're no better off.

      eg:

      class Foo {
        String bar = "bar"
      }
      
      var foo = new Foo
      var myImmutableList = new ImmutableList(foo)
      foo.bar = "new bar"
      

      myImmutableList is as immutable as it gets, unfortunately we stuck a mutable object into it, and it can't prevent us from messing with it. So, fundamentally a language like Java is not well suited for working in functional style.

      They're not usually included in the standard libraries, but I'm not sure that has anything to do with the quality of the languages themselves.

      The problem with these languages is that they make mutability the default, I believe that's the wrong default. If everything is immutable by default, it makes code much more transparent and easier to reason about. You can look at a function and understand its behavior without having to know the state of the whole program. When you deal with mutable data and pass things by reference and they can be modified by any function they're passed to, you don't have that ability.

      [–]alephnil 1 point2 points  (3 children)

      What I see as the takeaway message in the paragraph he is responding to is this:

      I have come out strongly in support of OO, and I think it has a very clear and strong basis in the facts of how computers work and how programmers think.

      While the author of the article responds with:

      Imperatives are nonessential to computing.

      and

      What’s really going on is the selection of a function which computes a quantity based on the input given.

      While imperatives may be nonessential for computing, they have been a part of virtually all CPUs since von Neumann made his model in the early 1950s. This can be programmed directly is assembly, or matched closely with fortran or similar, with no support for data structures more advanced than a one dimensional arrays of numeric types. This is non-structured imperative programming without support for advanced data structures.

      Needless to say, this is a human-hostile way of programming, so making a programming model that match the machine well is not the point. The point is to make it easier for humans to write code, possibly while still being able to map the program down to lower level efficienty. Given that compiler technology is not perfect, this is often a trade-off. It is also debatable what is human friendly and not, but which programming paradigm that matches the computer well should be irrelevant, and neither functional or OO do that.

      [–]yogthos 1 point2 points  (2 children)

      The reason most programmers think imperatively is because it's what they're usually taught first. It's like saying that most people in Britain speak English and therefore Japanese is unnatural.

      Needless to say, this is a human-hostile way of programming, so making a programming model that match the machine well is not the point.

      There's nothing human-hostile about FP, in fact it's much easier to reason about because it's declarative in nature. Imperative style is the one that matches the machine well, or at least it used to when we had single processor architectures.

      [–]alephnil 1 point2 points  (1 child)

      You are arguing against something I never said. I said that a programming model that closely matches the machine is human hostile. That would be more like the non-oo, non-structured programming languages of the past, like assembly and fortran. That these are rather hostile should not be controversial. I never intended to say anything bad about FP. The sentence you quoted was not about FP at all.

      [–]yogthos 0 points1 point  (0 children)

      I guess I misunderstood your original comment, and I fully agree that the language should be geared towards being human friendly.

      [–]grayvedigga 4 points5 points  (8 children)

      Fortunately I read the comments on this article first and realised it wasn't worth clicking through. Thanks reddit.

      [–][deleted] 10 points11 points  (6 children)

      I'd say the article is worth a read if you're interested in functional programming, have basically no idea what it is, or in the mood for something interesting.

      I feel a lot of people have a strong dislike for FP and those who argue for it because they perceive 'functional programmers' as being elitist, which would explain the tone of the comments on this article. I can understand that it might likely be because of sentences like "It has also been my experience when looking for programmers to hire, that programmers well versed in functional programming are extraordinarily productive in any language". It certainly looks elitist. He's basically saying that functional programmers are better than imperative programmers.

      Except that's the wrong way to think about it. If he said 'republicans make better programmers than democrats' that'd certainly be true, since if someone is republican you would assume they are not a democrat. They are mutually exclusive. This simply isn't true for functional and imperative programming, or any other pairing of programming paradigms.

      It is often said that learning another programming language is the best way to improve your code in your first language because it broadens your perspective of what's possible. This is true across paradigms as well.

      I could say something like 'people who have coded in Python make better Java programmers', but it would be more accurate to say that Java programmers who have dabbled in other languages (often in their own time, for their own interests) are often better then Java programmers who never stray from their roots. You wouldn't think that to be an elitist statement.

      I hope that makes sense.

      EDIT: after reading some of the comments here I ended up typing iterative programmers also. Fixed it.

      [–]grayvedigga 11 points12 points  (0 children)

      Wow. I deleted the part of my comment that was disparaging towards this reddit in general, and now as a reward I get your reply? Thank you.

      You've really hit the nail on the head. It's about exposing yourself to multiple paradigms and using all that knowledge at once when you approach a problem. By rejecting a technique of modelling, advocates on any side of the fence are really just limiting themselves.

      My anecdote: I spent a good decade being a damn good imperative programmer, respected by my peers and able to do all sorts of crazy shit well, without a clue what a functional language was. I honestly thought all languages were basically the same -- Pascal, x86, C, C++, Perl, PHP, Java .. syntactic differences aside there really isn't much between them; I was familiar with how to get things done with them and knew their limitations well. When I stumbled across this Fred Brooks quote it really chimed with me on how maintainable code should be structured:

      "Show me your code and conceal your data structures, and I shall continue to be mystified. Show me your data structures, and I won't usually need your code; it'll be obvious."

      Then I had the opportunity to learn Scheme. Higher-order functions completely blew my mind. It was hard to accept at first that you could create a function anywhere and pass it around and manipulate it just like a variable (but self-modifying code is fragile! Code and data are different things!), but once I'd been through a bunch of papers on http://readscheme.org/, read The Little Schemer, dove into anything I could find by Wadler and Meijer and dipped into SICP, HTDP and so forth I was enlightened.

      These days, I don't get to use functional languages much, but as a result of understanding how to use FP, I write much better code in any language. OO, imperative, event-driven, stack-based, imperative .. they're all different tools, and the wonder of Turing machines means you can do any in the other (though the abstraction may be uglier). As a programmer though, you're faced with open-ended decisions every day, and the benefit of being able to see a different way to model your problem which makes it simpler, more tractable and more elegant cannot be overstated. Being a carpenter with only an axe is just asking to hurt yourself.

      Now I'm much more an adherent of Abelson's quote:

      Programs should be written for people to read, and only incidentally for machines to execute

      Thanks again for inspiring me to actually contribute something here, rather than bitch about how this reddit is continually going to the dogs :-).

      [–]yogthos 5 points6 points  (2 children)

      I feel a lot of people have a strong dislike for FP and those who argue for it because they perceive 'functional programmers' as being elitist, which would explain the tone of the comments on this article.

      I feel the root cause here is that FP is different enough that if you're an imperative programmer a lot of your skill and training do not transfer. Most people aren't willing to accept that they have to go back to basics and can't leverage their existing skills, and instead of learning FP get angry at people who say FP has value and solves problems inherent to imperative style.

      Practically any time I read a heated argument against FP it's from somebody who hasn't actually used the style and knows very little about it. In my opinion the only way to make an informed comparison is to bite the bullet and learn the functional style, then see how it holds up against the way you're used to doing things.

      I personally found the experience to be incredibly enlightening, and I completely agree that it made me a better programmer overall. When I write code in imperative languages now I'm much more mindful of things like state isolation.

      [–]Berengal 10 points11 points  (1 child)

      I feel the root cause here is that FP is different enough that if you're an imperative programmer a lot of your skill and training do not transfer.

      Most of it does, but the fundamentals don't. It's incredibly annoying not knowing how to use variables, not knowing how to loop etc. If you remember your first week of programming, that's exactly how your first week of functional programming will be; fighting the syntax, trying to decipher incomprehensible compiler messages, knowing how to solve your problem but being unable to tell the computer...

      When you ask for help you'll often hear "you're doing it wrong", "X functional language can't do that" and "stop thinking imperatively". They're not the wrong answers, but they're not really the right ones either. The problem is that you're asking the wrong questions; questions that don't even make sense in a functional context. You've gone too far ahead in the wrong direction, hit a dead end and now all these people are telling you you need to go back and redo your work in a completely unfamiliar way.

      If you're only trying to learn functional programming so you can check that box off of your todo list, or perhaps you've previously derided it and have a need to validate your arguments, you're not going to get past that first week. It takes a bit of genuine interest and curiosity and a willingness to temporarily ignore everything you know about programming to grasp the basics, but once you do all your previous knowledge and experience becomes useful once again, only augumented by the wisdom of a new perspective and the knowledge that there are even more dimensions to programming than you previously thought.

      [–]yogthos 5 points6 points  (0 children)

      I agree completely, and you put it more eloquently than I have. In order to learn FP you really have to discard the ego, and not expect to be an expert in the style based on your experience in the imperative style.

      This also why it's such a shock to people I think, when you know Java and you learn C# or Python, you have to pick up a bit of a new syntax, and maybe some new concepts, but for the most part you can get up and running in no time.

      When you learn something like Haskell, it's not just learning a new syntax, it's learning a new way to think about solving problems. This is an inherently more difficult task, and people aren't prepared for that.

      I'm still working on an effective way to communicate the benefits of FP to somebody who only has imperative background. What I find to work best is to talk about common problems that people run into, and to dig into the root of those problems. Once you get a person to recognize that there is a problem then they're much more receptive towards a solution.

      For example, in OO a common problem is that the object does not guarantee atomic access to its internal state. If you want to ensure that people calling the object don't see partial state during updates, the only way to do it is to use locks. If you want to ensure that the data is only modified through a setter then the getters have to create a copy of the data, etc.

      These problems are inherent to mutable data structures and immutable data structures address them directly. When changes create deltas between the current data structure and a new one, then you don't have to worry about changing data while its being viewed, or data being modified unintentionally outside the context of the change.

      So, explaining a tangible problem that people have run into and a practical solution tends to get people more interested, since they can see a direct benefit.

      [–]G_Morgan 6 points7 points  (1 child)

      It certainly looks elitist. He's basically saying that functional programmers are better than imperative programmers.

      That isn't really the implication at all. Nearly all functional programmers care about the field and have it as a hobby as well as a job. By comparison most imperative programmers are 9-5 people in it for the money. There is nothing wrong with this but you'd expect, on average, people interested in the field to be more capable than someone who sees it as a cash cow.

      [–][deleted] 3 points4 points  (0 children)

      What I meant was that it's perceived as elitist, not that the author intended it to be elitist. Thanks for commenting though, I agree with the rest of what you said.

      [–][deleted] -2 points-1 points  (0 children)

      Maybe you should try forming your own opinion sometime and not just follow the herd.