Hacker News new | past | comments | ask | show | jobs | submit login

I would specify grandparent's claim a bit more - certain kind of code, frequently used in ML style without a GC is hard/impossible.

E.g. heavily recursive data structures may not be a best fit (also not the best fit for the CPU).

Rust has definitely grown out its own style, which is more of a "strongly typed FP with local-scoped imperative parts", elegantly combining ML's strengths with C/C++-style performant patterns.






Haskell is a pure FP language with what amounts to imperative EDSL's in the form of the ST, STM, and IO monads. Haskell has its own issues, but is that approach of an FP outer layer with embedded imperative sections such a bad approach? If you wanted to not have a GC, you could use just the imperative fragment.

> If you wanted to not have a GC, you could use just the imperative fragment.

I think it would be quite hard in practice to make Haskell not dependent on a GC. What Haskell is most obviously lacking at present is a more elegant story of how to interface "strict" and "lazy" parts of a single program. PLT researchers and logicians have been exploring these questions for some time, coming up with notions such as "polarity" and "focusing", views of some types as "naturally strict" (such as tagged unions), others as "naturally lazy" (such as functions) with still others coming in both strict and lazy varieties ("product" or record types), and elementary operators to shift between "strict" and "lazy" uses of any type - but the practical implications of these concepts in real-world programming language are still unclear. Haskell would make an ideal testing ground as such.


I think what they mean is that you can program without a GC in a GC'd language, but it is much harder to do it the other way around.

I think it's just not feasible to totally avoid the GC in a language such as Haskell. It's inherently involved in anything that would require heap-allocated data in C/C++, and more besides. For example, Haskell does not have a borrow checker, so it needs the GC to ensure that closures' environments will stick around for as long as they're needed. (The Rust approach is the opposite by default - the compiler errors out whenever a closure will outlive the established lifetime of its referenced environment. You can always use Rc<> or Arc<> to have multiple owners that will all keep a program object alive as needed, but it's not the default.)

It's quite possible to program imperatively with no GC, no borrow checker, and no memory leaks in Haskell or in other languages such as Ada. The main technique is to simply not allocate or free anything, but instead just use fixed buffers, or objects that you have allocated before entering the no-GC region. In Haskell and other GC'd languages, GC generally triggers on allocation, so no allocation = no GC.

Back when memory was scarce this was a well known practice in Lisp. You'd just adopt an ugly style in the parts of the program where performance was important, doing destructive updates instead of consing in order to avoid GC'ing in those parts. Rust's contribution (the borrow checker) is in letting you make more use of dynamic memory allocation while still not using a GC or programming unsafely.

You might look at this presentation for more: https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced...


I tried writing simple imperative programs in GHC using the IO and IORef types, and the programs ran about 1000 times slower than analogous programs in C.



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: