
Comparing Rust and JavaScript Ergonomics with a Simple Linked List - codesections
https://www.codesections.com/blog/javascript-vs-rust-linked-list/
======
jerf
Heh, I feel like "someone" ought to write the Big List of Bad First Projects
for This Language, e.g.:

Go/Erlang/Elixir: "Testing" the concurrency by parallelizing the addition of
an array of integers via some sort of sending single integers over messages,
or in the worst cases, literally spawning entire processes/goroutines/etc. to
add two ints (and then wondering why the concurrent program fully consumes all
eight CPUs but is still twenty+ times slower).

Go (as of this writing): Immediately trying to implement a generic data
structure.

Rust: Complicated pointer-type data structures like linked lists, or goodness-
forbid, doubly-linked lists.

Haskell: Starting right off by trying to implement an in-place sorting
algorithm.

Python: Taking your C numeric algorithm and converting it into pure Python
(and then being shocked at the performance).

Criteria for my inclusion is that I personally have seen each of these many
times.

It's not that these tasks are necessarily impossible, or even necessarily all
that hard when you know what you are doing, just that they are _bad first
tasks_ , but they seem to tempt people for some reason. For example, someone
reading a Python tutorial hasn't heard of numpy, if you're just learning Rust
immediately learning how to break the rules you don't fully understand yet
isn't the best use of your time, etc.

In this particular case it all turned out OK in the end, but it often doesn't
go this well. :)

~~~
kbp
> Complicated pointer-type data structures like linked lists

If a singly linked list is a complicated data structure then what's a simple
one?

~~~
tetromino_
A heap would be simple.

Rust's ownership rules make it hard to implement data structures composed of
nodes that own references to other nodes. (This includes linked lists, binary
trees, and naive implementations of graphs.) There is a reason for this - it's
rather tricky to implement such data structures _truly safely_ in any language
without introducing hidden assumptions, that's why they are so frequently seen
in interview questions for java and c++ coders.

~~~
SilasX
The difficulty of such interview questions doesn't stem from the problem of
ensuring memory safety, but stuff like "finding the form of the recursion you
need".

------
pornel
Oh no, anything but the linked list.

Real-world Rust programs don't implement linked lists. There's LinkedList in
libstd if you really wanted one, but in modern architectures cache locality is
so important that almost always some other data structure is a better choice.
Rust's standard library and crates.io have plenty of containers to choose
from.

Linked list is popular because it's a CS101 topic, and because C is so barren.
When you don't have any containers in stdlib, dependency management is hell,
and due to lack of generics any 3rd party implementation will be either
inefficient or full of macros, only then low-effort hand-rolled linked list
seems like a sensible choice.

~~~
AndyKelley
Linked lists have a really important property: each node can be owned by a
different allocator. You can have a node which is stack memory, linking to a
node which is heap allocated with libc malloc, linking to a node which is
arena-allocated per frame of a game engine, linking to a node which is global
static memory. And you can set this up in a maintainable, sensible way.

Linked lists are incredibly useful when an object can exist in a predetermined
set of lists, and allocation failure must not be possible when adding the
object to a list.

~~~
duneroadrunner
Yes, and in C++, linked lists can retain this property and be implemented in a
memory safe way using non-owning reference-counting smart pointers[1].

Many defend the use of unsafe Rust in cases like these, in part by asserting
that C++ would have the same (un)safety issue. I don't think that's right. A
C++ implementation would not have to use (unsafe) raw pointers, or (expensive,
intrusive) owning pointers from the standard library.

I think C++ has the advantage in cases like these because of the
aforementioned non-owning reference-counting smart pointers. I don't think the
same type of pointer/reference can be implemented in Rust (as it would need a
constructor), but it's not immediately obvious to me that such a reference
type couldn't be added to the language as an intrinsic element (like _Rc_ ). I
think such an element is dearly missing from the Rust language. I suspect that
adding it would make the language safer and easier to use.

[1] shameless plug: [https://github.com/duneroadrunner/SaferCPlusPlus#norad-
point...](https://github.com/duneroadrunner/SaferCPlusPlus#norad-pointers)

~~~
foota
I'm not a Rust expert, but aren't you describing [https://doc.rust-
lang.org/std/rc/struct.Rc.html](https://doc.rust-
lang.org/std/rc/struct.Rc.html)?

------
Shebanator
I'm baffled how the author could look at these code samples and say that the
Rust and Javascript versions were mostly identical.

------
cryptonector
> What's more, according to that book, there simply isn't a good way to
> implement this structure in safe Rust. The way to go is to venture into
> unsafe Rust.

Noooo, you don't want to do that. Just give up on circular references, doubly-
linked lists, and so on. Use different data structures and work around the
[perceived] downsides of not having the data structures you're used to in
Lisp, C, ECMAScript, ... You'll find it pays off.

See this HN post for more:
[https://news.ycombinator.com/item?id=18098239](https://news.ycombinator.com/item?id=18098239)

------
desireco42
If I had a dollar each time I needed to use and implement single linked
list... (I wouldn't have many dollars)

~~~
codesections
Yeah, I 100% agree that they're not good examples of the sort of problem
you'll need to solve in a given language.

That said, I still like them—at least enough to write this one,
anyway!—because they're small, self-contained, and dive deep enough into the
language internals that you can (start to) see the differences in the "world
view" of the language. (Compare them to something like Advent of Code
challenges—those are also small, self-contained, and unrealistic to real
programming, which makes them pretty similar. But many of the early ones don't
get deep enough into the language to really get a feel for how the language
pushes you to think/approach problems)

------
offbytwo
>Rust is pretty

>Of course, you might feel differently, but one of my biggest takeaways from
all of this side-by-side code is that Rust is clear, expressive

As someone who doesn't use either of these languages, I couldn't disagree
more. The Javascript was intuitive and immediately made sense, while the Rust
code gave me a headache.

------
codezero
I'd like to see this comparison, but with TypeScript instead of JavaScript.
I'm sure it will still be better than Rust, but it seems like the main thing
making Rust really awkward here is the memory safety.

------
simplify
Can someone explain why raw_tail was necessary in the add_to_tail function?

~~~
codesections
We needed to use a raw pointer there because of Rust's ownership system.
Here's the short version: Rust wants everything to have exactly one owner and
enforces that by disallowing multiple mutable references to the same data (or,
for that matter, multiple references to the data if even one of the references
is mutable).

But that doesn't play too well with linked lists. You need to have a reference
to the tail node from the previous node _and_ have a reference from the list
itself. And you need to be able to mutate the tail node, so you can't just do
that with immutable references.

Now, rust does have some safe ways to solve that type of problem (Arc and
RefCells are two). But it turns out that the best way to solve it here is to
make the jump to `unsafe` code since we can guarantee the invariants that keep
it from being unsafe in practice.

------
Scarbutt
Found the JS implementation horrible, he could just have use plain objects
(would be fair since he used a plain struct in rust) and functions instead of
'this' everywhere.

~~~
codesections
I'd be interested to see what you have in mind/hear why you think that would
be a big improvement on the way I had it set up. (I'll admit to not putting a
ton of thought into the JS version, though)

