Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. GPT-6 Sol and Luna(openai.com)
    535comments
  2. Claude Opus 5.5(anthropic.com)
    744comments
  3. Microsoft killed FoxPro in 2007. Anyway, here's FoxPro revived(foxscript.org)
    73comments
  4. OpenAI GPT–6 Astra breaks Enigma message that has resisted solution since 2005(cryptocellar.org)
    350comments
  5. 'We hacked the FBI:' Hackers say they have data on all FBI employees(404media.co)
    181comments
  6. SAML: A fractal of bad design(trailofbits.com)
    60comments
  7. Claude Opus 5.5 Intelligence, Performance and Price Analysis (Max)(artificialanalysis.ai)
    55comments
  8. WordPress: Unauthenticated path traversal leading to conditional RCE(github.com/wordpress)
    72comments
  9. Unreal Agent(unreallabs.ai)
    59comments
  10. ReBarUEFI: Resizable BAR for almost any UEFI system(github.com/xcuri0)
    discuss
  11. An update on how we confirm your age group on Discord(discord.com)
    34comments
  12. Native apps written in TypeScript and CSS(github.com/geastack)
    16comments
  13. How did AMD Ryzen get 50% faster in two years?(lemire.me)
    48comments
  14. Did OpenAI solve the wrong Navier-Stokes problem?(scientificamerican.com)
    34comments
  15. MUNI Heritage Weekend in San Francisco(lawrence.lu)
    35comments
  16. The UV index is not the warm sensation of sunlight on bare skin(asciitweezers.com)
    34comments
  17. Markdown in /src(htmx.org)
    31comments
  18. OpenAI is well positioned to fast-follow Jev(arcturus-labs.com)
    178comments
  19. Show HN: JevBench, a reproducible benchmark for typed decision models(benchmarkheaven.com)
    7comments
  20. The trouble with 'ntile()'(djnavarro.net)
    discuss
  21. Show HN: Training a model to identify AI web content from structure alone(arxiv.org)
    8comments
  22. George Lucas Returns to Earth, Bearing Gifts(commonedge.org)
    29comments
  23. 16-bit Intel 8088 chip (c. 1985)(allpoetry.com)
    13comments
  24. Rabbit Hole: Minimum L-seams(fractalkitty.com)
    5comments
  25. People hooked on vapes try a new way to quit: cigarettes(bloomberg.com)
    65comments
  26. Pentagon says overreliance on AI contributed to missile strike on Iran school(bloomberg.com)
    160comments
  27. Apple has added persistent 'ads' to iOS, and it's driving users crazy(techradar.com)
    426comments
  28. There's a high chance of devices being sold with GrapheneOS preinstalled in 2027(grapheneos.social)
    103comments
  29. Launch HN: Coverage Cat (YC S22) – Umbrella insurance via your personal agent(coveragecat.com)
    19comments
  30. The JavaScript Midlife Crisis(maroun-baydoun.com)
    7comments

Why Rust ditched pure functions

83 pointsby 12y agothread.gmane.org
27 comments
12y agoHN ↗

You would only use D if you considered it great.

12y agoHN ↗

There 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.

12y agoHN ↗

Agreed 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. :-)

12y agoHN ↗

Purity 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.

12y agoHN ↗

D 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.

12y agoHN ↗

Since 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.

12y agoHN ↗

I 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.

12y agoHN ↗

It 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.

12y agoHN ↗

I 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.

12y agoHN ↗

OTOH, I am not really sure I would want STM in a systems language. It is a little bit too magical, taking into account all the possible retries of a transaction. Perhaps something based on the pi calculus would be a better fit.

12y agoHN ↗

I think the magic factor is a key point. Haskell is by design a very high-level language. Things like STM and other "magic monads" allow a lot of stuff to happen under the hood, with guarantees of correctness because of other constraints on the language, but not necessarily a great degree of control of what exactly is happening. Rust, on the other hand, is meant for low-level programming and as such tends to be very explicit about what it's doing at every step. I think Rust and Haskell happen to share some similarities but ultimately they're just not designed for the same purpose. Nothing wrong with learning both :)

