Live data from Hacker News

Why Rust closures are somewhat hard

stevedonovan.github.io

91–92 of 92 posts

Re: Why Rust closures are somewhat hard

#91
post #48

Everything that's hard in Rust could be solved by GC. With Rust, programmers have to spend most of their mental energy worrying about management of memory, which has largely been automated already. I always go back to this quote from Andrei Alexandrescu (creator of D): A disharmonic personality. Reading any amount of Rust code evokes the joke "friends don't let friends skip leg day" and the comic imagery of men with…

> You just limited the set of programs you can write ... which is smaller than the set of good programs

That's true of all static type systems.

Also, the whole point of Rust is to cover cases where performance and memory management are important. If you can use a GC'd langauge for you program, then pick one of the many fantastic existing ones.

Re: Why Rust closures are somewhat hard

#92
post #13
post #8

I don't understand the intuition of closures and they turn me off to languages immediately. They feel like a hack from someone who didn't want to store a copy of a parent-scope variable within a function. The idea that I can touch variables that have gone out of scope (and that have ostensibly been GC'd) makes me feel that it is impossible to reason about variable lifetimes when dealing with closures. Is there some p…

I don't have a problem with the intuition but I'm with you on programming style. It's sort of a contrary opinion but I prefer to be explicit about state, and closures are sort of silently bundling up state for you behind the scenes. It's not very apparent from the syntax. I think languages should have a lighter-weight syntax for classes and that would subsume many use cases for closures. ----- While I've never progra…

Yeah, I came to the same conclusion about closures when I wrote Ur-Scheme. In mainstream modern languages, you have the remarkable situation that, when you are writing the code, you know which variables you intend your closure to capture, but you don't note that explicitly in the code. Then the compiler needs some extra complexity to calculate the set of free variables in the body of the lambda — and which binding contours they are being captured from, although that's usually pretty trivial. And then the guy who is changing the code next year also needs to reverse-engineer that same set of variables and binding contours in order to modify it successfully. So it seems sort of perverse to leave that information out of the code!

Since then, though, I've come to doubt my conclusion, for two reasons:

1. The same thing is true of, for example, static types; but using type inference or dynamic typing often makes your code easier rather than harder to read. (Some wag said something to the effect that dynamic typing is what you do when it's simultaneously so trivial to see that your program has no type errors that you can do it in your head and so difficult that you don't want to spend the time to do the proof.)

2. There isn't a really compelling difference to me between the closure in

    ^(x 
capturing x and the closure in

    fetch(json).then(r => widget.displayJson(r.json()))
capturing widget, or the block in

    (let ((overlay (make-overlay beg end)))
      (overlay-put overlay 'face (or face 'highlight)))
capturing face.

That is, inner blocks of control structures implicitly capture variables from their outer scope all the time, and this is mostly not a problem; and closures are a useful technique to make it possible to extend the set of control structures. (As it happens, let in Emacs Lisp is implemented as a built-in special form, but in Scheme it's normally implemented as a macro that puts the inner block into a closure.)

Maybe part of the reason is the lifetime: the example with fetch() is in fact socking away a reference to widget until after the HTTP response comes back, so aliasing bugs and space leaks are possible, while the other two examples aren't. This might be a reason implicit closures are so much more popular in functional programming languages: aliasing bugs are not a problem for immutable data, and nobody expects to be able to predict how much memory their functional program will need anyway.

Post reply on HN