The type system is nice with the algebraic data types, but lacking the higher orderedness of languages like Haskell, it just seems sad.
So basically, to me it seems like you're getting the worst of both worlds. You don't get the freedom of c/c++ and you don't get the actual type safety of a language like Haskell (refcell kills the notion of compile time checking).
Realistically what needs to happen is some system for circular references like Haskell has (let bindings).
The benefit is that for almost all code you get mutability xor aliasing, which I think is incredibly important to achieving correctness at scale.
A doubly-linked list enters the chat...
Rust's stdlib comes with one: https://doc.rust-lang.org/std/collections/struct.LinkedList....
[1] There are some cases where they're useful, e.g. when amortized O(1) append is not enough and you want actual O(1) append. But this matters to almost no one.
Umm... how do you propose implementing a queue or a stack cpu-efficiently and memory-efficiently using vectors?
For a stack, just use a regular vector. Pushes are amortized O(1), and pops are O(1).
For a queue, a ring buffer backed by a vector. (This is how VecDeque in Rust's stdlib works.) Again, enqueue is amortized O(1) and dequeue is O(1).
Even if you do need to use a linked list, it's generally better to depend on someone else's implementation than write your own.
I am the someone else who writes that, often enough…
All y'all forget that behind your cute libraries and abstractions stands someone who wrote them in C or assembly…
A lot of the point of Rust is to make a few people do the hard work of writing some complex data structure in unsafe code, and let everyone else reap the benefits.
> doubly-linked lists
Synonyms for application developers.
The point is that you don't have to do that for all of your data objects, unlike other languages that use refcounts and dynamic checks under the hood. Most alloc/dealloc in Rust can be dealt with via simple RAII.
data DLList a = DLList a (DLList a) (DLList a) | End
make_dllist :: [a] -> DLList a
make_dllist = go (\_ -> End)
where go mkPrev [] = mkPrev End
go mkPrev (x:xs) = go (\next -> let me = DLList x (mkPrev me) next in me) xs
No need for IORef. Too many people misunderstand the meaning of 'let' in Haskell. It doesn't mean what you think it does. It defines, not assigns. In rust, let 'declares' and assigns in one go. It does not define.