Live data from Hacker News

Functional languages should be so much better at mutation than they are

cohost.org

161–170 of 188 posts

Re: Functional languages should be so much better at mutation than they are

#161
post #56

Earlier quoted context omitted.

Aside: Could a Rust library provide an Rc interface but use a more sophisticated GC algorithm underneath?

You can, but it turns out that, as one may intuitively expect, a GC is never needed unless implementing a VM for a GC-based language or an API that required GC like fd passing on unix domain sockets, and those generally want an ad-hoc GC instead tailored to whatever you are implementing. Since it's not needed and it's massively worse than reference counting (assuming you only change reference counts when essential an…

> You can, but it turns out that, as one may intuitively expect, a GC is never needed unless [...]

Rust uses plenty of reference counting. You could replace most of that with a GC; depending on your GC implementation and your reference counting implementation, and your requirements in terms of latency and throughput and ability to handle cycles.

> Since it's not needed and it's massively worse than reference counting (assuming you only change reference counts when essential and use borrowing normally) due to the absurd behavior of scanning most of the heap at arbitrary times, there is no Rust GC crate in widespread use.

There are choices. You can have real time garbage collectors. And if you want to handle cycles, you need some kind of tracing anyway.

Also, if you only care about throughput and not about latency, garbage collection can easily be faster than reference counting.

If you don't allow cycles, you can also take advantage of that in your garbage collection. See how Erlang does it. (In Erlang, the garbage collector relocates your objects so that they are in topological order, so all references only point forwards in memory. You can combine that with generational gc, too, of course.)

Re: Functional languages should be so much better at mutation than they are

#162
post #97
post #77

Earlier quoted context omitted.

People often forget that the runtime of free is not trivially calculatable! I've worked on tiny embedded systems (.net micro framework) where for a given usage pattern the GC was perfectly predictable, as it should be.

What do you mean? Assuming you use a set of slabs of fixed size objects and keep free objects in a linked list, both malloc and free are trivial O(1) operations. Destructors with cascading deletions can take time bounded only by memory allocation, but you can solve that for instance by destroying them on a separate thread, or having a linked list of objects to be destroyed and destroying a constant number/memory size…

> Destructors with cascading deletions can take time bounded only by memory allocation, but you can solve that for instance by destroying them on a separate thread, or having a linked list of objects to be destroyed and destroying a constant number/memory size of them on each allocation.

You can run your garbage collector on a separate thread, too. Or use a real time garbage collector.

Re: Functional languages should be so much better at mutation than they are

#163
post #128

> A lot of people think that functional programming is mostly about avoiding mutation at all costs. People should try to stop thinking of mutation as something to be avoided, and start thinking of it as something to be managed. Mutating state is good. That's usually the whole point. What's bad is when you create "accidental state" that goes unmanaged or that requires an infeasible effort to maintain. What you want is…

> plus a mechanism

That should read, “plus one mechanism”. Another place where people get into trouble is thinking “a” means >= 1 instead of exactly one.

When the state has multiple entities trying and failing to manage it consistently is when things get bad. Functional tends to make for more friction which discourages doing a lot of state, which to some extent controls the superlinear complexity of state management by making each piece dearer.

Re: Functional languages should be so much better at mutation than they are

#164
post #88

Earlier quoted context omitted.

> You're basically trading runtime efficiency for memory. What do you mean? Aren't GCs both less efficient at run time and use more memory?

Worst case, 2× is actually a steal compared to a non-moving allocator such as malloc/free or RC built on top of that, which cannot[1] do better than about 1 + ½log₂(largest allocation / smallest allocation). For example, if you have allocations from 1K to 16K bytes, any malloc/free implementation can require at least 3× the memory you actually use; if from 16 to 16K, 6×; etc. At this point I must mention that paged m…

For anyone following the discussion: Mesh (https://github.com/plasma-umass/mesh) is a seriously interesting read.

Re: Functional languages should be so much better at mutation than they are

#165
post #111
post #105

Earlier quoted context omitted.

So, RC is better than tracing GC, when it’s not used as memory management, and it is special cased everywhere.. got you! Like, as I explicitly wrote, it is probably the correct choice for low-level languages close to the metal, that want easy compatibility with other languages through FFI. But the method itself has still got a much slower throughput than a tracing GC, when used in a similar manner . Anything else is…

> But the method itself has still got a much slower throughput than a tracing GC, when used in a similar manner That is correct, but the issue is not with reference counting, but rather with having unnecessary extremely frequent RC/GC operations. Once frequency is reduced to only necessary operations (which could be none at all for many programs), reference counting wins since its cost is proportional to the number o…

You can very well have a Rust-like language with Rust's model of 'compile-time memory management', but you replace all uses of reference counting with tracing garbage collection.

Re: Functional languages should be so much better at mutation than they are

#166
post #101
post #95

Earlier quoted context omitted.

> One thing that many people miss is that Haskell's monadic style is a direct consequence of lazy evaluation. It all started because they thought lazyness was nice, and wanted to make a language that brought that front and center. But then they found out that they had to come up with a new way to do side-effects, because traditional side-effects don't work when the order of evaluation is unpredictable. But this is no…

I wouldn't say that's an accurate description of how Haskell handles side effects. In fact I wouldn't say that Haskell has side effects at all.

Well, it depends on exactly what you mean by side-effects.

First, obviously you have unsafePerformIO, so that everything can have side-effects.

Second, you have side-effects like using memory or using the CPU. You are not supposed to worry about those. Though a more serious side effect you do have to worry about is non-termination. Haskell doesn't track that in its type system.

You are right that the way input/output is handled can be described not as _side-effects_ but as _effects_ of interpreting values of the IO datatype.

Re: Functional languages should be so much better at mutation than they are

#167
post #132

Earlier quoted context omitted.

I think this is historically wrong. Monads didn’t land until later in Haskell, no?

They did, but they also did land explicitly to make I/O suck less in lazily evaluated language instead of magic main function signature working to provide explicit ordering. There's a reason why Monads aren't exactly monadic and why IO was the original monad in GHC -as well as why non-lazy, non-super-pure languages never really go for Monads

Actually, lots of those more pragmatic languages go for monads, they just don't use them for input/output.

The way JavaScript handles async is pretty close to monadic. Error handling via the local equivalent of Maybe / Either is monadic. Tuples are monadic. Sequences can be monadic. Etc. Some languages have a flexible enough type system to expose this (like Haskell), some don't. Some like Rust generally don't expose monads to the type system, but their users are aware enough of the shared monadic structure that you can see it reflected in the naming conventions for functions that do essentially the same thing (in a monadic sense) but for different structures.

Re: Functional languages should be so much better at mutation than they are

#168
post #137
post #107

Earlier quoted context omitted.

It's literally impossible on a CPU. Some people claim FP languages can make optimisations that are based on the fact that values are immutable and which other languages can't, and that's definitely true. But the problem is that those optimisations are almost never actually made by real programming languages, and when they are, they're still slower than a low level imperative language like C or Rust in very nearly eve…

If you compile your immutable program with LLVM, literally one of the cure steps is transforming it into functional form that does not allow mutations. This is called Single Static Assignment form and its denial of mutation is crucial to optimization, from common expression removal, to efficient register allocation, and all sorts of control flow analysis.

> If you compile your immutable program with LLVM, literally one of the cure steps is transforming it into functional form that does not allow mutations.

You probably wanted to write something like 'If you compile your _mutating_ program with LLVM, [...]'?

Re: Functional languages should be so much better at mutation than they are

#170
post #144
post #128

> A lot of people think that functional programming is mostly about avoiding mutation at all costs. People should try to stop thinking of mutation as something to be avoided, and start thinking of it as something to be managed. Mutating state is good. That's usually the whole point. What's bad is when you create "accidental state" that goes unmanaged or that requires an infeasible effort to maintain. What you want is…

I like to say that immutability is a really good idea in the 1990s, especially considering how counterculture it would have been at the time. I don't mean that as diminutive or patronizing, I'm serious. It was a good cutting edge idea. However, nobody had any experience with it. Now we do. And I think what that experience generally says is that it's a bit overkill. We can do better. Like Rust. Or possibly linear type…

> I like to say that immutability is a really good idea in the 1990s, especially considering how counterculture it would have been at the time. I don't mean that as diminutive or patronizing, I'm serious. It was a good cutting edge idea.

> However, nobody had any experience with it. Now we do.

Working intimately with C++ in the '90s, immutability as a concept was neither considered counterculture nor without significant experience employing it. At that time and in C++, it was commonly known as "const correctness" and was a key code review topic.

Go back another decade or two when K&R C ruled the land and that's a different story ;-).

Post reply on HN