Why compose classes, abstract base classes, etc. when you can compose simple functions!
It's true that abstractions in functional languages can seem foreign and hard to understand, but generally they have some purpose, being grounded in mathematical practice. OO abstractions and patterns OTOH, taught essentially in "elementary school" which possibly makes them seem easier to understand, do a very poor job of solving more problems than they create.
Learning a functional language is often a transformative experience that lasts throughout a career, whether you even use functional languages or not. It might make you do something as simple as partitioning which functions have side effects and which don't, even if the type system doesn't enforce it. Or use a form of quick/fuzz testing, even if it's not the standard test suite. Or make parts of the data immutable for scalability, auditability, etc. Or...
There really are few things as satisfying as developing a large codebase in a functional language. A lot of the frustrating maintenance work just goes away. But even if you don't, functional principles can yield similar benefits in imperative languages.
My opinion is that it's a double-edged sword. It's like when someone recommends you to learn SQL and relational algebras, and you, coming from OOP world, say, oh, I can learn some ORM first, that will make it easier.
Personally, I found that diving directly into the language that represents a paradigm in the "pure" form (for FP I would recommend Haskell) works best for me. It makes it most obvious why things are done certain way.
Personally I think they're great for development, but less great for learning. The advantage with something like Haskell is that it forces you do to things the 'right way' every single time and puts all the functional concepts right at the forefront. Once you've internalized the concepts then you can easily go onto other languages and bring those concepts with you.
While I haven't really written anything in Haskell since leaving school, learning Haskell has informed (and in my opinion improved) the way I program in every language more than basically anything else I've done.
> Why compose classes, abstract base classes, etc. when you can compose simple functions!
Because they allow you to compose higher level entities?
(Incidentally, one would generally compose objects).
"When programming a component, the right computation model for the component is the least expressive model that results in a natural program." -- Concepts Techniques and Models of Computer Programming
So when a less expressive model (such as FP) is sufficient for a "natural" program, definitely use that. And of course that has been the general recommendation. Switch to a more expressive model once this is no longer the case. In my experience, FP tends to be good for "computation", at least if performance isn't a primary concern. However, most of what "computers" (badly named) do today isn't computation, and modeling communication and storage over time tend to get awkward (though obviously possible).
Models in "Concepts Techniques and Models of Computer Programming"
Note that they are talking about general models of computation, in particular including at least:
- Declarative sequential model (strict functional programming, deterministic logic programming, dataflow/logic variables, higher-order procedures). Component behavior is independent of rest of program.
- Declarative concurrent model (explicit threads, by-need/lazy computation, data-driven concurrency, demand-driven concurrency). Almost as simple as declarative sequential.
Declarative model with exceptions: allows nondeterminism to be visible.
- Message-passing concurrent model (declarative plus ports/communication channels). Allows nondeterminism, and allows nondeterminism to be restricted to particular components.
- Stateful model (declarative model extended with explicit state). Allows components to keep history. Typical of sequential OO programming.
- Shared-state concurrent model (declarative extended with both explicit state and threads). Typical of concurrent OO programming.
- Relational model (declarative extended with search). Search space explored by testing choices until result is satisfactory. Encompasses Prolog-style logic programming.
- Constraint programming and still other models are discussed elsewhere in the book.
> Because they allow you to compose higher level entities?
That isn't true. FP still uses data records, they're just not tightly coupled to the functionality like OO. Pure functions + immutable types is a more powerful programming paradigm than data and functionality encapsulation via classes and methods.
Also more advanced techniques like combinators can encode more complex and extensible patterns in a significantly more robust way than any OO class hierarchy (see 'parser combinators' for an example).
You do realize that the object model is just data bundled with functions, right? If I'm using Erlang I can pass in a map that has something like #{ data => [(data)], methods => [(functions)] }. The object style approach is orthogonal to FP.
EDIT: Just to be clear, I don't think this is a good idea. It's usually better to pass in one or more data structures and one or more first class functions separately. I'm just saying that it's not too different.
> It's true that abstractions in functional languages can seem foreign and hard to understand, but generally they have some purpose, being grounded in mathematical practice. OO abstractions and patterns OTOH, taught essentially in "elementary school" which possibly makes them seem easier to understand, do a very poor job of solving more problems than they create.
This kind of sweeping unsupported assertion is actively harmful for FP evangelists. Anyone who isn't already a fanboy is most likely going to read that and say “clearly this person has no idea what they're talking about. [close tab]”.
If you want to make a productive form of this argument it'd be better to focus on discussing why the mathematical abstractions are so much better with comparisons to their actual recommended OOP counterparts. The points you mentioned about things like side effects or immutability are good but you need to not give someone a reason to go away before getting there, especially since there are going to be common tasks like I/O which are _not_ going to look like an improvement for anyone who isn't already on-board.
> This kind of sweeping unsupported assertion is actively harmful for FP evangelists. Anyone who isn't already a fanboy is most likely going to read that and say “clearly this person has no idea what they're talking about. [close tab]”.
That seems as much an unsupported assertion (i.e. opinion) as what I wrote.
I don't think it's useful to try to write a comprehensive essay with no ambiguity every time I comment, and I don't have the time. Doesn't mean I don't believe the things I say. :)
If you decide to close the tab because I said functional programming languages are much better at abstraction, that's too bad, but it's not exactly an unsupported assertion--and I'm not trying to sell you anything anyway.
If it helps, most of my FOSS stuff is written in Go, a language Haskell fans generally vehemently dislike for "ignoring 30 years of PL research." I actually like Go for a similar reason I like FP: It does away with a lot of the bad abstraction (classes) and emphasizes the good (interfaces.)
The difference is that you're dismissing the entire field of mainstream software development for the last couple of decades as “elementary school” level abstractions which “do a very poor job of solving more problems than they create”. A strong majority of working programmers are familiar with those concepts because they were taught those concepts in schools, by industry experts, and see them used by platform developers and vendors.
FP is not that pervasive and anyone trying to make the case that it's better across the board has to address that familiarity gap. Try to think about, say, the average Java or C# developer working on a large project. They aren't spending their day saying “OOP is terrible” and when you say something is better because it's “grounded in mathematical practice” that's really non-obvious to someone who's thinking the main way their life would improve would be if they could get the business stakeholder to make a decision and stick with it for more than 24 hours, stop using Oracle products, etc. Talking about avoiding shared state and side-effects, going beyond Java-level typing to make refactoring safer, etc. is a lot more useful since those probably are things they spend time on regularly.
I don't disagree that somebody who knows OOP but not FP needs a lot more information than I gave. Where we disagree is on the notion that I need to explain everything in detail when there are fountains of material out there. If anything, the purpose of my comments is to make you think, "Is it hyperbole, or is he on to something? Maybe I should look into this further."
I was an imperative programmer for a decade before I looked at functional languages, and it was because of glowing but unfamiliar praise that I looked deeply in the first place. Now I know that a lot of that praise was warranted. Everyone's different!
Also, as I noted in another comment, the "elementary school" comment was not meant to imply that it's simple--alas, one of my main gripes with OOP is that it isn't simple in the ways it needs to be--just that it's something you're almost certainly exposed to early on, so it quickly becomes what's familiar.
Just wanted to note that the "elementary school" comment in the original post rang true with me. When I was learning OOP, my first program was literally about animals (cows, chicken, sheep) making sounds. A cow says "Moo", a sheep says "Baa", a chicken says "Cluck-cluck", an Animal says "Error: this method shouldn't be executing" or something.
Yes. Note that I did not say it was wrong or that he shouldn't be allowed to hold it, only that the style in which it was expressed seemed unlikely to be effective for people who didn't already share that opinion.
> Why compose classes, abstract base classes, etc. when you can compose simple functions!
Why only do one while you can do both?
Modern languages have first class functions and support class polymorphism and parametricity, which is still a very powerful way to describe problems intuitively.
Theoretically you can do both. Practically, few languages give you the tools you'd want to ensure functional purity.
C++ is a multi-paradigm language, for instance. But it doesn't have any concept of immutable data. The 'const' keyword exists but it only does a very shallow check for immutability (i.e., the pointer won't change but its data might). And even with a 'const', there are still huge backdoors (the 'mutable' keyword).
Point being, it's possible, but you'd be relying on convention in your design and care in your implementation to make it work.
Not joking at all. Functional languages have a reputation for being hard to learn mainly because they aren't what most people learn initially (and switching paradigms is never easy, no matter which direction you're going.)
Disclaimer: The above is an opinion. Double-blind trials have not been performed!
I agree that switching paradigms is not easy. The part that sounded like a joke and still sounds like a joke is downplaying the difficulty it is to learn OO abstractions and patterns. Even initially being taught them, does not mean you've really learned nor understood them well. When comparing it to something "elementary" I'd expect something simple like 13+4, not something as complicated as software design.
Nothing we do is easy for most people... that's why we're highly sought after.
What I meant was not that it's easy to do something, rather that it's something that often comes early, and is mandatory, in your journey of discovery. The concepts you learn early on, while not easy to fully grasp, stick, and make other paradigms seem alien.
> Why compose classes, abstract base classes, etc. when you can compose simple functions
For some kind of projects (video games, applied math, anything else that is sufficiently performance or latency sensitive), data structures are just as important as code. And they need to be composed, too.
For example, in C++ I can put small structures into couple megabyte-sized vectors, because memory controllers love sequential RAM access. Then I put these vectors in another vector, because address space might be fragmented and memory manager might not be able to give me continuous 1GB buffer, also to save CPU time + RAM bandwidth when growing my dataset to gigabytes. Then I wrap these vectors into another container that creates and maintains an index over the whole dataset using a hash map, because besides sequential access, other times I want to lookup my values by some key, and I want the lookups to run fast. And so on.
FP paradigm is just fine for composing functions. AFAIK, FP offers little for composing data structures. And those sophisticated specialized data structures are often the key for writing high-performance code.
There are libraries like https://hackage.haskell.org/package/repa that make some of these tasks much easier to do. (Write your program/algorithm in terms of these arrays and all operations on them are seamlessly parallelized.) And there's really no reason you can't wrap something by making a new data type that includes the original arrays and an index.. it's just not a class.
While it's worth mentioning that Haskell does allow you to get pretty low level, it nonetheless has a GC, and the code you end up writing often looks more like C than FP. Rust is a great alternative that combines a lot of the raw performance and control over memory of C/C++ and good stuff from FP (e.g. sum types/pattern matching.) (Or even better, use something like Haskell and FFI with Rust for performance-critical parts.)
I never used Rust in commercial projects. But to my knowledge, data structures in Rust are not exceptionally good at composing, because the language lacks raw pointers.
In C++ I can add hashmap-based index to existing collection of values without duplicating the values, because I can only keep pointers in the map. I can add linked list-based LRU tracking to existing collection of values. I can use pointers to implement graph-based structures. While there’re workarounds in Rust, such as reference counted pointers, raw pointers in C and C++ are just faster.
This is incorrect, Rust has raw pointers. Those reference-counted pointers that you mention are all just standard library types implemented using raw pointers under the hood.
I’m sure Rust smart pointers are implemented using traditional C pointers.
Regardless of how you call them, you still can’t use them to compose data structures into higher-level structures in Rust.
In C++ with raw pointers, I can combine a hashmap with an existing collection of values to speed up lookups, without duplicating values. I can combine hash map with linked list to create an efficient LRU cache, with a few lines of my own code.
C++ can do that because collections, std::unordered_map, std::list and the rest of them, expose raw pointers at their API boundaries. It’s possible to store these pointers in other collections, encapsulating one or more simple data structures into a higher-level specialized data structure, with the performance characteristics suitable for the job.
A star-const T or star-mut T (wow I cannot figure out HN's formatting here) in Rust does absolutely everything a C pointer can. They're the same thing. You can do all the stuff you're talking about here. Exposing a safe interface does not also mean not exposing an unsafe one as well for these kinds of things.
See how much code is there (more than 1k lines), and note most code is unsafe.
In C++, one would probably use list<pair<K,V>> for storage, together with unordered_map<K, list<pair<K,V>>::iterator> for indexing. And the implementation would be trivial, because there’s no need to re-implement a linked list, you only need to implement these get/set methods that update both collections at the same time.
In Rust however, they had to come up with their own implementation of linked list. The LinkedList from standard library doesn’t expose raw node pointers in the API, therefore it can’t be used for the job.
Sure, but that's an oversight of the LinkedList API (which, honestly, was almost removed from std all-together, it's not exactly a shining beacon of API design) than some sort of inherent limitation of smart pointers, which seems to be what you're saying here.
I think rust safety model prevents rust containers from returning mutable pointers to the contained items. Especially pointers to item's implementation details, like nodes of that linked lists.
And without raw pointers to items, you can’t easily compose containers to make higher-level data structures from them.
There is no reason why you couldn't "compose data structures" in FP. Lists are composed data structures, as are trees. And Haskell's type classes are in fact a superior way to build ADTs.
The difference is the mindset. FP makes it really easy to compose higher-level functions. But composing higher level functions typically means little control where the intermediate results are stored (which is what Game developers need).
You can absolutely write C++ style in Haskell by composing imperative functions (e.g. IO monad). The only problem I see is the syntax. There is no built-in syntax for indexing and assignment. Writing
do
v1 <- readArray a i
v2 <- readArray a (i+1)
writeArray a (i+2) (v1+v2+1)
> composing higher level functions typically means little control where the intermediate results are stored
Exactly.
I need my code to access sequential RAM addresses as much as possible, because performance.
And sometimes my RAM layout is fixed, because I’m directly sending large sequential blocks of RAM to GPU (e.g. on Windows, by calling ID3D11Device::CreateBuffer or ID3D11DeviceContext::UpdateSubresource), and GPU can only consume C-array of POD types with very specific alignment and padding requirements.
Use the right tool for the job. If the job requires precise control of memory, FP is not the right tool. If the job requires precise control of sequence, FP not the right tool. (Yes, it's a tool that could be made to work, but you're fighting the tool rather than working with it.) If the job requires precise control of timing, lazy languages are the wrong tool.
This does not mean that there is anything wrong with FP or with lazy languages. They're just not the right tool for all purposes. When they're not the right tool, don't use them for that.
Honestly I'm not sure if OO is actually easier to understand than FP. I remember when I started programming it was a crappy but simple language called Turing that was procedural and had support for objects and pointers.
We weren't really taught classes in my high school course, so everything we did was entirely imperitive. I came across a problem where I had about 20 different entities in a game who all had a special way of updating during each tick, but I didn't want to have to write a switch statement for each one. I looked up "How to have an array of functions", and without knowing it at the time I was trying to implement first-class functions in this language which it just so happened to have.
From there it's easy to see how once you understand the concept of first class functions, many FP concepts start to fall in line, and by the way the language was set up it was difficult to use side-effects in this language, generally you use a function to output to the screen or to return a new resulting value. In fact when it finally came around to learning about classes, I had a very difficult time understanding how they worked or what purpose they served, made my Java classes in University difficult for some time.
I'm not sure what point I'm making here, I just thought how it was neat looking back that my first language I learned I naturally branched into more FP-oriented programming.
i'll say on any post here that's even slightly related: learning functional reactive programming (in my case via Bacon.js) improved my code, and my thinking about code, by orders of magnitude. Now, the only bugs are related to me not fully understanding/encoding the business logic and i can make complicated changes with extreme confidence, and as you can see i'm eager to tell people about it.
Does anyone have a solid place to start with functional programming? Don't really care too much about the language it's associated with but would really like to jump into learning the concepts behind it.
> Real World OCaml is aimed at programmers who have some experience with conventional programming languages, but not specifically with statically typed functional programming. Depending on your background, many of the concepts we cover will be new, including traditional functional-programming techniques like higher-order functions and immutable data types, as well as aspects of OCaml's powerful type and module systems.
It's a nice segue into the world of functional programming if you're not ready to give up on imperativeness just yet.
The last section there is important. In the real world, your language is not always your choice, but it's perfectly possible to put functional structure in most any language.
If you come from a C# background I really enjoy the book Real World Functional Programming [1]. The way it lays out samples side by side with C# and F# is pretty great and really helped me start to understand functional programming and F#.
That is a pretty excellent book, and definitely agree that it is helpful seeing the C# and F# code for the same example laid out side-by-side to compare. It helps a lot for those situations where you can't just switch to a functional-first language, but you want to use more functional constructs in your code.
After all, if you try hard enough, you could code in a functional style in C.
I've recommended this book in the past, and I'll recommend it again. Functional Programming in Scala [1] does a good job of taking traditional stateful object oriented code and refactoring it using pure functional approaches. Coming from an OOP background, I've found it has really helped my understanding of functional programming.
[1] https://www.manning.com/books/functional-programming-in-scal...
I like Erlang. It's got an odd syntax so some of the Java/C# baggage is dropped. It's oddity makes it kinda fun in its own right. If you want to do network programming, OTP is pretty neat.
I understand that. I started to make my product in Clojure. Got fairly along. Created an ArangoDB driver and migrator for it. Once I started creating the services, I keep having to go up through essentially the call stack to figure out what shape the data had at various points. I tried using a contract framework (forget its name, but I preferred it to Clojure's recent typing that doesn't type the value of a map). Now I'm back in Java.
The nice thing that either language will help introduce functional ideals. I recommend Erlang since its so unique.
https://functionalcs.github.io/curriculum/ has a bunch of resources. Robert Harper's Programming in Standard ML book plus the notes from 15-150 at CMU are good for general FP concepts.
For me at least, this site made programming fun again! It's colorfully written and mostly easy to follow, though some of the concepts are a bit mind blowing if you are only familiar with OOP like I was (passing a collection of functions to map really made me stop and think). Oh and it's a pretty neat way to learn emacs if you haven't already.
"However, there is a very important point that is often missed. When writing a modular program to solve a problem, one first divides the problem into subproblems, then solves the subproblems, and finally combines the solutions. The ways in which one can divide up the original problem depend directly on the ways in which one can glue solutions together. Therefore, to increase one’s ability to modularize a problem conceptually, one must provide new kinds of glue in the programming language."
We need more kinds of glue. He argues that FP provides one (function composition, a Good Thing™) and lazy FP another (lazy eval, a bit more controversial).
The last couple of decades we've seen the rise of exactly two kinds of glue (objects and frameworks) into mainstream use. Two extra may not be a lot, but you aren't getting many more anywhere else.
There are also high order types polymorphism, that normally comes with FP but it not inherently linked to it.
Well, there's dataflow/pipes-and-filters. Constraints, especially (one-way) dataflow constraints are awesome for gluing stuff together. I've done some work on making messaging more flexible, messaging is pretty powerful glue.
But yes, overall, it's been fairly abysmal. Which is why I personally think we need to really, really focus on flexible glue: http://objective.st :-)
I suggest looking up Paul Morrison's stuff on Flow-based Programming. He's been using it in enterprise a long time.
Also, if looking for glue, check out Wikipedia's list of programming paradigms or types of programming languages. Quite a few including some styles you may have not heard of.
Yep, have the book. In fact, my own OO/dataflow stuff[1] (also a good 20 years old now) is similar in some ways, and I am trying to merge ideas from Morrison as much as I can.
Have also started trying it out in GUI settings[2]
I'd say dataflow is older, but yes, it's great. And it also tends to be better implemented on FP languages (what is in them that attracts those concepts?).
Now that you talked about constraints, there's constrained search that never got mainstream but is also great. This one does not mix well with other glues. Now I'm wondering what kind of polymorphism could make FP/imperative mix well with it.
Hardly. The GoF patterns are pretty much all poor attempts at functional patterns, with disturbingly long-winded implementations. They are there because of missing features in OO languages (mostly first class functions). The GoF also label good programming practices as bad (anaemic domain model for example). They are a scourge on the world of programming.
My point was that there are language features for composition outside of functions (type-classes, ad-hoc polymorphism); as well as very sound composition approaches in code (monads, applicatives, FRP ... which actually still use functions btw). The code approaches are based on sound and provable maths, the GoF patterns are a joke, as is inheritance based composition, or pretty much any approach to composition in OO-land, because the 'glue' you talk of should be at a lower level (the function level), not at a class level or higher, where the shapes of the things you're composing don't match in any meaningful mathematical sense. Even the higher level glue in Haskell (type-classes) and Scala (ad-hoc polymorphism) is all about set theory and matching of shapes.
I'm saying this as a reformed OO dev; after spending 20 years believing the GoF (and OO world) dogma I finally changed my thinking about 7 years ago after a super large project I still work on became cognitively too difficult for the team to manage (the scale of the code-base combined with the extreme abstraction of components and hidden mutable state meaning it's very difficult - unless the coder wrote the feature - to know what mutation would go on behind the scenes; this is one of the big failures of hidden mutable state with packaged functionality that hides the mutation).
Inheritance is a myth, interface based abstraction is a myth, code reuse is a myth, OO composition is a myth. You may achieve this stuff once in a while, but if you 'abstract' a service behind an interface, 9 times out of 10 that service's own interface is imprinted in the abstract interface. And when you do decide to replace it later, unless it's trivial, then there is nearly always a change to the interface. If the thing behind the interface mutated state, then whether you like it or not, the code that uses it makes assumptions - which increases coupling. Abstraction is used liberally, even when you're only abstracting one type of thing. "Ah, I have a MyService class, let's abstract it behind an IMyService". "But there's only one of them?", "No matter, Martin Fowler said I should".
When you see whole DI frameworks and tooling, and mocking frameworks, you must realise that something is wrong? Why use DI when you can just use first class functions? Or a Reader monad? There are a lot of people in the OO world with opinions on the perfect architecture for applications, but none of them have any study backing them - but the dogma flows and flows, it's like, once somebody reads the GoF book they think they have all the answers. Yeah let's use the Visitor pattern to get over the fact we don't have algebraic data types. Let's use the Command pattern because we don't have first class functions, etc.
I prefer to rely on the proven technology: mathematics. It works, and writing 'expression oriented' code with immutable values just makes sense. It makes sense for the brain, it makes sense when you don't want code rot, it makes sense in parallel programming, it makes sense when you want programmers to know what the hell is going on.
Bringing in functional practices, and going away from the whole OO 'belief system' was enlightening, and I'll never go back. Neither will anybody on my team. I realise you've nailed your colours to the mast, and it's clear from this thread that you're living the OO dogma dream, and none of this will make any difference to you. But your blanket dismissal of anything from the func...
> Imperative programming is like building assembly lines, which take some initial global state as raw material, apply various specific transformations, mutations to it as this material is pushed through the line, and at the end comes off the end product, the final global state, that represents the result of the computation.
This isn't the best analogy as functional and imperative languages are both often used in a procedural fashion. If I simply replaced "global state" with "immutable arguments", this analogy fits functional programming as well. The fact that the arguments would be copied, however, would be implied.
> Each step needs to change, rotate, massage the workpiece precisely one specific way, so that it is prepared for subsequent steps downstream. Every step downstream depend on every previous step, and their order is therefore fixed and rigid.
This is more about tight coupling than imperative vs. functional paradigms. In general, imperative methods can be just as loosely coupled as functional methods. It basically comes down to what sort of data you're handling.
> Because of these dependencies, an individual computational step has not much use and meaning in itself, but only in the context of all the others, and to understand it, one must understand how the whole line works.
This, again, can be true of functional languages as well. You cannot always guarantee that a method is individually useful given the data at hand.
There is some faulty assumption that functional programming is never imperative. Functional programming has nothing to do with declarative/imperative programming styles. The "functional" part determines the architecture by which the code is structured opposed to the style (vanity) by which the structure comes together.
If you need to compare functional programming against something contrast it against OOP, which is a different architectural approach.
>Functional programming has nothing to do with declarative/imperative programming styles.
nothing!?
>The "functional" part determines the architecture by which the code is structured opposed to the style (vanity) by which the structure comes together.
> Functional programming has nothing to do with declarative/imperative programming styles.
> The "functional" part determines the architecture by which the code is structured opposed to the style (vanity) by which the structure comes together.
I think it means a code can be functional but looks imperative. One example is the for-comprehension in Scala:
val aFuture = future(a)
val bFuture = future(b)
(for {
a <- aFuture
b <- bFuture
c <- futureC(a, b)
} yield c)
This is just a contrived example for working with `Future[T]`, but it can be applied to other monadic types.
>> functional and imperative languages are both often used in a procedural fashion
Exactly.
The most common ELI5 definition of functional programming I get from other developers is that you're piping multiple statements together into a single chain of processing [input(s) > multiple levels of processing > output(s)], without having to explicitly declare variables to hold the temporary inputs and outputs between each sub-statement within the chain. I know just enough to understand that this isn't the "proper definition", but that workflow is true enough that it's what many people associate functional programming with.
The problem with that particular definition is that it tries to make the primary benefit of functional languages seem to be this piping/chaining mechanism. Yet these languages are still written procedurally, executing multiple such pipes in sequence. You still have variables holding the inputs and outputs of each chain, so you can pass them to other unrelated chains. It reduces the overall number of statements and the manual variable/memory management required, but each statement is simply a compressed version of multiple statements merged into one, enforcing "fake immutable" variables for the inputs/outputs within the chain. You don't really have "immutability"; you simply have automatic variable management between sub-statements in a chain.
Now, show me a functional language where the entire program is written as a single piped chain, and I would classify that as its own genre. Literally, the entire program would have to be written top-down as a single block of code that chains every single required input from the top-level, all the way down to a single output, without using a single explicitly declared variable. Only the first line of code would be unindented at the first column, with all other lines having to be indented as part of that primary block. Now that would satisfy me as being "unique" or "different than procedural".
What is the primary metric of a functional language? Is it to write write golf code[1] that folds 10 "procedural statements" into a single 3-line "functional block"? To me that's not "functional programming"; that's just writing less code by chaining multiple operations into smaller blocks, reducing the complexity of having to explicitly declare more global or widely scoped variables.
Random thought association: is perl's well-known Schwartzian transform (@sorted = map { ... } sort { ... } map { ... } @unsorted), applied as a concept to an entire language, what makes a "functional language"? To me, that doesn't seem like enough of a scope change to warrant a different language "type".
you might want to check this js code I wrote. The whole program is essentially one big function (starting with runApp). Wonder if that is what you were looking for:
To meet my new-language-style expectations, you would have to remove every single "const" in your code. You have multiple definitions, all simply executed in sequence based on an initial caller. I was thinking of a single block that took all inputs to result in a single output.
Forgetting my expectations, the code example you linked is practically the antithesis for ES2015/ES6. You've abused the concept of "const". Your example is terrible, using "const" to define things that should have been defined as separate classes, without having to define so many global "const"s.
Even more critically... wtf are you doing with all those "const" definitions? That code is ultimately worse than what I saw in javascript in 1995. Please don't write code that way. :/
To go to the extreme, my ultimate reaction is that the code you linked is straight up unacceptable. You would fail an interview at my company with that code. It screams "I know ES6", while being the worst example of javascript I've ever seen, regardless of the Ecmascript version. You're overcompensating, trying way too hard to prove that you understand the latest spec. There are limits to what "modern javascript" means, and you have gone too far. A dozen global "const" declaration means you know ES6, but don't know how to write proper code.
tldr; Dial back a bit. Upgrading to ES2015/ES6 does not mean transforming all your code to be completely unreadable unless you know the latest spec. Your code should still look like javascript rather than 100% some-new-functional-language.
What are you talking about? How is this code worse than what you might have seen in 1995? How has the concept of const been abused - it is just an assignment keyword, no worse than the var of 1995.
If you attempt to compose functions out of smaller functions, then you need variables to hold on to those small functions. What's wrong with that? And why would you need "separate classes" for those smaller functions? What problem would "smaller classes" solve?
I don't understand your criticism. You asked for a functional program , I showed you one, and you start a rant against it because it looks functional?! It just happens to be in js but it could also be in common lisp or clojure or whatever..
The crucial thing to understand is, that those consts are just assignments for global modules that I use. They are NOT variables. But if you want to go to the full extreme and remove every single const: EASY! Just add all the modules to the environment of the most external Reader monad and inject them into the function chain. This would get rid of 99% of global consts that are not functions. I leave that as an exercise to you.
The rest of the consts are just function assignments. Instead of const f = x => ... I could also write function f(x) { } .. but honestly, I prefer the former. It is more elegant in my opinion ... So in order to get rid of them, just rewrite it. This is trivial.
Finally, you would want to get rid of the two local consts within the two functions putPublicationToElastic and createUploadDocument: Straightforward, they are just there for cosmetic. Again, they are NOT variables, they are just names to make some following lines a bit shorter. Again, exercise to you to remove them.
So if we do all the three steps above, the only const we would have left would be the config variable. The rest is one big function, composed in order to achieve a goal. Mind that calling the function will not produce any output (You'd have to fork it), so the function is even 100% pure...
Honest question to you: Why would I need a class here? I really don't see anything in that code that would profit from being put into a class. It's just a bunch of functions composed together and wrapped into a Reader monad. I can rename runApp to uploadSQLDocumentsToElastic and export it and have a perfectly fine, encapsulated logic. I don't think you could do better with a class. But if, please show me. I'm eager to learn!
P.S. Please tell me the name of your company. Another one I would NEVER ever want to work for ;-)
P.P.S. Sometimes people write code as an intellectual exercise. In order to try out some new paradigm, or coding style. I'd advise you to consider that next time before attacking their efforts.
> piping multiple statements together into a single chain of processing[] without having to explicitly declare variables to hold the temporary inputs
This is known as point-free style. I think point-free style implies functional programming (at least locally; i.e., a point-free function will by definition be functional, although it can call imperative functions) but functional certainly does not imply point-free.
Please tell me you know of a functional language that does not incorporate "point-free style", as you put it. I would love to look at such a language as a way to redefine how I view functional languages in general. No sarcasm involved, I am genuinely interested.
Ah, well... point-free style is going to be more-or-less possible in any decent functional language; it (or rather, functional composition) is one of those things like "while loops" in imperative languages which, if absent, would cause you to consider a functional language kind of rubbish. Functional programming would be far too verbose to be comprehensible otherwise.
That said, Scheme is probably a good example. Lisps in general are a funny case for functional programming: historically they were described as "functional" but the word had a different meaning we would now call "procedural"; I think Lisp may have predated Algol so the concept of having functions at all was fairly notable. However, Lisps generally support functional programming and Scheme has embraced it more fully than the others. Note, for example, that Scheme doesn't actually have loops as a fundamental concept in the language; it emulates them with obligatory TCO and convenience macros.
My apprehension comes from lack of seeing it in the wild (i.e. scaled businesses).
Google primarily uses C++/Java. Facebook: Hack. Twitter tried Scala and as far as I know, abandon it and went to Java. LinkedIn definitely tried Scala, failed, and went to Java. Square is Ruby/Java.
I'd like to have something to point to as a success story of a company at scale with functional programming. Anyone know of one?
From the article "in this case for massive distributed systems Functional Languages are the right tool
...
Immutability at scale is really important because it allows you to go from 30k members to a staggering 2.5 Million+ and not even feel blip within 3 months, like we did here at Jet from the end of July to October. That’s powerful!"
I once heared a speech from Joe Armstrong, where he considered erlang the only true object oriented language... This was of course a little quip to the OOP community, but it has a certain truth in it. He argued, that the actor model is basically object orientation like it should have been done.
If you look at early concepts for OO where objects were simulations of things (Smalltalk, Simula) and communicated via message passing, erlang's process and message passing model actually fits well within the OO-framework of thought at least with regards to application design. What it's missing are syntax/semantics based on class hierarchies and such from OO languages like Java and C++, which isn't a bad thing.
"Joe Armstrong: Smalltalk got a lot of the things right. So if your question is about what I think about object oriented programming, I sort of changed my mind over that. I wrote a an article, a blog thing, years ago - Why object oriented programming is silly. I mainly wanted to provoke people with it. They had a quite interesting response to that and I managed to annoy a lot of people, which was part of the intention actually. I started wondering about what object oriented programming was and I thought Erlang wasn't object oriented, it was a functional programming language.
Then, my thesis supervisor said "But you're wrong, Erlang is extremely object oriented". He said object oriented languages aren't object oriented. I might think, though I'm not quite sure if I believe this or not, but Erlang might be the only object oriented language because the 3 tenets of object oriented programming are that it's based on message passing, that you have isolation between objects and have polymorphism.
Well if you want to go that way ;-) jokingly Erlang is the only true OO language implementing Alan Kay's idea of what "Object Oriented" means -- passing messages between isolated components.
I've heard of inheritance as a corrupting influence which has taken over and corrupted OO for years/ Funny enough, even most OO folks eventually realized that and moved to banish inheritance as a viable pattern.
You can do functional programming in many languages. Using functional programming or having a "success story" with it doesn't mean you need to use "functional only" -language or Scala.
For example: I've been developing for the last 3 years for the iOS and we been using FP and FRP almost everywhere with different teams and companies. Compared to the standard OO or Apple -way of doing things we have been able to make much better tests, stability/maintainability of the apps has increased etc.
That's an excellent question - especially given that you can essentially use it as a "functionally enhanced java" as it's not a hard-FP language like Haskell. I'd love to know - maybe it's a question of staffing? More skilled Java programmers around than Scala programmers probably. Also might be easier to work with lower level DB libraries and such, but I don't see why a company that large couldn't develop and maintain their own abstractions.
"especially given that you can essentially use it as a "functionally enhanced java" as it's not a hard-FP language like Haskell"
I'm not sure if I can call this "the Haskell community consensus", but a lot of the Haskell community finds Scala too complex to be worthwhile. They find it introduces a lot of complexity above and beyond Haskell, but at the same time, fails to take proper advantage of it and the result is quite dirty, full of special cases, and consequently hard to reason about. So you get a lot of the costs, perhaps even more costs for compliance than a Haskell code base, but you get fewer benefits.
That's really the main issue per the original question. It's not that functional somehow fails on its merits to deliver, it's just that "at scale" means having enough developers who know it. The reality is that imperative/OO languages have the greatest mindshare, and thus it's far easier to find developers, and far less wind-up time, if you're using such a language.
Also, there's enough different about Scala that can't be expressed on a simple OO vs FP axis that it's hard to learn that much from Scala vs Java. (On this axis)
So far the only real instance of a big company abandoning Scala has been Yammer, so this is a mistaken impression. LinkedIn and Twitter are heavily invested in Scala.
Designed to replace and address flaws of an older language but ends up being huge and unmaintainable, with very questionable design decisions and a tool chain that's simply not up to standards in the 21st century (slow compiler, poor IDE integration that keeps breaking version after version, etc...).
In C++, some of these design decisions were driven by legacy pressure but in Scala, a lot of design decisions were driven by the pressure on the team to write research papers. Either way, both languages end up being monsters that implement all known programming language features known on Earth.
Quite the opposite. Scala is a language designed around a very small core of very powerful, and sometimes hard-to-grasp features like implicits or higher-kinded types. It is a different language than Java and was not designed to replace Java or to be a better-Java.
Your C++ to C analogy doesn't hold, because C++ is an (almost) superset of C, while Scala is not a superset of Java at all. Modern C++ compiler can compile most of C code with at most minor, cosmetic changes.
As for the toolchain - I'm working in it daily and so far it has been great. Ok, compiler is not as fast as Java (point taken), but this doesn't matter as long as I can compile my code fast enough. IDE support is stellar compared to most other popular languages, particularly dynamic ones like Python or PHP.
It's not just too complex (we're talking more complex than C++ and Ada) but also poorly designed overall, with so many features that they interact with each other in ways that are pretty much unpredictable.
Odersky himself gave up on scalac and he's writing a compiler and a new language from scratch.
* C++ language specification: 1374 pages (and still includes plenty of "unspecified behavior" / "undefined behavior")
* Java language specification: 788 pages
* Scala language specification: 191 pages
> Odersky himself gave up on scalac and he's writing a compiler and a new language from scratch.
Odersky created a new language to be able to do research without sacrificing Scala stability, which is already mainstream and should not undergo any more major revolutions. So Dotty is for research / incubating language features, while Scala stays on the stable side of things, letting companies like Twitter or LinkedIn develop without fear that 2.13 will not compile their 2.12 code.
> also poorly designed overall
This is an opinion, not a fact.
> With so many features that they interact with each other in ways that are pretty much unpredictable.
Name three. I'm coding in it for several years, and didn't notice a single one issue. I heard this complaint about Scala being too hard a few times very long time ago (when Scala was at version 2.6, and its tooling was in fact terrible), but it was always from programmers, who had also major problems coding in Java, so I never treated this seriously.
As someone who loves typed functional programming and has used both Scala and Java, I oddly prefer Java; it's much easier to reason about. I find Scala almost impossible to make sense of due to the language's complexity.
Scala is very powerful. Too powerful.
There are too many ways to do the same thing and no idiomatic way. Some people also abuse Scala to create DSLs with horrific syntax that is very hard to comprehend.
I love and use Scala, but I can totally see why it can
be a hard language to use for collaboration.
I think the end result is going to be companies adopting functional concepts. I can't find the article right now, but Carmack wrote about how even though he was not sure if he would write a whole game engine in something like Haskell, just learning to think functionally improved his C coding.
Java has had lambdas and streams for awhile now. A pretty common design pattern has also become anemic domain models operated on by groups of functions, which fits in the spirit of functional programming. Modern java can, and is used in a functional style.
On the JS side, functional concepts are everywhere. Given how heavily FB and Twitter are invested in JS, I don't think they have abandoned functional programming at all.
Finally, IMO Scala is actually a pretty poor example of a language that can be used at scale. Without a highly enforced set of rules it can quickly become a write once/read never language. I'm sure there are exceptions, but given the choice between scala and java 8+, I would go with java. Clojure may be an option though.
Yeah, my Java code pretty consists of two categories of class types now days.
Pojo's which are just data structures or a glorified HashMaps for holding data. And, if allowed, using Lombok to get rid of all the getter/setter cruft.
The second category of class types are just Service classes. These classes hold no state and are a logical grouping of methods that typically operate on a given data type. However, the class is based more on a specific role it performs than the type(s) it operates on. Also, there's considerable thought given to reuse of the Service classes outside the given context at hand.
The reason why you see this pattern is not because in functional programming vs. OOP, functional losses.
The reason for this pattern is because companies look for easily replaceable developers.
To get into functional you need to be good at abstracting the business domain, this requires seniority which is hard to find. Most of the time, when you are working using functional programming you are implementing the business vocabulary. Entry level developers are not good/interested in this. Their worries are in how they can use Angular 2 in this project, or why we need to still use SQL Server instead of converting to {insert the newest database technology}.
It is easy to find (and replace) junior developers that are happy because they created something with the latest technology and it provides the immediate value intended. It sounds good, but it misses the point.
Software development in a company happens to support/enhance the business. This means that it has to stand the test of time, not only in reliability but also in adaptability. The only constant in software is that it will change. Here is where building a vocabulary that represents the business subjects pays off. Change now is a definition-change and, unless the business is pivoting, definitions rarely change; instead, they have constant adjustments. Functional shines in creating a vocabulary and having this adaptability.
Of course, you can adapt using OOP, but the question is not if adaptability is possible, it is instead how to make changes at the lowest risk.
>Most of the time, when you are working using functional programming you are implementing the business vocabulary.
>Here is where building a vocabulary that represents the business subjects pays off. Change now is a definition-change and, unless the business is pivoting, definitions rarely change; instead, they have constant adjustments. Functional shines in creating a vocabulary and having this adaptability.
I tend to use the same arguments to make the case against FP for business modelling.
I tend to say that FP is good at adding new operations to existing things, while OOP is good at adding new things to existing operations. However when Software Development is used to model a business - as it should be for reasons you accurately explained - the reality it meets is the one of the business world in which business needs evolve and requirements get added. You start by supporting local groceries and then you grow to support global supermarket chains. OOP is more suited to model business because you can naturally extend existing types and apply existing operations to them (ie. pass a supermarket everywhere a shop was expected + things such as polymorphism). In FP, every time you add a type, you need to add switch cases to your existing operations (at best), or redefine them create / new ones (at worse), since the ubiquitous assumption of FP development is immutability and known types.
I'd be curious to know how you approach this conflict in a way that makes FP work in real world business modelling which needs to be extension-oriented. It seems to me that the more operations using a type you have, the more you will be screwed when you want to extend this type. The only reason I can see this wouldn't be the case would be to say that I approach FP with the wrong philosophy and that there is no such things as extending types in FP. But in this case I'd question if FP modelling really is the best tool to model real world business for which it is natural to define things as extensions of other things.
Thanks for the reference, this is indeed all about it. The solutions mentioned are unnatural patches to the respective shortcomings of FP and OOP. It's ok to patch corner cases to complete the last 15% of a job for which the tool was a perfect fit for the first 85%, however the first patch should be to use the right tool for the right job.
The functional and strongly typed value proposition of FP is very appealing on paper but only shines when you have a level of certainty and knowledge on requirements that you typically do not have in real world software development. OOP by design embraces this uncertainty (but as a trade off is less assertive on correctness than FP).
That being said, certain businesses do not have a high level of uncertainty in their developments while correctness is a big deal for them (banks, scientific researchers, etc...). It makes sense for them to reinvest this slack in correctness. However, for those iterating consumer facing products (which represents the majority of developments), OOP modelling usually is the way to go. Because of the expression problem (which should probably be called the expression dilemma to better highlight the fact that the assessment should be continuous and situational rather than ideological and/or philosophical)
What you are mentioning is one of the hardest things to do when moving into FP.
"OOP is more suited to model business because you can naturally extend existing types and apply existing operations to them (ie. pass a supermarket everywhere a shop was expected + things such as polymorphism)"
The reason why you feel is more suited is because you are thinking in an object oriented way. It is not a bad thing, but it is not functional.
"... extend existing types and apply existing operations to them". This means you have things, and you do things to them. This is the OOP way, not the FP way.
In FP the things are immutable, so you don't do things to them because they cannot change; instead, you create new things out of what you have.
In OOP this is what you have, this is what it can do, and you put all the gears (or objects) together and you get your engine.
In FP you have pipes, this is what I have and if I put it through this pipe it becomes something else.
When a local shop there is a sale, there is a function that takes a bunch of arguments and produces something called a sale, Maybe is the total, maybe is a tuple with the different pieces of the sale.
When you move that to a supermarket, then the question is: how what the shop owner calls a sale in the local shop is different from what the supermarket owner calls a sale? How my vocabulary changed? for a lot of things, you will see that the meaning is the same, just over more data; and also, there are new words that didn't exist in the smaller context. A sale is in both cases the sum of the quantity multiplied by the price of the groceries, apply the tax, spit out the result. But maybe the meaning of Tax changed, instead of been a fixed percent, it needs to be the lookup in a table depending on where the supermarket is.
If you need to constantly add switch cases, then probably you are using a functional language using an OOP mentality.
The way that I have introducing FP to people is using Excel. Think on this syntax:
A1: 1
B1: 2
C1: A1 + B2
You don't need new cells, C1 does not mean the same thing and the formula have to change... the formula or is it the function?
When you model the real world, you can focus on the objects, map them to types, and go from there. Or you can focus on the meaning of the words, then you need just a few types, see how those meanings compound, and go from there.
"But in this case I'd question if FP modelling really is the best tool to model real world business for which it is natural to define things as extensions of other things."
I agree, FP is bad at extending things... but it is not FP fault that you see the world as things that need to be extended.
Many thanks for taking the time to explain this, I can see that you have a point.
>Or you can focus on the meaning of the words, then you need just a few types, see how those meanings compound, and go from there.
>I agree, FP is bad at extending things... but it is not FP fault that you see the world as things that need to be extended.
I should probably give another look to FP and continue to study the subject, I have likely been approaching it with a OOP mindset as you suggest. One last question though, what about code duplication ? If you focus on the meaning of words and compounding these meanings to create new things, wouldn't it most of the time create lot of duplicate code ? For example in the case of the local shop and the supermarket, wouldn't you have two functions (or a switch case) containing exactly the same code to calculate the quantity multiplied by the price of the groceries ? One would take a local shop as parameter, and the other one would take a supermarket.
Splitting the sale processing function in two parts - one summing up the groceries and the other one calculating the taxes - so that you can reuse the first function implies knowing in advance the existence of the supermarket structure (which you will only know many years after putting your product in production). Not doing it in advance either means duplicate code or refactoring every time you add an operation. The extension mindset initially comes from the need to avoid code duplication which is known to make maintenance difficult.
Now maybe the strongly-typed experience of FP and its compile-time checks are so convenient in practice that they make the maintenance of this kind of code easily manageable ? Maybe it's not even really duplicate code since what would be a basic number in OOP would be two different types here in FP ? Or maybe it's still thinking about FP from an OOP perspective ?
What goes through the sale function pipe is not the store and its size, it really does not matter for the meaning of sale were the sale happened. What matter for the sale is the cart. The cart might be more or less sofisticated because the size of the store, but is still a cart.
So the sale function is a pipe that eats a cart and spits out a receipt.
Or if you want to put it in another way, a sale is something that might happen to a cart over time. Functions are the clock on the system. In a functional system, times does not pass until a function is executed (does it sounds like lazy evaluation?)
In functional programming, we avoid duplication of code by appliying functions to the data so it spits what the next function needs. If you have a function sale that can eat a simple cart, but now you have a complex cart, one solution is to create a function that converts the complex cart into the simple one that the sale function needs; another way is to make the complex cart having the same data as the simpler cart. What you choose to do is proportional to how different the meaning of cart is, or maybe the cart remains the same. In general terms, this type of thinking tend to produce less lines of code needed per similar acomplishment.
So in OOP your are using objects to put together the store, while in FP your are descriving what happens in the store by connecting pipes betweem the different data. It is not about what can happen to the data, but what makes the data travel. It is not about what steps makes it work, but the fluidity of the data life span.
Many thanks jorgeleo ! I wasn't clear on how FP handles complexity management and the unknown. You've beautifully connected the dots and helped me shift my thinking, this is all clear now.
In particular your demonstration was very convincing from a DDD perspective. I can see that FP is not less natural than OOP for domain modelling while it approaches things from a very different angle. However FP brings to the table rich domain semantics, high correctness guarantees, and I feel productivity gains too. And with the mindset you've presented, it is also clear that the unknown seems to be accounted for in FP too. As an architect, this last point was the grey area and the deal breaker for me. However now I see no reason not to invest in heavily leveraging FP moving forward. Thanks again jorgeleo.
> Twitter tried Scala and as far as I know, abandon it and went to Java.
This is incorrect. One of the former VPs said he would not use Scala. Twitter uses Scala massively and has published and continues to maintain several open source Scala projects.
> LinkedIn definitely tried Scala, failed, and went to Java
This is incorrect. A newly hired VP insisted on moving the front end from Scala to Java. In the offline backend stack Scala is used extensively. Check Kafka, Samza from LinkedIn or better yet ask current LinkedIn employees.
Apart from these Spotify, Foursquare, ebay, several banks use Scala. FP is huge in financial institutions, check K/KDB+. Jane Street etc. Thats where most FP programmers work. Also verizon, jet.com and walmart.com. There are several dozen large companies using FP.
FP is mainstream now. Traditionally, it was financial institutions using some flavor of ML/Haskell. With Scala/Clojure on the JVM, Si Valley has moved into FP in a big way.
Since I don't think he means Scala transpiled to javascript, I assume he means the services/apis that are used by the front end. This is distinguished from applications which do not talk directly to the browser. Front end and back end have different meanings depending on perspective.
Facebook/WhatsApp is using erlang for their messaging backend. Erlang itself was invented at ericsson labs, they are one of the biggest suppliers of telco backend equipment.
Wings3d.com is written in Erlang, a functional programming language. Additionally any business that scales will be using functional constructs, because they parallelise trivially. Google uses MapReduce for instance. Visual Studio rewrote their compiler to use immutable constructs, and so on.
Functional Programming, as the article points out, can be universal to many languages. You don't have to use an "FP" language to enjoy "FP" benefits.
JavaScript, for example, is ubiquitous in the industry, and, especially with the advent of ES6, can be written quite functionally. ReactJS is also widespread and can also enjoy an FP approach.
MapReduce, which Google built for indexing the entire web, along with many other big data tasks, is an example of something that could only have been invented by someone familiar with the principles of functional programming:
Imperative/object oriented languages are often more practical for real-world use (MapReduce itself I believe is written in C++), however it's the ideas of functional programming that matter most. Those with experience working in functional languages are at an advantage over developers who've never had that exposure, because they have a wider range of mental tools at hand with which to solve problems.
Plenty of people use functional languages in the wild, though sometimes, like Jane Street, they don't do it for the same reasons that are normally stated as being the reasons functional programming is better.
This is a good video, from Jane Street, on why they use OCaml:
Or even better, how about empirical research to back up the claim that functional programming is "better"? Does the use of functional language result in fewer bugs at less cost? Compared to what (C, Java, Ada, Lisp)? I don't have an opinion on it but I would like to see the bold claims backed up by actual evidence instead of assertions.
It would be nice, but is a rather tall order. Total cost of maintenance and development of software is not usually public, often unknown even to the developing company, and not actually a very useful metric without context of how much value was generated by that cost. And again that generated value is generally not public and usually unknown even to the companies themselves.
Another approach is to run experiments but they are universally terrible. Their methods have so little relation to the way real software is developed, that it is hard to take any conclusions seriously.
I would also like some hard data, but don't hold your breath. Technology decisions will probably need to made based on other factors for the foreseeable future.
I agree that hard data is difficult to come by. Without it though, people should not be claiming that X style of programming is better than Y. As much as I like the functional style, it could be that Pascal-style structured programming is actually the best. Who knows?
There was a recent post here on HN about empirical language design and I thought that was a refreshing change. I'd like to see a change in software culture towards an evidence based approach. It's long overdue. Alan Kay called the software world "pop culture" and I think he is right. Software is more fashion driven than Vogue magazine.
Academic research could be a vehicle for a more empirical approach. Research in the hard sciences embraces empiricism. Sadly, the academic research in software doesn't, generally, adhere to the same level of rigor.
Erlang is used at WhatsApp. One of the interesting things there is that for the amount of users and messages handled they had a very small backend team. They have credited Erlang and its features as one of the keys to their success. It means less code (mostly related to minimal impedance mismatch from language to problem domain), debug-ability, reliability, fault tolerance, less ops overload and so on.
I personally find it much easier to navigate and fix bugs in an Erlang code base than in the equivalent C++/Java/C# one. It mainly boils down to how state is updated. When I see NewState = update(Value, State) it is clear what is happening. In OO code, I usually need to remember what object inherits from, what are is the instance state so far (what other members have been called) and how it got there. I find that much harder to handle, for example.
Bleacher Report went from 150 servers to just five (yes, that is not a typo, that is a 1/30 reduction) moving from Ruby on Rails to Phoenix on Elixir (née Erlang, but we should just call it "BEAM" at this point): http://www.techworld.com/apps/how-elixir-helped-bleacher-rep... They also handle 8x as much traffic. With 1/30 the number of servers.
Ruby is OOP. Elixir/Erlang is purely functional (although dynamically-typed... some will prefer typed... but the results speak for themselves).
If you are a long-time developer like me and are just coming across this, this news should strike you somewhere between "astonishing" and "pure fucking magic."
Here's the deal- Paradigm shifts, most people only see them AFTER they've finished. If you want to be ahead of the curve on this one and you want to reap the benefits, go functional (Haskell, Clojure, OCaml, F#, Elm, Erlang/Elixir). Today. That is my #1 piece of advice right now. (Well, that, and to avoid Scala and Go. Scala is just too overly complicated to keep your cognitive load down as a developer, and Go... Well, the name even says it: "Go!" As in, "don't stay!" ;) Go will suffer the same long term problems that all OOP/procedural langs share, compounded by its idiotic take on error handling /opinion)
If you're a long-time developer and just coming across this, it should be... old news. The Techempower benchmarks [1] have consistently shown Ruby on Rails results can be in the range of 1/30 to 1/40th speed of C, C++, Scala, Java and Go, depending on the kind of task. The first thing I thought of actually was an article from 2013, on replacing Ruby with Go [2]. I'm surprised there aren't more of these sort of articles, really: Replacing Ruby on Rails with Rust|Scala|Java|Insert Here.
There are a lot of interesting aspects of functional programming, but there's no particular miracle here: Ruby, particular Ruby on Rails, is slow.
The Quant firm Jane Street uses Ocaml and built Core [1], an alternative to the Ocaml standard lib. I wouldn't be surprised if their business domain benefits from FP.
Also demonware [2], which is owned by Acitivision/Blizzard and manages online game lobbies for all their titles (ie Call of Duty series across all platforms), uses Erlang. They switched from C++ to Erlang before Call of Duty Black Ops was released. They said if they hadn't decided to switch before the release the company would have never been able to handle the 5 months of user growth the game brought to their platform [3].
I've seen an number of papers focusing on the mathematical side of things. While I'm not a PL researcher, it does seem to me that math is the universal language and it seems reasonable to focus on that rather than non-sense concepts like objects.
By capturing relations. If we define an algebra it will have certain properties (eg commutative, associative). You don't think twice when writing a physics equation on how to factor, compose, or compute a value. It comes naturally from the rules of algebra.
In category theory we might have different categories. Some might instruct the compiler and programmers that the function obeys certain rules when applying. It could be trivial to parallel or perhaps it specifies a strict sequencing for computation. Following Haskell research, you can really see the evolution as people find more useful generalizations (which in the end, has made things simpler!)
I know it's just anecdata, but from my experience, Haskell forces me (due to strict control over side effects) to write really short functions. And while that can be harder to do when you're writing the code, it seems to really help readability, testability and reusability.
It's not like you cannot write short functions in other languages - you can - but it's often too easy not to do it.
It would be nice to have some empirical evidence for this, unfortunately I am not aware of any.
What you say is true, but the flip side is that scientific research on programming language effectiveness is a very small field, and it's unlikely the academia will be able to do the large scale studies that are necessary to establish meaningful results. (For example, no sizeable project is going to be built in two different languages just to gather evidence for a research study.)
Without rigorous evidence we're left to argue from theoretical models / principles and anecdotal data. This is still useful. It would certainly be more useful to have rigorous empirical results to back up the claims and validate the models but we, as practitioners, have to make decisions on language choice now using the available resources.
> Does article contain references to any enpirical evidence that particular language features or programming idioms have a benefit?
The kind of empirical evidence you are asking for is extremely expensive to provide. Even if you conduct a massive controlled trial, experiment will have several biases which will invalidate any conclusion. As an exercise try looking for scientific evidence that programming in Java is more efficient than programming in assembly. No scientific evidence for this exists. Yet most of us would never choose to write a web service in assembly! The only evidence that can be provided are discussions and benefits of particular features and anecdotes.
I'm not the user you're replying to, but I found this question interesting.
> Do you think programming productivity is possible to measure and if so how?
For the purpose of discussion, I would propose that a team of developers are given a simple task with highly specific and explicit functionality requirements. This team of developers should Ideally have no experience with any of the technologies used. Experience with the problem domain is acceptable. These developers would then be tasked with building out the solution with various different technologies (languages, frameworks, libraries). We then compare the time it took for the developers to complete the task relative to the amount of bugs present in the solution. For example, the team could be tasked to build a gui calendar with Haskell and then Python.
The issues with the above proposed experiment are as follows:
* We would need to find some way to adjust for problem domain familiarity. The developers are going to get better, and thus more productive, at the task after they have completed it the first time.
* We need some sort of concrete numerical measure of "bug likelyness" for lack of a better term. All software has bugs, but some are very hard to find or appear only during runtime under very specific conditions.
* We need to decide whether or not we take the language ecosystem into account. In the calendar example I provided above, Python would obviously be more productive because there are a ton of different packages available that make creating a GUI extremely trivial.
* Do we take into account time spent on learning the language/tool/package/framework/library? Do we measure the amount of time that it takes the team to feel comfortable working with a new technology?
All in all, it's an interesting thought experiment and I'm interested to hear what you think.
The above papers are not about FP but about static type systems (there tends to be lots of crossover), but I think you'll find that what it really comes down to is guarantees provided by a language. I would be surprised if similar research that focused solely on purity did not exist.
This is an incredibly difficult area to study. "Better software" is a difficult metric, and even a more meaningful metric is incredibly hard to measure. For a field as young as CS it's no wonder that the research into this is still immature, so we largely have to rely on anecdotal evidence and common sense.
So yeah we have some research and we have some basic common sense and we have people demonstrating through their projects that it has worked well for them.
More to the authors point - what they are really talking about here is modularization being a benefit to a moving codebase. Their quotes, their 'argument from authority', is mostly about modularization. Their argument is that functional programming lends itself to modularization by limiting state space and focusing on composition.
I have read a lot of articles about learning functional programming to make you a better programmer with conventional OO or imperative languages - but this does not make sense to me.
The argument is "learn these concepts that are not available in other languages to make you better at those languages". Can anyone explain?
I think the most apparent example is that people recognize patterns like `fold` and `map` everywhere once they've seen functional programming.
This can be implemented in any language I guess. Most often you'll see explicit & imperative loops being refactored to shorter, descriptive code with anonymous functions, folds, filters and maps
You can take those concepts and use them in your designs in languages where they're missing, even if you don't use FP or logic languages where they're "native".
Broadly speaking, imperative programming allows one to start coding a solution before one understands the problem.
Functional programming is generally more abstract in its approach to modelling the problem. If you get the model wrong, you will not end up with a working solution, forcing you to rethink your model.
While imperative programming allows you to reiterate towards a solution as you start to understand the problem better as you work towards it, it's obviously better and faster if your initial model of the problem is more accurate.
Functional programming forces you to create a viable model of the problem before you start. If you can extend that discipline over to an imperative language, you will need less iteration and the resulting solution will likely be more elegant.
The argument is not (or shouldn't be) about concepts, but about paradigms and discipline.
Working with functional languages has made me value and seek out simplicity in my code. Before I write a loop or create another class I'll often ask myself if there is a more simple way to solve the problem - and oftentimes there is.
Many people doing OO have trouble structuring their classes, splitting functionalities and responsibilities properly.
OO kind of lets you do anything you want, allowing you to store data anywhere and having any kind of flow you want. It's very easy to do something that "just works", and while there is a lot of value in that, you can keep bad habits for very long.
FP is a lot more constraining, and will force you to adapt how you think to fit said constraints.
Having to think differently offers a different perspective on code architecture, that will eventually give you ideas applicable beyond FP languages.
Many would argue the exact opposite, that OO is contraining and FP is much more free, allowing you to change your design model without having to redesign the entire model.
A quick example that can be faked in any language is a pure function [1]. The functions only inputs are the set of arguments, and from those arguments returns a side-effect free result. A pure function is easy to test and easy to reason about.
Contrast a pure function with an impure function that uses an objects internal state plus the arguments passed in to further tweak the state an/or return a result. It is immediately obvious the second is much harder to test and reason about. It becomes even more challenging when the object is thrown into a large system with a lot of moving parts.
Even before I really started learning about true functional programming, I had been writing 'pure' functions for years because they just made sense. Even internal private methods are simpler as pure functions. Shared state is evil for many reasons and should be avoided if possible.
I wish someone would one day write a more objective article, such as "Why some aspects of functional programming are useful while some other aspects are an inconvenience to produce good code".
Because there are no valid objective qualities as to why functional programming is any "better" or "worse" than the alternatives. At the end of the day, you're instructing the machine to do the same work, regardless as to the structure of the code you're writing.
Functional vs. an alternative is nothing more than visually different styles that result in developers having a personal preference. Some languages offer optimizations for certain constructs, but even those depend on the implementation found in each language. A functional language doesn't automatically grant objectively better qualities, whereas a specific functional language might provide advantages that have everything to do with that specific language rather than the fact it happens to be functional.
Functional languages are interesting and the right tool for the job for many people. But they are not better, and when you have developers fighting hard to defend their language as "better", recognize that has a lot more to do with their ego than anything based on facts.
This misguided blogger thinks that object-based programming is necessarily about members and inheritance. It isn't. It's about message-passing and uniform interfaces and bundles of state and behavior. It's about ravioli code and modules and separation of concerns.
There are "Blub" languages which are such that if you don't use inheritance to connect two record types T1 and T2, either to a common supertype S, or to each other, then T1 and T2 are not substitutable. The users of these languages came up with the term "object based" for that situation in order to try to linguistically connect that to object-oriented programming somehow.
In real OOP, we don't have to use inheritance for objects of different types to be substitutable, so "object based" doesn't exist as a separate phenomenon. We use inheritance when two or more things are internally similar, such that they can share a chunk of implementation. If things are similar only externally (API level) but have totally different internals, then we don't use inheritance.
OOP is happening when we substitute objects of different types into the same code and they work, regardless of whether those objects are related to each other by inheritance.
"Object based" is when we cannot do that.
It's basically a new (or not so new any more) term for "abstract data type" which is used when the abstract data type language supports obj.function(arg) syntactic sugar.
If we take Wirth's Modula-2 or Pascal exactly as-is (two languages exemplifying abstract data typing support) and then add the "obj.function(arg)" sugar, they suddenly become "object based".
... Alan Key, who coined the term "Object Oriented Programing" identified the following his definition of "object oriented":
"OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme LateBinding of all things."
Alan Key though Java and C++ were abominations. However he may feel, THAT is the state of Object Oriented Programming today. Objects are instances of classes, which typically also determine their type. :/
There's an entire branch of the Smalltalk family with no classes, just prototypes, with Self, Python, JS, etc. and there's another branch without prototypes or classes, with E, Monte, etc.
You're not wrong that Erlang and Scheme are just as much about objects and message-passing as they are about actors.
Kay may or may not agree with me, but I like to require a facet he mentioned in another discussion once: The uniform calling interface. This is the property of objects that you may send any message to any object. If you require this, then Java and C++ disqualify themselves neatly.
> If a company hires software engineers, there’s a good chance that critical parts of their business exist in the form of computer code. Therefore the growth of that business is closely linked to the maintainability of that code. Businesses adapt and grow constantly, they perpetually change. New features and new offerings to customers are added every day. Existing features are revisited, strategies are revised, whole business models are pivoted.
There are advantages to functional programs, but I wouldn't say they're any easier to change than imperative programs. In fact, it's often more work to change a program where all functions depend purely on their arguments. Instead of adding a single imperative state update, you have to add a new argument to a whole group of functions and thread state through them appropriately.
(And besides, most functional programming languages apart from Haskell support mutable state (e.g. ML ref cells, Scheme set!) -- pure functions aren't fundamental to the functional paradigm.)
Refactoring Haskell code has been the best refactoring experience I've ever had, and I've worked with "a lot" of imperative languages. IMO the biggest boost in maintainability is by adding a (typed) compilation step - after that the stronger the type system, the better.
Functional programming is here already and even in OOP languages. What really matters though - is why we should be using languages like Clojure, Haskell, and Ocaml.
197 comments
[ 88.3 ms ] story [ 4734 ms ] threadIt's true that abstractions in functional languages can seem foreign and hard to understand, but generally they have some purpose, being grounded in mathematical practice. OO abstractions and patterns OTOH, taught essentially in "elementary school" which possibly makes them seem easier to understand, do a very poor job of solving more problems than they create.
Learning a functional language is often a transformative experience that lasts throughout a career, whether you even use functional languages or not. It might make you do something as simple as partitioning which functions have side effects and which don't, even if the type system doesn't enforce it. Or use a form of quick/fuzz testing, even if it's not the standard test suite. Or make parts of the data immutable for scalability, auditability, etc. Or...
There really are few things as satisfying as developing a large codebase in a functional language. A lot of the frustrating maintenance work just goes away. But even if you don't, functional principles can yield similar benefits in imperative languages.
What do you think of the recent rise of 'hybrid' languages like scala?
Personally, I found that diving directly into the language that represents a paradigm in the "pure" form (for FP I would recommend Haskell) works best for me. It makes it most obvious why things are done certain way.
While I haven't really written anything in Haskell since leaving school, learning Haskell has informed (and in my opinion improved) the way I program in every language more than basically anything else I've done.
Because they allow you to compose higher level entities?
(Incidentally, one would generally compose objects).
"When programming a component, the right computation model for the component is the least expressive model that results in a natural program." -- Concepts Techniques and Models of Computer Programming
So when a less expressive model (such as FP) is sufficient for a "natural" program, definitely use that. And of course that has been the general recommendation. Switch to a more expressive model once this is no longer the case. In my experience, FP tends to be good for "computation", at least if performance isn't a primary concern. However, most of what "computers" (badly named) do today isn't computation, and modeling communication and storage over time tend to get awkward (though obviously possible).
You can express object models in FP so what you are saying is very confusing to me.
Note that they are talking about general models of computation, in particular including at least:
- Declarative sequential model (strict functional programming, deterministic logic programming, dataflow/logic variables, higher-order procedures). Component behavior is independent of rest of program.
- Declarative concurrent model (explicit threads, by-need/lazy computation, data-driven concurrency, demand-driven concurrency). Almost as simple as declarative sequential. Declarative model with exceptions: allows nondeterminism to be visible.
- Message-passing concurrent model (declarative plus ports/communication channels). Allows nondeterminism, and allows nondeterminism to be restricted to particular components.
- Stateful model (declarative model extended with explicit state). Allows components to keep history. Typical of sequential OO programming.
- Shared-state concurrent model (declarative extended with both explicit state and threads). Typical of concurrent OO programming.
- Relational model (declarative extended with search). Search space explored by testing choices until result is satisfactory. Encompasses Prolog-style logic programming.
- Constraint programming and still other models are discussed elsewhere in the book.
http://wiki.c2.com/?PrincipleOfLeastPower
That isn't true. FP still uses data records, they're just not tightly coupled to the functionality like OO. Pure functions + immutable types is a more powerful programming paradigm than data and functionality encapsulation via classes and methods.
Also more advanced techniques like combinators can encode more complex and extensible patterns in a significantly more robust way than any OO class hierarchy (see 'parser combinators' for an example).
Lots of parser-combinator libraries in OO languages.
EDIT: Just to be clear, I don't think this is a good idea. It's usually better to pass in one or more data structures and one or more first class functions separately. I'm just saying that it's not too different.
This kind of sweeping unsupported assertion is actively harmful for FP evangelists. Anyone who isn't already a fanboy is most likely going to read that and say “clearly this person has no idea what they're talking about. [close tab]”.
If you want to make a productive form of this argument it'd be better to focus on discussing why the mathematical abstractions are so much better with comparisons to their actual recommended OOP counterparts. The points you mentioned about things like side effects or immutability are good but you need to not give someone a reason to go away before getting there, especially since there are going to be common tasks like I/O which are _not_ going to look like an improvement for anyone who isn't already on-board.
That seems as much an unsupported assertion (i.e. opinion) as what I wrote.
I don't think it's useful to try to write a comprehensive essay with no ambiguity every time I comment, and I don't have the time. Doesn't mean I don't believe the things I say. :)
If you decide to close the tab because I said functional programming languages are much better at abstraction, that's too bad, but it's not exactly an unsupported assertion--and I'm not trying to sell you anything anyway.
If it helps, most of my FOSS stuff is written in Go, a language Haskell fans generally vehemently dislike for "ignoring 30 years of PL research." I actually like Go for a similar reason I like FP: It does away with a lot of the bad abstraction (classes) and emphasizes the good (interfaces.)
FP is not that pervasive and anyone trying to make the case that it's better across the board has to address that familiarity gap. Try to think about, say, the average Java or C# developer working on a large project. They aren't spending their day saying “OOP is terrible” and when you say something is better because it's “grounded in mathematical practice” that's really non-obvious to someone who's thinking the main way their life would improve would be if they could get the business stakeholder to make a decision and stick with it for more than 24 hours, stop using Oracle products, etc. Talking about avoiding shared state and side-effects, going beyond Java-level typing to make refactoring safer, etc. is a lot more useful since those probably are things they spend time on regularly.
I was an imperative programmer for a decade before I looked at functional languages, and it was because of glowing but unfamiliar praise that I looked deeply in the first place. Now I know that a lot of that praise was warranted. Everyone's different!
Also, as I noted in another comment, the "elementary school" comment was not meant to imply that it's simple--alas, one of my main gripes with OOP is that it isn't simple in the ways it needs to be--just that it's something you're almost certainly exposed to early on, so it quickly becomes what's familiar.
Why only do one while you can do both?
Modern languages have first class functions and support class polymorphism and parametricity, which is still a very powerful way to describe problems intuitively.
Theoretically you can do both. Practically, few languages give you the tools you'd want to ensure functional purity.
C++ is a multi-paradigm language, for instance. But it doesn't have any concept of immutable data. The 'const' keyword exists but it only does a very shallow check for immutability (i.e., the pointer won't change but its data might). And even with a 'const', there are still huge backdoors (the 'mutable' keyword).
Point being, it's possible, but you'd be relying on convention in your design and care in your implementation to make it work.
In practice, Java's weaker `final` (immutable references) appears to be a reasonable middle ground.
What did I just read, you're joking right?
Disclaimer: The above is an opinion. Double-blind trials have not been performed!
What I meant was not that it's easy to do something, rather that it's something that often comes early, and is mandatory, in your journey of discovery. The concepts you learn early on, while not easy to fully grasp, stick, and make other paradigms seem alien.
For some kind of projects (video games, applied math, anything else that is sufficiently performance or latency sensitive), data structures are just as important as code. And they need to be composed, too.
For example, in C++ I can put small structures into couple megabyte-sized vectors, because memory controllers love sequential RAM access. Then I put these vectors in another vector, because address space might be fragmented and memory manager might not be able to give me continuous 1GB buffer, also to save CPU time + RAM bandwidth when growing my dataset to gigabytes. Then I wrap these vectors into another container that creates and maintains an index over the whole dataset using a hash map, because besides sequential access, other times I want to lookup my values by some key, and I want the lookups to run fast. And so on.
FP paradigm is just fine for composing functions. AFAIK, FP offers little for composing data structures. And those sophisticated specialized data structures are often the key for writing high-performance code.
While it's worth mentioning that Haskell does allow you to get pretty low level, it nonetheless has a GC, and the code you end up writing often looks more like C than FP. Rust is a great alternative that combines a lot of the raw performance and control over memory of C/C++ and good stuff from FP (e.g. sum types/pattern matching.) (Or even better, use something like Haskell and FFI with Rust for performance-critical parts.)
In C++ I can add hashmap-based index to existing collection of values without duplicating the values, because I can only keep pointers in the map. I can add linked list-based LRU tracking to existing collection of values. I can use pointers to implement graph-based structures. While there’re workarounds in Rust, such as reference counted pointers, raw pointers in C and C++ are just faster.
This is incorrect, Rust has raw pointers. Those reference-counted pointers that you mention are all just standard library types implemented using raw pointers under the hood.
Regardless of how you call them, you still can’t use them to compose data structures into higher-level structures in Rust.
In C++ with raw pointers, I can combine a hashmap with an existing collection of values to speed up lookups, without duplicating values. I can combine hash map with linked list to create an efficient LRU cache, with a few lines of my own code.
C++ can do that because collections, std::unordered_map, std::list and the rest of them, expose raw pointers at their API boundaries. It’s possible to store these pointers in other collections, encapsulating one or more simple data structures into a higher-level specialized data structure, with the performance characteristics suitable for the job.
However, look at the Rust implementation of the LRU cache: https://github.com/contain-rs/linked-hash-map/blob/master/sr...
See how much code is there (more than 1k lines), and note most code is unsafe.
In C++, one would probably use list<pair<K,V>> for storage, together with unordered_map<K, list<pair<K,V>>::iterator> for indexing. And the implementation would be trivial, because there’s no need to re-implement a linked list, you only need to implement these get/set methods that update both collections at the same time.
In Rust however, they had to come up with their own implementation of linked list. The LinkedList from standard library doesn’t expose raw node pointers in the API, therefore it can’t be used for the job.
I think rust safety model prevents rust containers from returning mutable pointers to the contained items. Especially pointers to item's implementation details, like nodes of that linked lists.
And without raw pointers to items, you can’t easily compose containers to make higher-level data structures from them.
(That is, many data structure _do_ do this, and you _can_ do it. It is an oversight.)
The difference is the mindset. FP makes it really easy to compose higher-level functions. But composing higher level functions typically means little control where the intermediate results are stored (which is what Game developers need).
You can absolutely write C++ style in Haskell by composing imperative functions (e.g. IO monad). The only problem I see is the syntax. There is no built-in syntax for indexing and assignment. Writing
instead of gets old really quickly.Exactly.
I need my code to access sequential RAM addresses as much as possible, because performance.
And sometimes my RAM layout is fixed, because I’m directly sending large sequential blocks of RAM to GPU (e.g. on Windows, by calling ID3D11Device::CreateBuffer or ID3D11DeviceContext::UpdateSubresource), and GPU can only consume C-array of POD types with very specific alignment and padding requirements.
This does not mean that there is anything wrong with FP or with lazy languages. They're just not the right tool for all purposes. When they're not the right tool, don't use them for that.
We weren't really taught classes in my high school course, so everything we did was entirely imperitive. I came across a problem where I had about 20 different entities in a game who all had a special way of updating during each tick, but I didn't want to have to write a switch statement for each one. I looked up "How to have an array of functions", and without knowing it at the time I was trying to implement first-class functions in this language which it just so happened to have.
From there it's easy to see how once you understand the concept of first class functions, many FP concepts start to fall in line, and by the way the language was set up it was difficult to use side-effects in this language, generally you use a function to output to the screen or to return a new resulting value. In fact when it finally came around to learning about classes, I had a very difficult time understanding how they worked or what purpose they served, made my Java classes in University difficult for some time.
I'm not sure what point I'm making here, I just thought how it was neat looking back that my first language I learned I naturally branched into more FP-oriented programming.
http://learnyouahaskell.com/chapters
[1]: https://en.wikipedia.org/wiki/Pure_function
> Real World OCaml is aimed at programmers who have some experience with conventional programming languages, but not specifically with statically typed functional programming. Depending on your background, many of the concepts we cover will be new, including traditional functional-programming techniques like higher-order functions and immutable data types, as well as aspects of OCaml's powerful type and module systems.
It's a nice segue into the world of functional programming if you're not ready to give up on imperativeness just yet.
http://chriswarbo.net/blog/2015-01-18-learning_functional_pr...
Eric Lippert's Monad Posts, starting at https://ericlippert.com/2013/02/21/monads-part-one/ - Uses C# to build up Monads using examples.
Slides: https://speakerdeck.com/swlaschin/domain-driven-design-with-...
Video of talk: https://vimeo.com/97507575
And then you go from there.
The last section there is important. In the real world, your language is not always your choice, but it's perfectly possible to put functional structure in most any language.
[1] - https://msdn.microsoft.com/en-us/library/hh314518.aspx
After all, if you try hard enough, you could code in a functional style in C.
http://elixir-lang.org/learning.html
http://learnyousomeerlang.com
The nice thing that either language will help introduce functional ideals. I recommend Erlang since its so unique.
[0] https://app.pluralsight.com/library/courses/csharp-applying-...
For me at least, this site made programming fun again! It's colorfully written and mostly easy to follow, though some of the concepts are a bit mind blowing if you are only familiar with OOP like I was (passing a collection of functions to map really made me stop and think). Oh and it's a pretty neat way to learn emacs if you haven't already.
[1]: https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.p...
"However, there is a very important point that is often missed. When writing a modular program to solve a problem, one first divides the problem into subproblems, then solves the subproblems, and finally combines the solutions. The ways in which one can divide up the original problem depend directly on the ways in which one can glue solutions together. Therefore, to increase one’s ability to modularize a problem conceptually, one must provide new kinds of glue in the programming language."
We need more kinds of glue. He argues that FP provides one (function composition, a Good Thing™) and lazy FP another (lazy eval, a bit more controversial).
But that's not a whole lot, is it?
There are also high order types polymorphism, that normally comes with FP but it not inherently linked to it.
But yes, overall, it's been fairly abysmal. Which is why I personally think we need to really, really focus on flexible glue: http://objective.st :-)
Also, if looking for glue, check out Wikipedia's list of programming paradigms or types of programming languages. Quite a few including some styles you may have not heard of.
Yep, have the book. In fact, my own OO/dataflow stuff[1] (also a good 20 years old now) is similar in some ways, and I am trying to merge ideas from Morrison as much as I can.
Have also started trying it out in GUI settings[2]
[1] https://github.com/mpw/MPWFoundation/tree/master/Streams.sub...
[2] https://github.com/mpw/FlowChat
Now that you talked about constraints, there's constrained search that never got mainstream but is also great. This one does not mix well with other glues. Now I'm wondering what kind of polymorphism could make FP/imperative mix well with it.
Combinators, type-classes, ad-hoc polymorphism, monads, applicatives, FRP, ...
And FRP is, of course, just dataflow made more complicated by trying to squeeze it into an FP framework.
Hardly. The GoF patterns are pretty much all poor attempts at functional patterns, with disturbingly long-winded implementations. They are there because of missing features in OO languages (mostly first class functions). The GoF also label good programming practices as bad (anaemic domain model for example). They are a scourge on the world of programming.
My point was that there are language features for composition outside of functions (type-classes, ad-hoc polymorphism); as well as very sound composition approaches in code (monads, applicatives, FRP ... which actually still use functions btw). The code approaches are based on sound and provable maths, the GoF patterns are a joke, as is inheritance based composition, or pretty much any approach to composition in OO-land, because the 'glue' you talk of should be at a lower level (the function level), not at a class level or higher, where the shapes of the things you're composing don't match in any meaningful mathematical sense. Even the higher level glue in Haskell (type-classes) and Scala (ad-hoc polymorphism) is all about set theory and matching of shapes.
I'm saying this as a reformed OO dev; after spending 20 years believing the GoF (and OO world) dogma I finally changed my thinking about 7 years ago after a super large project I still work on became cognitively too difficult for the team to manage (the scale of the code-base combined with the extreme abstraction of components and hidden mutable state meaning it's very difficult - unless the coder wrote the feature - to know what mutation would go on behind the scenes; this is one of the big failures of hidden mutable state with packaged functionality that hides the mutation).
Inheritance is a myth, interface based abstraction is a myth, code reuse is a myth, OO composition is a myth. You may achieve this stuff once in a while, but if you 'abstract' a service behind an interface, 9 times out of 10 that service's own interface is imprinted in the abstract interface. And when you do decide to replace it later, unless it's trivial, then there is nearly always a change to the interface. If the thing behind the interface mutated state, then whether you like it or not, the code that uses it makes assumptions - which increases coupling. Abstraction is used liberally, even when you're only abstracting one type of thing. "Ah, I have a MyService class, let's abstract it behind an IMyService". "But there's only one of them?", "No matter, Martin Fowler said I should".
When you see whole DI frameworks and tooling, and mocking frameworks, you must realise that something is wrong? Why use DI when you can just use first class functions? Or a Reader monad? There are a lot of people in the OO world with opinions on the perfect architecture for applications, but none of them have any study backing them - but the dogma flows and flows, it's like, once somebody reads the GoF book they think they have all the answers. Yeah let's use the Visitor pattern to get over the fact we don't have algebraic data types. Let's use the Command pattern because we don't have first class functions, etc.
I prefer to rely on the proven technology: mathematics. It works, and writing 'expression oriented' code with immutable values just makes sense. It makes sense for the brain, it makes sense when you don't want code rot, it makes sense in parallel programming, it makes sense when you want programmers to know what the hell is going on.
Bringing in functional practices, and going away from the whole OO 'belief system' was enlightening, and I'll never go back. Neither will anybody on my team. I realise you've nailed your colours to the mast, and it's clear from this thread that you're living the OO dogma dream, and none of this will make any difference to you. But your blanket dismissal of anything from the func...
This isn't the best analogy as functional and imperative languages are both often used in a procedural fashion. If I simply replaced "global state" with "immutable arguments", this analogy fits functional programming as well. The fact that the arguments would be copied, however, would be implied.
> Each step needs to change, rotate, massage the workpiece precisely one specific way, so that it is prepared for subsequent steps downstream. Every step downstream depend on every previous step, and their order is therefore fixed and rigid.
This is more about tight coupling than imperative vs. functional paradigms. In general, imperative methods can be just as loosely coupled as functional methods. It basically comes down to what sort of data you're handling.
> Because of these dependencies, an individual computational step has not much use and meaning in itself, but only in the context of all the others, and to understand it, one must understand how the whole line works.
This, again, can be true of functional languages as well. You cannot always guarantee that a method is individually useful given the data at hand.
If you need to compare functional programming against something contrast it against OOP, which is a different architectural approach.
nothing!?
>The "functional" part determines the architecture by which the code is structured opposed to the style (vanity) by which the structure comes together.
No idea what this means.
> The "functional" part determines the architecture by which the code is structured opposed to the style (vanity) by which the structure comes together.
I think it means a code can be functional but looks imperative. One example is the for-comprehension in Scala:
This is just a contrived example for working with `Future[T]`, but it can be applied to other monadic types.For an example library that can be used with a few different styles, have a look at this: http://jsuereth.com/scala-arm/usage.html
Exactly.
The most common ELI5 definition of functional programming I get from other developers is that you're piping multiple statements together into a single chain of processing [input(s) > multiple levels of processing > output(s)], without having to explicitly declare variables to hold the temporary inputs and outputs between each sub-statement within the chain. I know just enough to understand that this isn't the "proper definition", but that workflow is true enough that it's what many people associate functional programming with.
The problem with that particular definition is that it tries to make the primary benefit of functional languages seem to be this piping/chaining mechanism. Yet these languages are still written procedurally, executing multiple such pipes in sequence. You still have variables holding the inputs and outputs of each chain, so you can pass them to other unrelated chains. It reduces the overall number of statements and the manual variable/memory management required, but each statement is simply a compressed version of multiple statements merged into one, enforcing "fake immutable" variables for the inputs/outputs within the chain. You don't really have "immutability"; you simply have automatic variable management between sub-statements in a chain.
Now, show me a functional language where the entire program is written as a single piped chain, and I would classify that as its own genre. Literally, the entire program would have to be written top-down as a single block of code that chains every single required input from the top-level, all the way down to a single output, without using a single explicitly declared variable. Only the first line of code would be unindented at the first column, with all other lines having to be indented as part of that primary block. Now that would satisfy me as being "unique" or "different than procedural".
What is the primary metric of a functional language? Is it to write write golf code[1] that folds 10 "procedural statements" into a single 3-line "functional block"? To me that's not "functional programming"; that's just writing less code by chaining multiple operations into smaller blocks, reducing the complexity of having to explicitly declare more global or widely scoped variables.
Random thought association: is perl's well-known Schwartzian transform (@sorted = map { ... } sort { ... } map { ... } @unsorted), applied as a concept to an entire language, what makes a "functional language"? To me, that doesn't seem like enough of a scope change to warrant a different language "type".
[1] https://en.wikipedia.org/wiki/Code_golf
https://gist.github.com/MarkusPfundstein/246446e428ab10dbd23...
Forgetting my expectations, the code example you linked is practically the antithesis for ES2015/ES6. You've abused the concept of "const". Your example is terrible, using "const" to define things that should have been defined as separate classes, without having to define so many global "const"s.
Even more critically... wtf are you doing with all those "const" definitions? That code is ultimately worse than what I saw in javascript in 1995. Please don't write code that way. :/
To go to the extreme, my ultimate reaction is that the code you linked is straight up unacceptable. You would fail an interview at my company with that code. It screams "I know ES6", while being the worst example of javascript I've ever seen, regardless of the Ecmascript version. You're overcompensating, trying way too hard to prove that you understand the latest spec. There are limits to what "modern javascript" means, and you have gone too far. A dozen global "const" declaration means you know ES6, but don't know how to write proper code.
tldr; Dial back a bit. Upgrading to ES2015/ES6 does not mean transforming all your code to be completely unreadable unless you know the latest spec. Your code should still look like javascript rather than 100% some-new-functional-language.
If you attempt to compose functions out of smaller functions, then you need variables to hold on to those small functions. What's wrong with that? And why would you need "separate classes" for those smaller functions? What problem would "smaller classes" solve?
The crucial thing to understand is, that those consts are just assignments for global modules that I use. They are NOT variables. But if you want to go to the full extreme and remove every single const: EASY! Just add all the modules to the environment of the most external Reader monad and inject them into the function chain. This would get rid of 99% of global consts that are not functions. I leave that as an exercise to you.
The rest of the consts are just function assignments. Instead of const f = x => ... I could also write function f(x) { } .. but honestly, I prefer the former. It is more elegant in my opinion ... So in order to get rid of them, just rewrite it. This is trivial.
Finally, you would want to get rid of the two local consts within the two functions putPublicationToElastic and createUploadDocument: Straightforward, they are just there for cosmetic. Again, they are NOT variables, they are just names to make some following lines a bit shorter. Again, exercise to you to remove them.
So if we do all the three steps above, the only const we would have left would be the config variable. The rest is one big function, composed in order to achieve a goal. Mind that calling the function will not produce any output (You'd have to fork it), so the function is even 100% pure...
Honest question to you: Why would I need a class here? I really don't see anything in that code that would profit from being put into a class. It's just a bunch of functions composed together and wrapped into a Reader monad. I can rename runApp to uploadSQLDocumentsToElastic and export it and have a perfectly fine, encapsulated logic. I don't think you could do better with a class. But if, please show me. I'm eager to learn!
P.S. Please tell me the name of your company. Another one I would NEVER ever want to work for ;-)
P.P.S. Sometimes people write code as an intellectual exercise. In order to try out some new paradigm, or coding style. I'd advise you to consider that next time before attacking their efforts.
This is known as point-free style. I think point-free style implies functional programming (at least locally; i.e., a point-free function will by definition be functional, although it can call imperative functions) but functional certainly does not imply point-free.
That said, Scheme is probably a good example. Lisps in general are a funny case for functional programming: historically they were described as "functional" but the word had a different meaning we would now call "procedural"; I think Lisp may have predated Algol so the concept of having functions at all was fairly notable. However, Lisps generally support functional programming and Scheme has embraced it more fully than the others. Note, for example, that Scheme doesn't actually have loops as a fundamental concept in the language; it emulates them with obligatory TCO and convenience macros.
Google primarily uses C++/Java. Facebook: Hack. Twitter tried Scala and as far as I know, abandon it and went to Java. LinkedIn definitely tried Scala, failed, and went to Java. Square is Ruby/Java.
I'd like to have something to point to as a success story of a company at scale with functional programming. Anyone know of one?
From the article "in this case for massive distributed systems Functional Languages are the right tool ...
Immutability at scale is really important because it allows you to go from 30k members to a staggering 2.5 Million+ and not even feel blip within 3 months, like we did here at Jet from the end of July to October. That’s powerful!"
Erlang was developed for Ericsson phone switches with a large proportion of uptime.
Whatsapp also use Erlang.
[1] http://harmful.cat-v.org/software/OO_programming/why_oo_suck...
Then, my thesis supervisor said "But you're wrong, Erlang is extremely object oriented". He said object oriented languages aren't object oriented. I might think, though I'm not quite sure if I believe this or not, but Erlang might be the only object oriented language because the 3 tenets of object oriented programming are that it's based on message passing, that you have isolation between objects and have polymorphism.
..."
Read the rest. It's good.
https://www.infoq.com/interviews/johnson-armstrong-oop/
I've heard of inheritance as a corrupting influence which has taken over and corrupted OO for years/ Funny enough, even most OO folks eventually realized that and moved to banish inheritance as a viable pattern.
For example: I've been developing for the last 3 years for the iOS and we been using FP and FRP almost everywhere with different teams and companies. Compared to the standard OO or Apple -way of doing things we have been able to make much better tests, stability/maintainability of the apps has increased etc.
I'm not sure if I can call this "the Haskell community consensus", but a lot of the Haskell community finds Scala too complex to be worthwhile. They find it introduces a lot of complexity above and beyond Haskell, but at the same time, fails to take proper advantage of it and the result is quite dirty, full of special cases, and consequently hard to reason about. So you get a lot of the costs, perhaps even more costs for compliance than a Haskell code base, but you get fewer benefits.
That's really the main issue per the original question. It's not that functional somehow fails on its merits to deliver, it's just that "at scale" means having enough developers who know it. The reality is that imperative/OO languages have the greatest mindshare, and thus it's far easier to find developers, and far less wind-up time, if you're using such a language.
Designed to replace and address flaws of an older language but ends up being huge and unmaintainable, with very questionable design decisions and a tool chain that's simply not up to standards in the 21st century (slow compiler, poor IDE integration that keeps breaking version after version, etc...).
In C++, some of these design decisions were driven by legacy pressure but in Scala, a lot of design decisions were driven by the pressure on the team to write research papers. Either way, both languages end up being monsters that implement all known programming language features known on Earth.
Your C++ to C analogy doesn't hold, because C++ is an (almost) superset of C, while Scala is not a superset of Java at all. Modern C++ compiler can compile most of C code with at most minor, cosmetic changes.
As for the toolchain - I'm working in it daily and so far it has been great. Ok, compiler is not as fast as Java (point taken), but this doesn't matter as long as I can compile my code fast enough. IDE support is stellar compared to most other popular languages, particularly dynamic ones like Python or PHP.
Odersky himself gave up on scalac and he's writing a compiler and a new language from scratch.
* C++ language specification: 1374 pages (and still includes plenty of "unspecified behavior" / "undefined behavior")
* Java language specification: 788 pages
* Scala language specification: 191 pages
> Odersky himself gave up on scalac and he's writing a compiler and a new language from scratch.
Odersky created a new language to be able to do research without sacrificing Scala stability, which is already mainstream and should not undergo any more major revolutions. So Dotty is for research / incubating language features, while Scala stays on the stable side of things, letting companies like Twitter or LinkedIn develop without fear that 2.13 will not compile their 2.12 code.
> also poorly designed overall
This is an opinion, not a fact.
> With so many features that they interact with each other in ways that are pretty much unpredictable.
Name three. I'm coding in it for several years, and didn't notice a single one issue. I heard this complaint about Scala being too hard a few times very long time ago (when Scala was at version 2.6, and its tooling was in fact terrible), but it was always from programmers, who had also major problems coding in Java, so I never treated this seriously.
Java has had lambdas and streams for awhile now. A pretty common design pattern has also become anemic domain models operated on by groups of functions, which fits in the spirit of functional programming. Modern java can, and is used in a functional style.
On the JS side, functional concepts are everywhere. Given how heavily FB and Twitter are invested in JS, I don't think they have abandoned functional programming at all.
Finally, IMO Scala is actually a pretty poor example of a language that can be used at scale. Without a highly enforced set of rules it can quickly become a write once/read never language. I'm sure there are exceptions, but given the choice between scala and java 8+, I would go with java. Clojure may be an option though.
Pojo's which are just data structures or a glorified HashMaps for holding data. And, if allowed, using Lombok to get rid of all the getter/setter cruft.
The second category of class types are just Service classes. These classes hold no state and are a logical grouping of methods that typically operate on a given data type. However, the class is based more on a specific role it performs than the type(s) it operates on. Also, there's considerable thought given to reuse of the Service classes outside the given context at hand.
The reason for this pattern is because companies look for easily replaceable developers.
To get into functional you need to be good at abstracting the business domain, this requires seniority which is hard to find. Most of the time, when you are working using functional programming you are implementing the business vocabulary. Entry level developers are not good/interested in this. Their worries are in how they can use Angular 2 in this project, or why we need to still use SQL Server instead of converting to {insert the newest database technology}.
It is easy to find (and replace) junior developers that are happy because they created something with the latest technology and it provides the immediate value intended. It sounds good, but it misses the point.
Software development in a company happens to support/enhance the business. This means that it has to stand the test of time, not only in reliability but also in adaptability. The only constant in software is that it will change. Here is where building a vocabulary that represents the business subjects pays off. Change now is a definition-change and, unless the business is pivoting, definitions rarely change; instead, they have constant adjustments. Functional shines in creating a vocabulary and having this adaptability.
Of course, you can adapt using OOP, but the question is not if adaptability is possible, it is instead how to make changes at the lowest risk.
Which is definitely part of the "company at scale" equation the GP referred to.
>Here is where building a vocabulary that represents the business subjects pays off. Change now is a definition-change and, unless the business is pivoting, definitions rarely change; instead, they have constant adjustments. Functional shines in creating a vocabulary and having this adaptability.
I tend to use the same arguments to make the case against FP for business modelling.
I tend to say that FP is good at adding new operations to existing things, while OOP is good at adding new things to existing operations. However when Software Development is used to model a business - as it should be for reasons you accurately explained - the reality it meets is the one of the business world in which business needs evolve and requirements get added. You start by supporting local groceries and then you grow to support global supermarket chains. OOP is more suited to model business because you can naturally extend existing types and apply existing operations to them (ie. pass a supermarket everywhere a shop was expected + things such as polymorphism). In FP, every time you add a type, you need to add switch cases to your existing operations (at best), or redefine them create / new ones (at worse), since the ubiquitous assumption of FP development is immutability and known types.
I'd be curious to know how you approach this conflict in a way that makes FP work in real world business modelling which needs to be extension-oriented. It seems to me that the more operations using a type you have, the more you will be screwed when you want to extend this type. The only reason I can see this wouldn't be the case would be to say that I approach FP with the wrong philosophy and that there is no such things as extending types in FP. But in this case I'd question if FP modelling really is the best tool to model real world business for which it is natural to define things as extensions of other things.
What you described is exactly the _expression problem_. And it has some solution.
See https://oleksandrmanzyuk.wordpress.com/2014/06/18/from-objec...
The functional and strongly typed value proposition of FP is very appealing on paper but only shines when you have a level of certainty and knowledge on requirements that you typically do not have in real world software development. OOP by design embraces this uncertainty (but as a trade off is less assertive on correctness than FP).
That being said, certain businesses do not have a high level of uncertainty in their developments while correctness is a big deal for them (banks, scientific researchers, etc...). It makes sense for them to reinvest this slack in correctness. However, for those iterating consumer facing products (which represents the majority of developments), OOP modelling usually is the way to go. Because of the expression problem (which should probably be called the expression dilemma to better highlight the fact that the assessment should be continuous and situational rather than ideological and/or philosophical)
"OOP is more suited to model business because you can naturally extend existing types and apply existing operations to them (ie. pass a supermarket everywhere a shop was expected + things such as polymorphism)"
The reason why you feel is more suited is because you are thinking in an object oriented way. It is not a bad thing, but it is not functional.
"... extend existing types and apply existing operations to them". This means you have things, and you do things to them. This is the OOP way, not the FP way.
In FP the things are immutable, so you don't do things to them because they cannot change; instead, you create new things out of what you have.
In OOP this is what you have, this is what it can do, and you put all the gears (or objects) together and you get your engine.
In FP you have pipes, this is what I have and if I put it through this pipe it becomes something else.
When a local shop there is a sale, there is a function that takes a bunch of arguments and produces something called a sale, Maybe is the total, maybe is a tuple with the different pieces of the sale.
When you move that to a supermarket, then the question is: how what the shop owner calls a sale in the local shop is different from what the supermarket owner calls a sale? How my vocabulary changed? for a lot of things, you will see that the meaning is the same, just over more data; and also, there are new words that didn't exist in the smaller context. A sale is in both cases the sum of the quantity multiplied by the price of the groceries, apply the tax, spit out the result. But maybe the meaning of Tax changed, instead of been a fixed percent, it needs to be the lookup in a table depending on where the supermarket is.
If you need to constantly add switch cases, then probably you are using a functional language using an OOP mentality.
The way that I have introducing FP to people is using Excel. Think on this syntax:
A1: 1 B1: 2 C1: A1 + B2
You don't need new cells, C1 does not mean the same thing and the formula have to change... the formula or is it the function?
When you model the real world, you can focus on the objects, map them to types, and go from there. Or you can focus on the meaning of the words, then you need just a few types, see how those meanings compound, and go from there.
"But in this case I'd question if FP modelling really is the best tool to model real world business for which it is natural to define things as extensions of other things."
I agree, FP is bad at extending things... but it is not FP fault that you see the world as things that need to be extended.
A middle step between what you are saying and FP will be Flow Programming (https://en.wikipedia.org/wiki/Flow-based_programming). It is not FP, nor OOP, but somewhere in between.
>Or you can focus on the meaning of the words, then you need just a few types, see how those meanings compound, and go from there.
>I agree, FP is bad at extending things... but it is not FP fault that you see the world as things that need to be extended.
I should probably give another look to FP and continue to study the subject, I have likely been approaching it with a OOP mindset as you suggest. One last question though, what about code duplication ? If you focus on the meaning of words and compounding these meanings to create new things, wouldn't it most of the time create lot of duplicate code ? For example in the case of the local shop and the supermarket, wouldn't you have two functions (or a switch case) containing exactly the same code to calculate the quantity multiplied by the price of the groceries ? One would take a local shop as parameter, and the other one would take a supermarket.
Splitting the sale processing function in two parts - one summing up the groceries and the other one calculating the taxes - so that you can reuse the first function implies knowing in advance the existence of the supermarket structure (which you will only know many years after putting your product in production). Not doing it in advance either means duplicate code or refactoring every time you add an operation. The extension mindset initially comes from the need to avoid code duplication which is known to make maintenance difficult.
Now maybe the strongly-typed experience of FP and its compile-time checks are so convenient in practice that they make the maintenance of this kind of code easily manageable ? Maybe it's not even really duplicate code since what would be a basic number in OOP would be two different types here in FP ? Or maybe it's still thinking about FP from an OOP perspective ?
What goes through the sale function pipe is not the store and its size, it really does not matter for the meaning of sale were the sale happened. What matter for the sale is the cart. The cart might be more or less sofisticated because the size of the store, but is still a cart.
So the sale function is a pipe that eats a cart and spits out a receipt.
Or if you want to put it in another way, a sale is something that might happen to a cart over time. Functions are the clock on the system. In a functional system, times does not pass until a function is executed (does it sounds like lazy evaluation?)
In functional programming, we avoid duplication of code by appliying functions to the data so it spits what the next function needs. If you have a function sale that can eat a simple cart, but now you have a complex cart, one solution is to create a function that converts the complex cart into the simple one that the sale function needs; another way is to make the complex cart having the same data as the simpler cart. What you choose to do is proportional to how different the meaning of cart is, or maybe the cart remains the same. In general terms, this type of thinking tend to produce less lines of code needed per similar acomplishment.
So in OOP your are using objects to put together the store, while in FP your are descriving what happens in the store by connecting pipes betweem the different data. It is not about what can happen to the data, but what makes the data travel. It is not about what steps makes it work, but the fluidity of the data life span.
In particular your demonstration was very convincing from a DDD perspective. I can see that FP is not less natural than OOP for domain modelling while it approaches things from a very different angle. However FP brings to the table rich domain semantics, high correctness guarantees, and I feel productivity gains too. And with the mindset you've presented, it is also clear that the unknown seems to be accounted for in FP too. As an architect, this last point was the grey area and the deal breaker for me. However now I see no reason not to invest in heavily leveraging FP moving forward. Thanks again jorgeleo.
This is incorrect. One of the former VPs said he would not use Scala. Twitter uses Scala massively and has published and continues to maintain several open source Scala projects.
> LinkedIn definitely tried Scala, failed, and went to Java
This is incorrect. A newly hired VP insisted on moving the front end from Scala to Java. In the offline backend stack Scala is used extensively. Check Kafka, Samza from LinkedIn or better yet ask current LinkedIn employees.
Apart from these Spotify, Foursquare, ebay, several banks use Scala. FP is huge in financial institutions, check K/KDB+. Jane Street etc. Thats where most FP programmers work. Also verizon, jet.com and walmart.com. There are several dozen large companies using FP.
FP is mainstream now. Traditionally, it was financial institutions using some flavor of ML/Haskell. With Scala/Clojure on the JVM, Si Valley has moved into FP in a big way.
JavaScript, for example, is ubiquitous in the industry, and, especially with the advent of ES6, can be written quite functionally. ReactJS is also widespread and can also enjoy an FP approach.
https://static.googleusercontent.com/media/research.google.c...
Imperative/object oriented languages are often more practical for real-world use (MapReduce itself I believe is written in C++), however it's the ideas of functional programming that matter most. Those with experience working in functional languages are at an advantage over developers who've never had that exposure, because they have a wider range of mental tools at hand with which to solve problems.
This is a good video, from Jane Street, on why they use OCaml:
https://www.youtube.com/watch?v=kZ1P8cHN3pY&t=109s
Another approach is to run experiments but they are universally terrible. Their methods have so little relation to the way real software is developed, that it is hard to take any conclusions seriously.
I would also like some hard data, but don't hold your breath. Technology decisions will probably need to made based on other factors for the foreseeable future.
There was a recent post here on HN about empirical language design and I thought that was a refreshing change. I'd like to see a change in software culture towards an evidence based approach. It's long overdue. Alan Kay called the software world "pop culture" and I think he is right. Software is more fashion driven than Vogue magazine.
Academic research could be a vehicle for a more empirical approach. Research in the hard sciences embraces empiricism. Sadly, the academic research in software doesn't, generally, adhere to the same level of rigor.
I personally find it much easier to navigate and fix bugs in an Erlang code base than in the equivalent C++/Java/C# one. It mainly boils down to how state is updated. When I see NewState = update(Value, State) it is clear what is happening. In OO code, I usually need to remember what object inherits from, what are is the instance state so far (what other members have been called) and how it got there. I find that much harder to handle, for example.
Ruby is OOP. Elixir/Erlang is purely functional (although dynamically-typed... some will prefer typed... but the results speak for themselves).
If you are a long-time developer like me and are just coming across this, this news should strike you somewhere between "astonishing" and "pure fucking magic."
Here's the deal- Paradigm shifts, most people only see them AFTER they've finished. If you want to be ahead of the curve on this one and you want to reap the benefits, go functional (Haskell, Clojure, OCaml, F#, Elm, Erlang/Elixir). Today. That is my #1 piece of advice right now. (Well, that, and to avoid Scala and Go. Scala is just too overly complicated to keep your cognitive load down as a developer, and Go... Well, the name even says it: "Go!" As in, "don't stay!" ;) Go will suffer the same long term problems that all OOP/procedural langs share, compounded by its idiotic take on error handling /opinion)
Elixir: http://elixir-lang.org/
Phoenix: http://www.phoenixframework.org/
There are a lot of interesting aspects of functional programming, but there's no particular miracle here: Ruby, particular Ruby on Rails, is slow.
[1] https://www.techempower.com/benchmarks/#section=data-r13&hw=...
[2] https://www.iron.io/how-we-went-from-30-servers-to-2-go/
Also demonware [2], which is owned by Acitivision/Blizzard and manages online game lobbies for all their titles (ie Call of Duty series across all platforms), uses Erlang. They switched from C++ to Erlang before Call of Duty Black Ops was released. They said if they hadn't decided to switch before the release the company would have never been able to handle the 5 months of user growth the game brought to their platform [3].
[1] https://github.com/janestreet/core [2] https://www.demonware.net/ [3] https://news.ycombinator.com/item?id=14120506
Have you noticed that these articles almost never do?
they have argument from authority and anectdote. Language research is still in the phase of bad humors and blood letting.
Love this. Practically all the claims I've seen are just small code samples accompanied by the author's vague endorsement.
In category theory we might have different categories. Some might instruct the compiler and programmers that the function obeys certain rules when applying. It could be trivial to parallel or perhaps it specifies a strict sequencing for computation. Following Haskell research, you can really see the evolution as people find more useful generalizations (which in the end, has made things simpler!)
It's not like you cannot write short functions in other languages - you can - but it's often too easy not to do it.
It would be nice to have some empirical evidence for this, unfortunately I am not aware of any.
Without rigorous evidence we're left to argue from theoretical models / principles and anecdotal data. This is still useful. It would certainly be more useful to have rigorous empirical results to back up the claims and validate the models but we, as practitioners, have to make decisions on language choice now using the available resources.
The kind of empirical evidence you are asking for is extremely expensive to provide. Even if you conduct a massive controlled trial, experiment will have several biases which will invalidate any conclusion. As an exercise try looking for scientific evidence that programming in Java is more efficient than programming in assembly. No scientific evidence for this exists. Yet most of us would never choose to write a web service in assembly! The only evidence that can be provided are discussions and benefits of particular features and anecdotes.
Do you think programming productivity is possible to measure and if so how?
> Do you think programming productivity is possible to measure and if so how?
For the purpose of discussion, I would propose that a team of developers are given a simple task with highly specific and explicit functionality requirements. This team of developers should Ideally have no experience with any of the technologies used. Experience with the problem domain is acceptable. These developers would then be tasked with building out the solution with various different technologies (languages, frameworks, libraries). We then compare the time it took for the developers to complete the task relative to the amount of bugs present in the solution. For example, the team could be tasked to build a gui calendar with Haskell and then Python.
The issues with the above proposed experiment are as follows:
* We would need to find some way to adjust for problem domain familiarity. The developers are going to get better, and thus more productive, at the task after they have completed it the first time.
* We need some sort of concrete numerical measure of "bug likelyness" for lack of a better term. All software has bugs, but some are very hard to find or appear only during runtime under very specific conditions.
* We need to decide whether or not we take the language ecosystem into account. In the calendar example I provided above, Python would obviously be more productive because there are a ton of different packages available that make creating a GUI extremely trivial.
* Do we take into account time spent on learning the language/tool/package/framework/library? Do we measure the amount of time that it takes the team to feel comfortable working with a new technology?
All in all, it's an interesting thought experiment and I'm interested to hear what you think.
https://sites.google.com/site/stefanhanenberg/ https://link.springer.com/article/10.1007%2Fs10664-013-9289-...
The above papers are not about FP but about static type systems (there tends to be lots of crossover), but I think you'll find that what it really comes down to is guarantees provided by a language. I would be surprised if similar research that focused solely on purity did not exist.
This is an incredibly difficult area to study. "Better software" is a difficult metric, and even a more meaningful metric is incredibly hard to measure. For a field as young as CS it's no wonder that the research into this is still immature, so we largely have to rely on anecdotal evidence and common sense.
So yeah we have some research and we have some basic common sense and we have people demonstrating through their projects that it has worked well for them.
More to the authors point - what they are really talking about here is modularization being a benefit to a moving codebase. Their quotes, their 'argument from authority', is mostly about modularization. Their argument is that functional programming lends itself to modularization by limiting state space and focusing on composition.
The argument is "learn these concepts that are not available in other languages to make you better at those languages". Can anyone explain?
This can be implemented in any language I guess. Most often you'll see explicit & imperative loops being refactored to shorter, descriptive code with anonymous functions, folds, filters and maps
Functional programming is generally more abstract in its approach to modelling the problem. If you get the model wrong, you will not end up with a working solution, forcing you to rethink your model.
While imperative programming allows you to reiterate towards a solution as you start to understand the problem better as you work towards it, it's obviously better and faster if your initial model of the problem is more accurate.
Functional programming forces you to create a viable model of the problem before you start. If you can extend that discipline over to an imperative language, you will need less iteration and the resulting solution will likely be more elegant.
The argument is not (or shouldn't be) about concepts, but about paradigms and discipline.
OO kind of lets you do anything you want, allowing you to store data anywhere and having any kind of flow you want. It's very easy to do something that "just works", and while there is a lot of value in that, you can keep bad habits for very long.
FP is a lot more constraining, and will force you to adapt how you think to fit said constraints.
Having to think differently offers a different perspective on code architecture, that will eventually give you ideas applicable beyond FP languages.
A quick example that can be faked in any language is a pure function [1]. The functions only inputs are the set of arguments, and from those arguments returns a side-effect free result. A pure function is easy to test and easy to reason about.
Contrast a pure function with an impure function that uses an objects internal state plus the arguments passed in to further tweak the state an/or return a result. It is immediately obvious the second is much harder to test and reason about. It becomes even more challenging when the object is thrown into a large system with a lot of moving parts.
Even before I really started learning about true functional programming, I had been writing 'pure' functions for years because they just made sense. Even internal private methods are simpler as pure functions. Shared state is evil for many reasons and should be avoided if possible.
[1] https://en.wikipedia.org/wiki/Pure_function
Functional vs. an alternative is nothing more than visually different styles that result in developers having a personal preference. Some languages offer optimizations for certain constructs, but even those depend on the implementation found in each language. A functional language doesn't automatically grant objectively better qualities, whereas a specific functional language might provide advantages that have everything to do with that specific language rather than the fact it happens to be functional.
Functional languages are interesting and the right tool for the job for many people. But they are not better, and when you have developers fighting hard to defend their language as "better", recognize that has a lot more to do with their ego than anything based on facts.
In real OOP, we don't have to use inheritance for objects of different types to be substitutable, so "object based" doesn't exist as a separate phenomenon. We use inheritance when two or more things are internally similar, such that they can share a chunk of implementation. If things are similar only externally (API level) but have totally different internals, then we don't use inheritance.
OOP is happening when we substitute objects of different types into the same code and they work, regardless of whether those objects are related to each other by inheritance.
"Object based" is when we cannot do that.
It's basically a new (or not so new any more) term for "abstract data type" which is used when the abstract data type language supports obj.function(arg) syntactic sugar.
If we take Wirth's Modula-2 or Pascal exactly as-is (two languages exemplifying abstract data typing support) and then add the "obj.function(arg)" sugar, they suddenly become "object based".
... Alan Key, who coined the term "Object Oriented Programing" identified the following his definition of "object oriented":
"OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme LateBinding of all things."
Alan Key though Java and C++ were abominations. However he may feel, THAT is the state of Object Oriented Programming today. Objects are instances of classes, which typically also determine their type. :/
You're not wrong that Erlang and Scheme are just as much about objects and message-passing as they are about actors.
Kay may or may not agree with me, but I like to require a facet he mentioned in another discussion once: The uniform calling interface. This is the property of objects that you may send any message to any object. If you require this, then Java and C++ disqualify themselves neatly.
https://www.infoq.com/presentations/Simple-Made-Easy?variant...
There are advantages to functional programs, but I wouldn't say they're any easier to change than imperative programs. In fact, it's often more work to change a program where all functions depend purely on their arguments. Instead of adding a single imperative state update, you have to add a new argument to a whole group of functions and thread state through them appropriately.
Patterns like monads and monad transformers can make this easier, but massive stacks of monad transformers have their own issues (http://blog.ezyang.com/2013/09/if-youre-using-lift-youre-doi...).
(And besides, most functional programming languages apart from Haskell support mutable state (e.g. ML ref cells, Scheme set!) -- pure functions aren't fundamental to the functional paradigm.)