At this day and age people should be familiar with multiple paradigms. Whether procedural, functional, or Object-Oriented they are all useful. This is why you see languages like C++, Java, and C# adding support for them all.
It is useful to express a particular problem domain in a way that is efficient and makes sense.
I would be more interested in a discussion about concurrency because it becomes more relevant across the programming-language or paradigm barrier. Because at the end of the day we are confined by how the hardware operates and concurrency is very much a modern way of thinking as developers.
The path to concurrency is paved with a mix of finite state machines and event-driven programs. IMO, neither FP nor OO have all that much to say about that.
FSM/event driven is pretty easy even in rickety old languages like 'C'. C++ is a bit nicer because there is dispatch demuxing built in. I suppose the same is true of Java.
I guess webby stuff doesn't lead to the appeal of FSM but for everything else, it's generally a better path. FPGA guys use a lot of FSM and they simply don't have the same defect rates as software guys.
I've used toolsets like ObjecTime/Rose where "everything is a state machine" and It Just Works. I'm not sure why this approach is still obscure - the various works in Verification ( with a capital V ) seem to point to FSM as a means of reducing complexity.
I've lived the ObjectTime/Rose path.
Made good money converting projects out of those tools.
So yes, everyone should use them.
C++14 and coroutines have replaced state machines in my world. They read like normal code, are easy to customize to your needs.
Had to convert a large PLC system from Beckoff structured text to C++. Coroutines allowed me to model it close enough that a little python translator made it work.
Setup actors with queues that timeout on interval and pump the (taskLets) Coroutines.
Create functions that provide blocking on what ever you like. Events, msgs or time.
Better IMO, compared to code shattered into bubbles in a tool or callbacks everywhere.
>At this day and age people should be familiar with multiple paradigms. Whether procedural, functional, or Object-Oriented they are all useful.
Why assume that "all are useful"?
I'd say that most of them developed ad-hoc, and whether they are useful or not is subject to actual research on their effectiveness in the field, with controlled studies etc.
Usually PL researchers go the other way around, toy with some things at the language/compiler/syntax/semantics level that think are cool/powerful/expressive etc but rarely bother with actual justification based on those that actually will use the PL, that is programmers.
Which makes the whole field cargo cultish and a pop culture, as Alan Kay notes.
Being familiar with different paradigms extends your capabilities, allows you to investigate problems from different angles, and pick the solution most appropriate to the domain.
Even if you learn something 'useless' (either to the current problem or in general), it allows you to discard certain solutions, and know why they are not a good approach.
The flip side of the lack of scientific evidence is that you have no reason to believe that any paradigm you happen to know well is any better than the others. So if you can't trust other people's opinions (which when they are in the form of popularity surveys and shiny blog posts I absolutely agree with), how else are you going to find such evidence than to try using ideas you're unfamiliar with?
They are all useful. Functional: reducing side-effects improves potential for concurrency; Object-Oriented: create a new type and overload operators to make it feel like the abstract mathematical idea it represents; Procedural: subroutines are pretty much indispensable.
Explain why FP doesn't do 'create a new type and overload operators to make it feel like the abstract mathematical idea it represents' better with say, parametric polymorphism?
Just my two cents, but regardless of whether it is a more pure representation, I'd say it is empirically more difficult for the average, object-oriented human to wrap their brain around.
At least on that measure, the object oriented paradigm has demonstrated some success.
realist contrarian question: why? If you didn't receive a formal education but you got good at OOP js or php, your expected salary gets pretty close to six figures. No understanding or even theoretical appreciation of other paradigms required. And I say that as someone with a formal education in programming and decent understanding of most programming paradigms.
If you're a developer making six figures and aren't really interested in staying up to date with current trends or becoming a better developer, then it may be a waste of time. This attitude may come back to bite you in the ass in ten years when you're looking for a new job and find that your skills are no longer applicable to the modern workforce.
I will say that it's virtually impossible to be purely an OOP programmer without using ideas that originated with imperative or functional languages. It's also pretty difficult to be a really good OOP developer without writing at least some code that looks very functional. There's a lot of ideas and techniques that help you as a developer no matter what paradigm you choose.
Because for those who don't understand or explore other paradigms their skillset is limited. There is a lot to be learned in concurrency domain from functional paradigms. Take a look at intel threading-building-blocks which is a modern way to look at concurrency and it is very much using functional concepts. For instance, parallel_for, parallel_reduce, parallel_scan. Reducing side-effects improves potential for parallelism.
That has never been a problem in a large part of the programming job market. If your skill set fills the job opening a big coorporation or institution has, and that job sets you up for life (instead of the frantic contract based work for startups or small companies) then exploration is a luxury, but in no way a necessity.
Note that logic applies here: I'm questioning the "you should know" claim, not claiming "you should not know" because that would be ridiculous. Learn all you like if you feel that gives you a leg up, or an enriched quality of professional life, but it is absolutely not a requirement in a well-paying part of the real world's programming landscape, so claiming "one should" is a little rich.
Well, this is true if all one is interested in is getting a job today.
However, the best developers aren't primarily concerned about getting a job or not, they are genuinely interested in programming as both an art and a science. Money and jobs is secondary (and readily available because such individuals are more skilled than those that limit their pursuits).
Anyone who stereotypes the practices of the best developers is kidding themselves. Some of the best developers I know only know C.
In reality there are roughly two types of tech: staples and new ones. Staples are around for a long time, but HN tends to focus on new ones. The thing is, even our modern staples came from a much larger set of new pieces of tech.
What this means is, that if you're using a piece of tech that has been popular for at least 20 years, you're probably good for at least the next 20. If you keep switching to the new hotness, you will have to keep doing that because you are most likely learning stuff that won't stay around.
>realist contrarian question: why? If you didn't receive a formal education but you got good at OOP js or php, your expected salary gets pretty close to six figures. No understanding or even theoretical appreciation of other paradigms required.
Because it's about the knowledge, and about doing what you do better, not merely about how much you earn.
"Give him threepence, since he must always make gain out of what he learns" -- Euclid said to his servant when a student asked what he would get out of studying geometry.
If you are a professional developer you should always be learning and growing your skill set. You don't have to learn about functional programming, but choosing to remain ignorant does not reflect well on you.
There's a difference between learning about it and using it at work. Your job may not have any good opportunities to apply FP, but you should be learning about it in your spare time given how many great use cases it has in today's world.
the real world does not particularly line up with that statement. For a fast moving contract based world, sure, but there's also the other part of the programming landscape where codebases need to be maintained forever for institutions and large companies whose idea of stable is even stricter than OpenBSD.
I know plenty of people who work on both, and the second category gets paid very good money indeed to be the sole maintainers of complex codebases, with zero need or intention to learn new approaches because it won't let them do their job any better. Does that make them less likely to get a new job? sure, unless their new job still uses the language they use right now, which when you have 20 years of experience tends to not happen - other big companies and institutions will hire you on the spot. But a more important question is: will they even get to a point where they will need to look for a new job before retiring? Chances of that are roughly zero.
Even in those jobs, there are always tangential tasks, one-offs, and side projects that could potentially be done much more easily/efficiently using different tools than the primary codebase. Even when using the same tools, different ways of thinking (patterns, paradigms) can make a huge difference.
The tools used to build GUI CRUD apps may be very well suited to that, but sooner or later all that data collected by the CRUD GUI will need to be processed, analyzed, and/or migrated. Although that might be doable with your CRUD GUI building knowledge, other tools or approaches, more well-suited to data processing, could make that task far easier, better, faster, and more reliable.
A legacy system from pre-networked days may be optimized well within the environment that it was created for, but when the day comes to make it connectable with an API, different skills may be useful. If you refuse to learn them, then either you have to hire someone else or you are likely to end up with a mess.
Then the company decides to outsource the IT doing the maintenance of that complex codebase to an Indian off-shoring company and fire 80% of the team, leaving just the ones needed to work as technical leads for the off-shoring team.
Now those guys are stuck with outdated skills that no one wants to hire.
I'm not sure how your response applies to my comment? I said that your particular job may not provide an opportunity for FP but you should still learn it for the sake of professional development.
Even if you never need a job that uses FP, you should understand it so that you understand why you don't need it in your job.
Even if you never leave your job, having those skills will help you push for a raise and move you ahead in your field.
And chances are even if your job doesn't need it now, unless you're already near retirement, eventually there will be a case where maybe it is applicable.
Mind you, that's in part because of the ambiguity of the term "should": are you using the "should, as in nice to do but not required" or "should, as in required, and not doing it is wrong", because I'm on board with the first, but that is not how the original comment reads. That reads more like everyone should be familiar with multiple paradigms and not following that rule is bad. Which the real world heavily disputes.
I feel that case just begs the answer. You're describing a job which is defined as "don't change anything unless absolutely necessary", so it won't directly help your work to learn how to change things. This doesn't seem like a deep result about the uselessness of learning new programming paradigms.
For now maybe. But I think it is short sighted to think that trend is guaranteed to continue.
Down the road, as other developers pick up different paradigms and can potentially implement the same features you are writing, with a fraction of the bugs and in a fraction of the time, why would companies keep paying you six figures?
why would you believe companies would pay multiple people lower salaries, totalling more than a single six figure salary when benefits and taxes are factored in? It's easy to ignore large corporations and both government and private institutions, but they are not interested in efficient quick fire best solutions, they mostly care about things simply not breaking, and veeeery slowly moving towards what 5 years ago was the future, just incase the actualy 5 years from now prognosis doesn't pan out.
Learn all you like, it's a great idea and makes you a versatile developer ("for some, X is great"), but don't ignore a very real part of the world where versatility is literally a non-issue, and being able to maintain an aging codebase without suggesting changes is what gets you set for life. Claiming that "everyone should X" ignores the real world.
The history of employment is littered with the misfortunes of those who expected that one narrow and not particularly deep skill would set them for life, and the trend is accelerating.
Beyond that, there is the issue of whether you would prefer to work on something interesting, all else being equal. Of course, for that to be an issue, one first must be interested in something.
I think the OOP vs FP debate misses the real asset that functional programming offers us, and it's not writing everything in [your favorite functional language]'s typical style. Look at a language like Idris; a formal definition of its unsugared semantics would fit on half a page easily. However it still manages to give us all kinds of goodies, like effect tracking, compile-time checking for virtually any condition you can write a decision procedure for, and design-by-contract on steroids.
These features are useful whether the code you're writing is pure, stateful, object-oriented, functional, and/or whatever paradigm you write up tomorrow. Forget aesthetic arguments about elegance; where else can you build so much without ad-hoc concessions to individual language features? As far as I know, there's no other method that lets you treat powerful language features as libraries without either (a) making a mish-mash when they're used together like compiler plugins do (b) making debugging your compile process a full time job like various strongly-typed macro systems tend to.
Why not use FP to form the fundamentals of our languages, something where as of yet it has no equal, and build up the structures we need (regardless of programming tradition of origin) on top of that?
I like your points, but I'm not sure of the Idris on half a page. How much tacit knowledge does that rely on? We do need to focus on the fundamentals of education, the spectrum of logics with quantifiers, lambda calculus, and natural deduction style presentations of language semantics (not sure what to actually call this?).
I'm referring to the operational semantics[1]. This doesn't require any tacit knowledge to fix the language past what the horizontal line and definitional equality symbols mean (it's entirely in the form of purely syntactic "given this, you can write this"), but it won't be remotely helpful to teach you what the syntax reductions mean or how to use them. If you're never heard of lambdas, you could technically still "use" them in the sense a computer can, but good luck figuring out that they represent functions. It wouldn't fit any sensible definition of "understanding".
My point isn't that these things are easy to learn because their presentations are so brief; personally, dependent typing took me a long time for me to wrap my head around. What I think the briefness of the operational semantics in combination with the examples of things people have built within them suggest is that they're very versatile. Even if only people working on language level features bother to learn them, the utility of their creations (all without needing to move to another language or introduce possibly incompatible extensions) is a huge asset.
It looks like you're criticizing the GP's praise of Idris' concise formal definition of its unsugared semantics. I wouldn't use such a formal definition for educating novices (like I think you're implying in your next sentence); I'd use it professionally to show that many desirable things--effect tracking, compile-time checking, and design-by-contract--derive from the same thing. Ken Iverson in his notes on mathematical notation says that one criterion for a good notation is "suggestibility"--the notation should suggest that other problems similar to those you found just now could be solved as well.
Whether formality is useful for novices, it is certainly useful for experts.
This conversation is awful. This seems like a bunch of armchair developers with really strong opinions and no real world experience.
No experienced developer I want to work with has the kind of dogmatic views that most of the people in this chat log have. FP and OOP are both just tools, how you use them is way more important than which tool you choose.
" No matter what language you work in, programming in a functional style provides benefits. You should do it whenever it is convenient, and you should think hard about the decision when it isn't convenient. "
In addition, the discussion in that chat looks far from constructive...there are legitimate uses of OOP, but they are ignored completely in lieu of sweeping statements.
Indeed, for example I think that the so-called "reliability" offered by FP is can be attributed to comparable simple tasks these developers work on. It's typically some form of parsing data.
While the motivation for their models might be complex or esoteric, calculating out the parameters might as well be done in Excel. Typically, the data flow is linear, and well suited for FP.
But it ain't hard either.
The kind of complexity I'm referring to is the need to synchronize and coordinate concurrency in a time efficient manner, along with the user interaction that is found in desktop applications - or in my case that controls hardware instruments.
the so-called "reliability" offered by FP is can be attributed
to comparable simple tasks these developers work on
The kind of complexity I'm referring to is the need to synchronize
and coordinate concurrency in a time efficient manner[..]
There's more than one kind of complexity. Keeping 1.3 million SLOC of trading code relatively error free while allowing non-full-time programmers to contribute to it is also complex.
Drop the dogma. Stuff like "OOP is terrible" or "FP is terrible" or "JavaScript is terrible", etc. are not only wrong but they are destructive only to you. Nobody else cares that you hold this view, it just keeps you ignorant about that thing and holds back your skill set and career. If you take the time to actually learn how to use the thing in question properly, what the good parts of it are and how good things not only can be made with it but are being made with it you will be better for it. Even if at the end of that you still decide you don't want to use it yourself (which is totally valid, we all have our preferences) you will be better off. You will be take the view not that "X is terrible" but that "X is not my preferred way of doing Y."
Second, don't waste your time bullshitting with a bunch of people who don't know anything about anything and just want to be "right" all the time. Where "right" here is actually "agree with the trendy position", which right now is "FP is good, OOP is bad." Talk to professional developers who actually do the work you want to do, and learn from them what it is they do and how they do it. To be sure, some people who hold those silly views do work as developers, but I would argue they're not professional. A professional sees tools as tools and not as a substitute for a personality.
Bullshitting is a great thing to do to blow off steam, we can't code 24x7, but there's constructive chat and then there's a useless echo chamber full of nonsense (which IRC is really good at forming.)
Anyway, hope that helps. I used to talk like the stuff I see in this chat when I was younger, then I realized what I just said about those opinions only being harmful to myself and now I try to be more open minded.
Thanks. I was trying to show it started off unproductive and went into a constructive chat about Haskell type and value level functions, but this was also a lazy test of if people are interested in the conversational format. I think the result is maybe? I want to make a socratic dialogue style presentation of some ideas in FP, I don't have much interest in saying OOP is terrible, because I don't have much interest in talking about OOP.
I really believe the future is a mixed OOP and FP world. I think we will see industry use languages like Scala and F# more and more.
In mission critical portions of systems people will use a functional style and try to isolate state, while most things in an OO style will be just fine.
I also believe the crazy complexity of OO languages like Java is slowly being reigned in. With other languages like Go explicitly making trade offs towards simplicity.
I have no stake in pro-Go or anti-Go statements here, but I do want to say that a simple language does not always lead to simple code in that language.
For example, if one has to copy and paste because a language is too simple to provide a needed abstraction, then the code is needlessly complicated (through duplication) because the language is too simple.
>In mission critical portions of systems people will use a functional style and try to isolate state, while most things in an OO style will be just fine.
What makes you think that programmers who are used to writing in FP style for mission critical components would step away from FP for OOP for less important code? In my experience, most of the time functional code is often more succinct and easier to write. I don't think it would benefit anyone to write the majority of an application in the more verbose style.
>languages like Go explicitly making trade offs towards simplicity
I think Go is a counterargument to your point here. It's simplicity makes it much less suited for multi-paradigm programming than a complex language like C++ or Scala.
Java didn't have generics either, until Java 5, when they've added an implementation with use-site variance with wilcards, for backwards compatibility reasons probably, but which is very user unfriendly. The irony is people complain about type erasure as being Java's problem, when in fact that has been one of its greatest features.
But anyway, the creators of Go where right to fear generics, b/c generics are hard. However the more time passes, the harder it is going to be to add. And truth is it's inevitable for generics to happen in Go and when they'll do they'll be half baked.
And remember that Java has striking similarities. Java is also a very opinionated and anti-intellectual language.
Michael Fogus, author of “Functional JavaScript”, suggests in his blog post “FP vs OO, from the trenches” (http://blog.fogus.me/2013/07/22/fp-vs-oo-from-the-trenches/) that when he deals with data about people, FP works well, but when he tries to simulate people, OOP works well.
I wonder about shape of the data as it moves from domain -> range? How would they map to machine and biological models for learning? First guess is the that ML maps well onto FP; for CNNs, the data progresses synchronously from one layer to the next. For Bio, state is asynchronous; neurons, after firing have an efficacy period. Maybe super-fine-grain objects? Petri nets are interesting in that they can feedforward state asynchronously.
A few incorrect points during the discussion as well as poorly approached. The only thing beneficial that I see from it is people trying to better their skills and Haskell gaining traction.
I personally would recommend #haskell-beginners on freenode IRC as well as http://haskellbook.com for the ones interested.
For everybody else, well I'm not a sale person and my job isn't to convince you. If it takes you 30 years to (re)discover Haskell, so be it.
Haskell as we know it now, with high performance, large library selection, more powerful type system, advanced tooling, testing and profiling etc, has been around for significantly less time than that.
I also think that's a specious argument. Many things influence a language's popularity that have nothing to do with the language's actual value. Haskell is very idiosyncratic compared to other mainstream languages, requiring a "relearning" of a lot of skills developers take for granted. Many people balk at the learning curve and never get into it. Haskell has also received comparatively little contributions from industry and was never the pet language of a major organization (like e.g. C#, Java, Go, Rust, Dart, etc). Also the influence of Haskell can be seen in a variety of areas, from other languages adopting more advanced type systems, type classes, systems like LINQ in C#, and the increasing popularity of functional programming in general. Finally, although popularity drives language ecosystem and therefore usability, Haskell's merits purely as a language stand on its own regardless of how many people use it.
Also we got Stackage and Stack recently (which ended "cabal hell"). Even "cabal hell" is gone with the new cabal-install improvements.
So don't count Haskell out too easily because it's old. It's an awesome language, but it took people a long time to figure out how to program well in it, given that it's so different from the normal way of doing things.
Like we only now see how bad large OO systems can be? :D.
Seriously though I think that people are becoming interested in FP because they see the limitations of their current tools. That's what happened for me anyway.
Also I don't know that Haskell will become mainstream, but something that looks way more like Haskell than Java will.
Haskell might be bad, but its unofficial slogan is "Avoid success at all costs" -- so I don't think lack of fire necessary implies it's shitty (which is I think what you were implying.)
I've always interpreted it (and I'm not sure Simon would disagree) as a serious "avoid success-at-all-costs" and a tongue-in-cheek "avoid success at-all-costs".
Haskell definitely has problems. I'm a huge fan of the language, but I think its disingenuous to pretend like its flawless.
To name a few:
1. Poor debugging tools. Unfortunately this is sort of intrinsically tied with non-strict evaluation. Typical evaluation stepping debuggers would be sort of unpredictable in haskell. Along these lines, haskell doesn't have stack traces enabled by default, and reading them is sort of tricky.
2. Clumsy exceptions model. There are asynchronous and synchronous exceptions, with the later being further broken down into exceptions in pure code or exceptions thrown in IO. Only exceptions thrown in IO are catchable. You can think of exceptions in pure code as similar to "panic()" calls in other languages, except they're even tricker due to lazy evaluation, and aren't necessarily guaranteed to be triggered due to slipperiness with laziness. Also since exceptions are used for interrupting computations (timeouts, for instance) and there isn't a way (other than some type class conventions) to distinguish between interrupting exceptions that should be allowed to propagate and exceptions due to "exceptional circumstances", catching all exceptions safely is a tricky matter.
3. Record syntax leaves a lot to be desired. It's incredibly easy to run into situations where you would have conflicting functions due to record syntax. Lenses are a partial fix for this, but its sort of annoying that something like row polymorphism isn't just a part of the language.
4. Laziness can make reasoning about time and space complexity trickier. Generally this is a little overstated, but you'll occasionally run into space leaks.
There are definitely real problems with the language, and some of them (such as poor debugging capabilities) can be legitimate showstoppers to use in industry, but generally I find that its advantages far outweigh its negatives.
The bits about exceptions and IO isn't quite right.
So far as I'm aware, there is no technical difference between exceptions thrown in IO versus exceptions thrown in pure code. There are two contextual differences.
First, exceptions can only be caught in IO, but everything running has IO above it somewhere, or it wouldn't be running in the first place.
Regarding exceptions thrown in IO versus elsewhere, it's worth noting that exceptions thrown anywhere are only actually thrown if the thunk representing them is forced. IO values tend to be used quite close to where they are created, whereas an exception in lazy, pure code might hide in the creation of the leaf of a tree or at the end of a list.
Yeah, just reread how I worded this and it's not quite correct. Your points here about how all synchronous exceptions are handled the same is correct. I think what I was trying to get at was that exceptions in pure code are usually treated like fatal errors.
The biggest challenge is definitely how easily exceptions can slip by handling code unless you make strict use of throwIO with synchronous exceptions (or something equivalent like throwM from exceptions). My favorite example is the following:
Many people learn Haskell (or FP in general) at university and then wash their hands of it and refuse to ever touch it again. Perhaps consider it could be a matter of preference or right-tool-for-the-job rather than the fact that the unwashed peasants just haven't "discovered" enlightenment yet.
Spoken as someone who prefers FP but is not a zealot.
Most statically typed programs/systems these days (Java, C#, even C++ if you wish) these days, use DI via IoC containers as the mechanism for constructing objects and choosing which code to run. You can even do it with dynamic languages like JS/Python if you wish, though many argue it being dynamic means you don't need to use a container - which is pretty true.
This approach is equivalent to a family of functions (with side effects), one family per class, each with N(c) + N(m) arguments, where N(c) is the number of constructor arguments, and N(m) is the number of method arguments. Upon object construction, these families are partially applied to construct a new family of functions that contain only N(m) arguments. You can think of a constructor as a functor, that returns a number partially applied functions - the methods on the classes.
This is how I actually think of my OO programs these days. I also make liberal use of the actual functional tools made available to me. For instance, my bread and butter is C#, and LINQ heavily promotes a purely functional style when manipulating collections of data, though side effects are possible.
At a system level, I also tend to think of my data pipelines as functional transformations as well - their being written as an OO program is of little actual consequence.
Cool, but I find that hard to read. I'm going to do a custom stylesheet, I was just waiting to see if there was any interest in the conversational format form my Slack conversations. Really appreciate your effort.
It is useful to express a particular problem domain in a way that is efficient and makes sense.
I would be more interested in a discussion about concurrency because it becomes more relevant across the programming-language or paradigm barrier. Because at the end of the day we are confined by how the hardware operates and concurrency is very much a modern way of thinking as developers.