4 ms·
Realistically, other than cool factor I'm having a real hard justifying the use of rust. It either devolves into using reference counting (fine but we have lots
by anon291 3y ago
Realistically, other than cool factor I'm having a real hard justifying the use of rust. It either devolves into using reference counting (fine but we have lots of languages that do that without borrow checking), or dynamics (i.e refcell).
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).
- empath-nirvana 3y agoThere's so much you can do in rust without messing with any of that, and the only time you have to get deep in the weeds arguing with the compiler is _exactly_ the sort of code that you _should_ be spending a lot of time carefully thinking about. That C allows you to write that code without thinking about it much is _not_ a benefit to using C.
- anon291 3y agoComing from a mostly Haskell background, I assure you I think about my code a lot.
- jeremyjh 3y agoI don't see what let bindings have to do with solving the circular reference problem, those are just local bindings. A Haskell doubly-linked list would use IORef, but no one would ever actually do that.
- anon291 3y agoHaskell doubly linked list: 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.
- sunshowers 3y agoData structures with circular references are so incredibly rare in practice. I've occasionally needed to use a graph (sometimes even a cyclic one), and petgraph with integer indexes works fine for that. Other than that, I've been writing Rust full-time for over 7 years and really not needed them. The benefit is that for almost all code you get mutability xor aliasing, which I think is incredibly important to achieving correctness at scale.
- dmitrygr 3y ago> Data structures with circular references are so incredibly rare in practice A doubly-linked list enters the chat...
- sunshowers 3y agoDoubly-linked lists are incredibly rare, few people should ever use one and even fewer people should ever write one. In almost all cases vectors are better [1]. Rust's stdlib comes with one: https://doc.rust-lang.org/std/collections/struct.LinkedList.html 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.
- dmitrygr 3y ago> Doubly-linked lists are incredibly rare, few people should ever use one Umm... how do you propose implementing a queue or a stack cpu-efficiently and memory-efficiently using vectors?
- sunshowers 3y agoIn almost all cases, it is better to use a vector for both those data structures. Cache locality is king, memcpy is blazing fast, and pointer chasing is generally pretty bad for performance. 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.
- zozbot234 3y ago> It either devolves into using reference counting (fine but we have lots of languages that do that without borrow checking), or dynamics (i.e refcell). 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.