News for hackers. Stuff that matters.
Re:Fundamentals of Garbage Collection by creata on Saturday July 12, 2025 @03:30AM (#44540061)
You can just forbid cyclic data types - e.g., require every struct type to only reference types that have already been defined. I can't think of any languages that do this.

Another solution is to make things immutable (like Erlang), or "as-if" immutable (like Koka), which guarantees that data can only point to things that have already been defined, preventing cycles.* Erlang uses this to simplify generational collection - because old data can't point to young data, it doesn't need a card table or anything like that.

I think it's perfectly possible to have a general purpose language without cycles: you can just use integer indices into an array instead of pointers if you want cyclic data structures. This is common in Rust, when people want to avoid the overhead of reference counting, but don't want to use unsafe code.

* A hidden assumption here is that the language is eagerly evaluated. There are languages like Haskell that have immutability and cyclic data structures.

Re:Fundamentals of Garbage Collection by asplake on Saturday July 12, 2025 @03:55AM (#44540174)
Even with cyclic relationships between types, immutability makes cycles within instances difficult (without laziness anyway). A syntax tree would be a good example.
Re:Fundamentals of Garbage Collection by creata on Saturday July 12, 2025 @03:58AM (#44540192)
Yes, either is sufficient, I think.
Re:Fundamentals of Garbage Collection by xscott on Saturday July 12, 2025 @04:36AM (#44540354)
Yes, and the nice thing about doing it with immutability is you can still have recursive types to build linked lists, trees, and/or dags. From there you can build hash-array-mapped-tries, finger-trees, and so on, giving you friendly dict/list or JSON style data structures.
Re:Fundamentals of Garbage Collection by daxfohl on Saturday July 12, 2025 @01:14PM (#44543420)
Couldn't you make lazily evaluated code in erlang too, even if it's not lazy by default like Haskell? You'd just need function pointers, right? Or is that not enough?
Re:Fundamentals of Garbage Collection by creata on Saturday July 12, 2025 @02:34PM (#44544013)
Haskell can have circular references because its laziness is implemented with thunks, which have a mutable cell in which to store the computed value so that terms don't get evaluated more than once. Here's a Haskell function that makes a circular linked list:

    -- circular linked list with one item
    repeat x = let xs = x:xs in xs
Here's a rough equivalent in JavaScript that doesn't use thunks, just functions:

    function repeat(x) {
        function xs() {
            return [x, xs]; // [first, rest]
        }
        return xs;
    }
The Haskell version has a cycle because, after evaluation, `repeat x` will be a circular linked list, but all the "lists" we create in the JavaScript code above are just the closure `xs`.

For completeness, here's a JavaScript version that uses thunks:

    class Thunk {
        constructor(f) { this.f = f; }
        get() { if (this.f) { this.v = (this.f)(); delete this.f; } return this.v; }
    }

    function repeat(x) {
        let xs = new Thunk(() => {
            return [x, xs]; // [first, rest]
        });
        return xs;
    }
If you try calling `x = repeat(1); x.get()`, you can see that we get a circular list.