Side-note, Idris is a Haskell-inspired pure language which is strict by default. It's designed from the outset to be useful for systems programming, and also has some cool theoretical ideas like dependent types. It might be worth looking into for those who wish Rust was more like Haskell, or vice-versa.

12y agoHN ↗

Sadly, AFAIK, Idris does not have linear types out of the box. I am aware that you can prove you are properly releasing your resources using dependent types, so technically speaking there is no loss of expressivity. However, having the compiler do the checking and enforcement automatically is a huge usability win in my book, especially since juggling with the lifetimes of various resources is such a common task in systems programming.

That aside, Idris looks very promising for verified application development.

12y agoHN ↗

I'm a Haskell newbie, and when I test a program and it shows a laziness-related space leak, I just put strictness annotations on the parameters I suspect of generating large unevaluated thunks. This has always made the issue go away so far.

12y agoHN ↗

But, would you not agree that it would be really nice to have separate strict vs. lazy types? It would bloat the syntax a little bit (e.g., Coq needs separate Inductive vs. CoInductive, Fixpoint vs. CoFixpoint keywords) but the benefits in terms of not having to find space leaks via debugging and profiling would be enormous.

12y agoHN ↗

There are several libraries that do distinguish between strict and lazy types. containers [1], for example, separates strict Maps and IntMaps.

That said, introducing new syntax to annotate strictness is far more troublesome than separating strict types from lazy types at the module level, where switching between the two is a comment away:

       import qualified Data.Map        as M
    -- import qualified Data.Map.Strict as M

Introducing syntax would make switching between the two far more painful.

[1]: https://hackage.haskell.org/package/containers

12y agoHN ↗

When I say sometimes I need strictness, I really mean it. (Without ugly hacks like deepseq, that is, because I am fundamentalistically opposed to hacks.) WHNF does not quite cut it. This is not to say that I dislike laziness. I want first-class support for both strictness and laziness.

When you come to think about it, a separation of strict types and lazy types makes perfect sense. For example, I want to foldl on lists (strict) but foldr on streams (lazy). I do not want to accidentally use the wrong operation on the wrong type. it is tiny details like these which make a type system helpful for guaranteeing correctness and improving performance.

So, if strictness and laziness are both useful and distinct from one another, why not provide both as core language constructs? Why do languages always have to be biased towards one of them?

12y agoHN ↗

I am confused as to what this has to do with the author's point. He isn't saying purity is hard to use, he is saying the features of Rust make a truly pure function hard to define.

The author seemed to imply that pure if easily used would be a great feature, he just doesn't think that the language that Rust defines is a good match due to the ease of tainting a function.

12y agoHN ↗

I agree that that's his point. I just wanted to put in a plug for Haskell being appropriate for many, many application development use cases, because there's a misconception that it's only useful in mathy or academic scenarios.

Again, this guy didn't argue as much; he basically just said it's reasonable for someone developing systems code, code with I/O on every line or something, to conclude she isn't going to be able to reap the benefits of writing pure code in Haskell.

But I think a lot of folks read anything of the form "Haskell isn't appropriate for use case X" as "Haskell's generally impractical". So I wanted to share a different perspective.

12y agoHN ↗

All the Haskell hate I have heard isn't on the language but on developers, not trusting everybody to properly implement the paradigm shift and all that.

12y agoHN ↗

This 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.

12y agoHN ↗

I 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).

12y agoHN ↗

Indeed, we mark them as readonly/readnone when we can.

12y agoHN ↗

nice to see a thread I started months ago on the HN homepage

12y agoHN ↗

Has anything changed in your thinking since posting the original mail?

12y agoHN ↗

Not sure. I've been less involved with Rust in the past few months.