Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Because side effects cause bugs and make code harder to reason about.

The ways we avoid side effects can be inefficient. Tools such as immutable data types. In the past it wasn't really worth the performance trade off. Now days we're often running in environments where raw speed is not achieved on single core performance but over distributed systems. All of a sudden immutability seems to make more sense. Not only does it help with removing side effects but it also helps parallelize workflows.

I think that's why its happening now.

I've recently switched to using F# where I can and it's been a huge win. The bug count is way down, I can refactor with confidence, and My code is more readable.

The learning curve was hard. I still am not sure I truly understand what a Monad is but I can see the pattern and use it as a tool. It feels more constrained at first but it brings order to chaos.



Can it be summarized with: multi-threading in non-functional languages is the most confusing and most time consuming thing?


Not exactly. I wasn't just talking about multi threaded systems but multi machine systems too. Where there is no shared memory. If you need to serialize your data to send out to a cluster for processing you've already constrained yourself to immutable data.


Most webapps are actually embarassingly parallel (https://en.wikipedia.org/wiki/Embarrassingly_parallel) and require little synchronisation. Most of the hard synchronisation problems are solved for you in the DB (at least if you've chosen a good one).


Its neither time consuming or confusing if you understand the concept of mutex, which is only one thread can access a resource at any given time. Anything beyond that is irrelevant for 99% of the use cases for multiple threading.

And furthermore, its highly likely that your project is better suited to async programming instead.


> I still am not sure I truly understand what a Monad is but I can see the pattern and use it as a tool. It feels more constrained at first but it brings order to chaos.

Ha, I learned Haskell over 6 years ago and I still can't explain what a monad is other than in programming terms. It's a container which defines two operations: put something inside the container (Haskell's "return" keyword), and chain two operations on the container together (Haskell's >>= operator).


That's because there's not much more to it.

The Monad tutorial problem is entirely due to academically oriented people attempting to explain monads through category theory etc.



As far as haskell

Declarative by nature and get parallelism and concurrency from the world class ghc runtime ; avoid call back style js, locks mutex, semaphores

Type classes

Type inference

Io capturing the messy real world of state, side effects, io, async concurrency, parallelism

Pure functions or expressions as opposed to imperative Statements

Pattern matching

Monads >>=

Monadic transformers

Maybe Monad equivalent to option type in rust ocaml to avoid null (f# might still have nulls)

Hackage cabal stack and world class libraries

Green threads like erlang Otp elixir

Cloud haskell is haskell's answer to erlang

Lazy default evaluation with strict constraints if needed

Perform unsafeio but explicitly

Immutable by default

Stm software transactional memory when need mutations that compose well

Heavily optimized ghc compiler with fast gc

Type safety Compilers giving errors on type mismatches : trusting the compiler and refactoring with abandon - if it compiles it works

Haskell native compiled code can be Very fast as in golang / ocaml

Tldr haskell makes easy things hard with a steep learning curve and hard things easy as composing is way more useful than Oops. Theoretically, functional programs should: have fewer bugs, be easier to optimize for performance, allow you to add features more quickly, achieve the same outcome with less effort, require less time to get familiarized with a new codebase, etc.

As venerable prof Joe armstrong says you need haskell erlang for fp ; you need c for high performance ; you really don't need cpp Java python c#

Most of these points apply to varying degrees to common lisp racket erlang elixir rust


> Most of these points apply to varying degrees to common lisp racket erlang elixir rust

... and Scala, with libraries explicitly apeing Haskel, such as Cats.


>Because side effects cause bugs and make code harder to reason about.

Not really. All functional programming does is basically force you to shoehorn your computation into defined pipelines. For some cases this works, for others, you are doing a lot more work than necessary compared to imperative programming, and the cycle of you developing said code is usually longer than writing the code imperatively, and then debugging.

In general if you look at the history of tooling, there has been a certain pattern within languages/tools where some description alludes to programmers being incompetent.

For example, in the case of functional programming, your statement above essentially means "As an incompetent programmer, you may write code that sets a variables value unexpectedly, which is turn used by some other thread, which will create a bug. So you need functional programming to avoid making this mistake"

History has shown that this doesn't work in practice, because you create arbitrary boundaries, friction, and inefficiencies that slows down development by a large amount. There is a reason why Python is top language (only second to Javascript, because of web stuff) on github, and as far as it goes, its a free-for-all in terms of how you code.


> "As an incompetent programmer, you may write code that sets a variables value unexpectedly, which is turn used by some other thread, which will create a bug. So you need functional programming to avoid making this mistake"

Ouch, don't hold back tell us what you really think.

But that is not the entire meaning. If I have a function that has side effects such as a typical OO setter function it may change the state of the object in ways that are encapsulated from the consumer of the function. If someone has to come in years later and change that function it's not always obvious what state changes the function is required to make in order for the other functions in the class to operate. So we have regression tests to ensure any misunderstandings are caught.

Pure functions take in state as data. So we lose the encapsulation but gain clarity.

You are correct however, if we programmers could only do our jobs competently we'd have no need of such things.

Personally I like to setup tools that catch my mistakes, because I make lots of them.


> You are correct however, if we programmers could only do our jobs competently we'd have no need of such things.

That's the thing though - comparing "good FP" vs "good OO" is a false equivalence, in reality you will need to deal with other people's code, or yourself when you didn't know better. Bad OO << bad FP, that's basically all I need to make my mind up!


To quote someone smarter than me.

"100% pure functions are the way to go where possible"

You don't need to throw out OO to introduce some functional ideas that help improve the correctness and make it easier to maintain.

Bad FP to me often means the unreadable mess of complexity that some choose to introduce with their functional code. Personally I try to avoid anything that I'd consider "fancy". But using pure functions is functional programming IMO.


That's true, if someone's fallen in love with recursion or currying, that's often going to end in tears.


Currying is amazing though.


Amazing to write, often insane to read / debug


> I like to setup tools that catch my mistakes

If you write unit/integration tests for your code, you already have all the tools necessary to catch those mistakes. You also have general knowledge at your disposal on writing code smartly as to avoid potential mishaps.

You don't need a whole another programming paradigm to do all of this.


>You also have general knowledge at your disposal on writing code smartly as to avoid potential mishaps.

Exactly that's why I use pure functions where possible.


A bug you didn't catch can cost the entire project, sometimes more.

And nothing to do with competency. Carmack himself let a lot of 'easy' bugs in his games.

Let's say you want performances. The easiest way to avoid bug in critical software would be to code in Ada (at least it is in my country).

If you still want some abstraction, at the cost of security, let's say for the program that will run the 3M experiment that your Ada code just launched into space, you'll use Ocaml, despite the fact than a huge part of your scientists know python better (real world examples BTW).

Also, code in python use more and more generator everywhere (even when more imperative solutions exists), I don't think I've seen any complex objects that did not use itertools in years (in professional context), and the lambda keyword is used more than ever (even saw it last week in a pydantic code, when it's typically the kind of code where imperative is better).

Also, React-based frameworks encourage functional style, and as people will understand the paradigm more, it will be used more.

For some stuff imperative is better BTW, I'm not saying functional is better. I've work for three year for a PaaS company, selling big data capacities to universities and some companies, I don't think I needed functional programming once. But clearly, even if you code in python, if you want to do big data stuff, you'll do functional. If you work in datascience, you'll do functional. I'm in $bigbusiness now, and in the first big library I've done, one of the 3 PR comment was 'you should just use zip here', so I guess in big business, you'll have to do some functional programming too.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: