Hacker News new | ask | show | jobs
by WolfeReader 857 days ago
You begin with "I don’t really care what people making claims say when they make claims without evidence". May I hold you to your own standards?

Because the rest of your post is pretty LOL-worthy in light of your opening sentence.

1 comments

Sure:

1) immutability has performance problems: source: literally every measurement of immutable vs not data structures ever performed.

Source 2: logic - copying data is slower than not copying it

Source 3: cache lines: modern CPUs rely pretty heavily on cache lines and branch prediction to improve performance. Immutability measurably harms both.

2) immutability requires more code and loc is the best predictor of defects

Clarification: runtime immutability requires more code

Source: it takes more lines of code to return deep copies of objects than to not do that.

Source: https://www.researchgate.net/publication/316922118_An_Invest...

Package densities are the best predictors of defects

3) Haskell projects have as many bugs as any other language

Source: the best evidence we have here is “the large scale study of programming languages on GitHub”, but I suggest that you look deeper here, as the authors qualifications of defects is somewhat questionable (a project that never fixes defects would have low defect rates in this study, it additionally doesn’t properly compare projects sizes and other things). Anyways, in responses that do have better controls in place (and hilariously even in this paper itself, where we see Haskell programs tend of see higher defects as projects go on while c projects tend to have fewer), we see that Haskell does absolutely no better than anything else for bugs and defects.

When you say "the large scale study of programming languages on GitHub", are you referring to this? https://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf

"Table 7: Functional languages have a smaller relationship to defects than other language classes where as procedural languages are either greater than average or similar to the average."

"The data indicates functional languages are better than procedural languages; it suggests that strong typing is better than weak typing; that static typing is better than dynamic; and that managed memory usage is better than un-managed."

You got owned by your own source.

As for your un-sourced claim that "copying data is slower than not copying it", I'd suggest learning how immutable-first languages practice data sharing between objects to minimize the amount of copying needed.

I wanted to write that making defensive copies is something you need to do in mutable situations to preserve safety, (not in immutable situations!), but it looks like enough commenters have hit that point.

So lets disabuse your mistrust of immutability in another domain!

Here is some typical "go fast and mutable!" nonsense code:

    int foo(int i, int j) {
      while (i < 10) {
        j += i;
        i++;
      }
      return j;
    }
Let's compile it with https://godbolt.org/, turn on some optimisations and inspect the IR (-O2 -emit-llvm). Copying out the part that corresponds to the while loop:

  4:
    %5 = sub i32 9, %0, !dbg !20
    %6 = add nsw i32 %0, 1, !dbg !20
    %7 = mul i32 %5, %6, !dbg !20
    %8 = zext i32 %5 to i33, !dbg !20
    %9 = sub i32 8, %0, !dbg !20
    %10 = zext i32 %9 to i33, !dbg !20
    %11 = mul i33 %8, %10, !dbg !20
    %12 = lshr i33 %11, 1, !dbg !20
    %13 = trunc i33 %12 to i32, !dbg !20
    tail call void @llvm.dbg.value(metadata i32 poison, metadata !17, metadata !DIExpression()), !dbg !18
    tail call void @llvm.dbg.value(metadata i32 poison, metadata !16, metadata !DIExpression()), !dbg !18
    %14 = add i32 %1, %0, !dbg !20
    %15 = add i32 %14, %7, !dbg !20
    %16 = add i32 %15, %13, !dbg !20
    br label %17, !dbg !21

  17:
    %18 = phi i32 [ %1, %2 ], [ %16, %4 ]
Well, would you look at that! Clang decided (even in this hot loop) never to re-assign any of the left-hand-sides, even though my instructions were just: "mutate j in-place. mutate i in-place."
Listen dude. I’m not going to argue about this:

Immutability is measurably slower. Full stop.

The fact that you can come up with silly, overly simplistic, non-idiomatic anecdotes showing that sometimes a compiler will prefer calculation doesn’t change that. It is a commonly known fact in low level programming that just because you’re calculating something doesn’t make it slower by default.

When Haskell devs can produce a game engine that doesn’t look like PS2 on a 4090, we can chat again about how immutability is supposedly not slow.

> Source 2: logic - copying data is slower than not copying it

> Source: it takes more lines of code to return deep copies of objects than to not do that.

Defensive copying and deep copying is not a thing you have to do in immutable languages. Even under the covers, it's not happening the way you seem to think it is. If I had a large immutable map in use by some other process, and needed a version of it with an element changed or added, why would I deep copy it when I can just point to that same map instance, and add a pointer to the key-value pair I want to substitute [1]? I think this is a common reservation people have about immutable programming because they come into it with a OO mindset. At least, I know I did.

In a really simplified example, a = (1, 2, 3, ..., 100) and b = (2, 3, ..., 100) are not allocated as two full lists in memory space. a contains 1 followed by a pointer to b. Because you have guarantees that b will never change, the single instance of b can be recycled in other data structures (or passed to many other functions and threads) and you avoid the complexity of managing race conditions, mutexes, semaphores, which are a significant source of bugs in other languages.

See [2] for a more realistic implementation.

1. https://en.wikipedia.org/wiki/Radix_tree

2. https://en.wikipedia.org/wiki/Hash_array_mapped_trie

In order to flatten these to regain cache hits, a deep copy is required all the way down.

There’s a reason that the fastest Haskell game engine looks like ps2 graphics on modern hardware.