6 ms·
Why Rust ditched pure functions
- vimes656 13y agoThe corresponding reddit thread at /r/programming: http://www.reddit.com/r/programming/comments/1t8y6g/why_rust_ditched_pure_functions/ http://www.reddit.com/r/programming/comments/1t8y6g/why_rust...
- qznc 13y agoInterestingly, D has this and everybody considers it great. The community consensus is that pure should have been the default, but it is not changed for backwards compatibility. http://qznc.github.io/d-tut/idiomatic.html#purity http://qznc.github.io/d-tut/idiomatic.html#purity
- frozenport 13y agoYou would only use D if you considered it great.
- Tuna-Fish 13y agoThere are other reasons to use D, and indeed, most of the community came from languages without pure functions and did not want the feature before trying it. However, it's one of those things where once you use it for a while, you begin to really appreciate it. Better optimization, autovectorization and cpu -> gpu code conversion are all unimportant reasons for checked purity in the type system. The important reason is that by constraining what functions do, it makes reasoning about complex systems easier. Generally, after you've worked in maintenance on one large project that designed everything to be pure unless there's a very compelling reason not to, you start to really miss the feature when you go back to projects in languages without it.
- catnaroek 13y agoAgreed there. But, on the other hand, D misses out on statically checked resource management, and IMO that is more important than purity in the niche Rust and D are targeted at (systems development). Of course, nothing prevents a language from having both. :-)
- WalterBright 13y agoPurity has a large advantage when writing concurrent code, as pure functions don't need to be synchronized. This is why D has enforced purity (via an attribute) rather than inferred purity.
- kibwen 13y agoD and Rust are vastly different beasts. Here's why none of the arguments from that page apply to Rust: > Pure means your function does not use or change mutable > global state except what is available from the > arguments. If in addition the arguments are not > mutable, a function is called “strongly pure”. In Rust, immutability is the default, and you must always opt in to mutability. A function's type signature will always make it apparent as to which arguments are mutable and which are not. If you declare a variable as mutable but then never mutate it, the compiler will pester you to make it immutable. Furthermore, Rust is so hell-bent against global mutable state that even reading global state that is declared as mutable requires one to wrap the code in an `unsafe {}` block. > Nothrow means your function will never throw an > exception. Rust does not have exceptions, and prefers to use returned algebraic datatypes and non-unwinding conditions to handle errors. > Safe means your function cannot break the type system > via unsafe casts or inline assembly. As alluded to earlier, all functions in Rust are safe by default. An explicit `unsafe {}` block is required to do stuff like inline assembly and type transmutation, and functions themselves can be marked as `unsafe` in order to force callers to use an unsafe block when calling them.
- christianpbrink 13y agoSince this author is reasoning through proposed purity in Rust by comparing it with purity in Haskell... - I personally have never felt constrained by Haskell's purity. During development I use `Debug.Trace` to do any debug printing I need to do in pure functions, and I design a program so that in production code I can do appropriate logging before and/or after any calls to pure functions. - Managing monad stacks in Haskell isn't that tricky. This is the kind of thing that people get scared away from not because they actually tried to learn it and couldn't, but because people make it out to be so hard. - The Haskell STM example the author links to is actually really simple, especially in terms of monad stacks. It seems dense at first glance only because of the `forkIO`, `timesDo`, and `milliSleep` calls, but you would need these functions' logical equivalents no matter what language you wanted to implement this example in.
- twoodfin 13y agoI am a Haskell outsider, but I've heard SPJ say several times that laziness is what enabled/forced Haskell to stay pure. My understanding is that even advanced Haskell programmers struggle with predicting the runtime cost in space and time of the laziness that bought purity. That unpredictability is highly undesirable in a systems language. There are certainly ways to have purity without laziness, but it's not straightforward for Rust to adopt the Haskell model, I think.
- catnaroek 13y agoIt is perfectly feasible for a strict language to be pure, even if most strict languages are as a matter of fact not pure. What (I understand from what) SPJ said is that laziness is completely unworkable without purity, and in this sense laziness forced Haskell to remain pure.
- christianpbrink 13y agoI think catnaroek has this right. Neither that nor my original comment is meant to suggest that it would be straightforward for Rust to borrow from Haskell. Just that the post's comments on Haskell seemed to reflect misconceptions.
- hawkharris 13y agoThis discussion is very interesting to me because I am just starting to learn about pure functions and functional programming in general. Coming from an OOP background, I am used to bundling functionality into objects that loosely represent real-world people, places or things, but I'm starting to experiment with using these more abstract "pure" methods. For example, I'm working on a GPS-based JavaScript game that uses a "check-in" system to encourage users to travel spontaneously. Initially, I designed a tightly encapsulated "Check-in" object responsible for fetching & interpreting users' locations. Inspired by reading about functional programming on HN and elsewhere, I'm trying to break up some of the general geo-processing logic such as looping, array filtering, map/reduce, etc., into general functions with predicable results that can be used throughout my application. It's definitely a different way of thinking that I'm not entirely comfortable with yet, but I can see how it allows for faster, more efficient code. I have been able to replace 50-line code blacks with 10-line blocks that are more efficient and - believe it or not - legible.
- kibwen 13y agoI just want to reiterate something that I say in a child comment in this thread: thanks to its thoughtful design, many of the advantages of purity are less appreciable in Rust than they would be in, say, C++. In Rust, everything is immutable unless you opt-in to mutability. Looking at a function signature will tell you which of its arguments can possibly be mutated. Global mutable state is highly discouraged, by requiring you to wrap code that accesses global mutable state in a dreaded `unsafe {}` block. As for optimization capabilities, LLVM itself can (AFAIK) infer when functions are "pure" and mark them as `readonly` or `readnone` (not sure what the limitations to this approach are, though). So don't make the mistake of thinking that Rust is a free-for-all due to the long-ago removal of its `pure` keyword. Many (dare I say a majority?) of the nice features of purity are merely provided by different mechanisms (for those use cases that Rust does not satisfy, Graydon's own explanation should suffice regarding their enormous added complexity in a language that is not Haskell).
- cmrx64 13y agoIndeed, we mark them as readonly/readnone when we can.
- maxcan 13y agonice to see a thread I started months ago on the HN homepage