Live data from Hacker News

How I went about learning Rust

eli.thegreenplace.net

281–290 of 303 posts

Re: How I went about learning Rust

#281

Earlier quoted context omitted.

How is this fundamentally different from raw pointers?

Not OP It serializes better, it's memory safe, it can be much faster in performance terms, you can get better memory usage if you're holding a lot of "pointers" because the indexes don't need to be 64 bits.

But you lose all ownership tracking / safety that Rust is famous for.

I just can't help but wonder what it means for that paradigm, when the most popular answer to "how do I model my entities in safe Rust" is basically "backdoor the safety".

Re: How I went about learning Rust

#282
post #39

Earlier quoted context omitted.

Yes. Rust is for what you'd otherwise have to write in C++. It's overkill for web services. You have to obsess over who owns what. The compiler will catch memory safety errors, but you still have to resolve them. It's quite possible to paint yourself into a corner and have to go back and redesign something. On the other hand, if you really need to coordinate many CPUs in a complicated way, Rust has decent facilities…

Noob question - What does go lack that makes it hard to write your multi threaded meta verse viewer

Any sort of safety: https://eng.uber.com/data-race-patterns-in-go/

Go's concurrency model is bog-standard shoot your foot off shared memory.

A channel is not magic, it's a multiple-producer multiple-consumer queue, you can unwittingly send a pointer over it (or a pointer-ish, like a hashmap) and boom you've got unchecked concurrent mutations, and in Go that even opens you up to data races (memory unsafety).

And because channels are slow, it's common to go down the stack, and hit further issues of mis-managing your mutexes or waitgroups, to say nothing of spawning a goroutine by closing over a mutable location.

You can do it right, in the same way you can do it right in C, C++, Java, Ruby, or Python. And arguably it's more difficult in Go because it drives you significantly more towards concurrency (and spawning tons of goroutines) without really giving you better tools to manage it (the only one I can think of is select).

Re: How I went about learning Rust

#283

Earlier quoted context omitted.

I think rust is the new haskell. After spending 7 months learning it, I can say I really enjoy the language, but there's no job in it and in my opinion, they take academic decisions that make the language way more complex than it should. Also, the community is toxic. For example, generics in Go were criticized by some, praised by others. You have the feeling that you can freely share your opinion in the go community…

> Also, the community is toxic. The Rust community has been the friendliest PL community I've seen so far.

There's similar thing about Haskell. I often hear stories like "wow, I'm so glad I found Haskell, the community has been so friendly and helpful" and then other stories like "I tried Haskell and I liked the language but it was just such a toxic community". I don't really know what to make of this, and at this point I just put it down to the infinite variety in human experiences and preferences.

Re: How I went about learning Rust

#284

Earlier quoted context omitted.

Since you're coming from a NodeJS background, you'll want to pick up an introductory textbook about C as well. Rust implicitly relies quite closely on the C machine model, and introductory books about Rust (such as "The Rust Programming Language") don't do a very good job of conveying the nitty-gritty details of that model to novice coders. This is a pretty nasty pitfall when trying to code in Rust, and it's importan…

Reading an entire book on C is probably overkill. This video is probably enough for most beginners: https://www.youtube.com/watch?v=rDoqT-a6UFg

Wow thank's for that link. Bridged a few gaps for me between what I remember from c++ and what I've been learning in rustlings.

Re: How I went about learning Rust

#285
post #176

Earlier quoted context omitted.

For me it was the web-of-pointers strategy I had to unlearn. A child object keeping a pointer to its parent is misery in Rust. It forces you to either make the child completely independent or really prove the parent will be around until the child disappears. 90% of the time this is dumb overhead, but 10% of the time it found a bug in some edge case, so I learned to appreciate it as a tough teacher, and my designs got…

>"90% of the time this is dumb overhead, but 10% of the time it found a bug in some edge case, so I learned to appreciate it as a tough teacher, and my designs got better for it." Sounds kind of like Stockholm syndrome

And you sound like you are part of the reason why we still have exploitable null-pointer bugs in 2022. Imagine a structural engineer that would say "all that static and dynamic analysis is dumb overhead 90% of the time, so I am going to skip it". Imagine an electrical engineer who would go like "all these wire gauge calculations are exhausting, 90% of the time my installations don't catch fire"

Seriously, I sometimes wonder what is wrong with the whole field of software development.

Re: How I went about learning Rust

#286
post #251
post #220

Earlier quoted context omitted.

Ok. But noticed what I said. *Things* that are easy in one OOP should be similarily easy to express in other OOP language. Counter example: Html5 DOM.

Counter example of what? A graph representation of nodes based on JavaScript object model? Fine, https://rustwasm.github.io/docs/wasm-bindgen/examples/dom.ht...

Yeah but if you dig deeper you'll notice it is riddled with unsafe, casts and Deref misuse.

It's a brittle simulation of Inheritance. To transform a saying "Just because you can write Ada in C, doesn't make C Ada".

Re: How I went about learning Rust

#287
post #158

Earlier quoted context omitted.

I'd consider something OOP if it has the same expressive power i.e. things expressible in OOP languages are easily expressible in another OOP language as well. And for Rust that's not the case. Otherwise you end up with Haskell is an OOP language.

> I'd consider something OOP if it has the same expressive power i.e. things expressible in OOP languages are easily expressible in another OOP language as well. That doesn't even make sense on its face. There are things which are trivially expressible in Smalltalk and I'm not sure even possible to wrangle in Java.

That's because Smalltalk OOP isn't the OOP in the sense Java is, some refer to Java Style as Class oriented Programming.

Re: How I went about learning Rust

#288

Earlier quoted context omitted.

Rust actually supports most OOP features, with the main exception of implementation inheritance. And implementation inheritance is a nasty footgun in large-scale software systems (search around for: "fragile base class problem"), in a way that just doesn't apply to simple composition and pure interfaces (traits). So it's hard to fault Rust for including the latter and not the former.

For me it was the web-of-pointers strategy I had to unlearn. A child object keeping a pointer to its parent is misery in Rust. It forces you to either make the child completely independent or really prove the parent will be around until the child disappears. 90% of the time this is dumb overhead, but 10% of the time it found a bug in some edge case, so I learned to appreciate it as a tough teacher, and my designs got…

Which way did you go, (1) not use pointers from child to parent (functional programming approach), or (2) kept using such pointers but made it work? Your first paragraph sounds like (1), but the second sounds like (2).

If it was (2), it sounds like you made it work without unsafe code? Can you share some code?

Re: How I went about learning Rust

#289
post #286
post #251

Earlier quoted context omitted.

Counter example of what? A graph representation of nodes based on JavaScript object model? Fine, https://rustwasm.github.io/docs/wasm-bindgen/examples/dom.ht...

Yeah but if you dig deeper you'll notice it is riddled with unsafe, casts and Deref misuse. It's a brittle simulation of Inheritance. To transform a saying "Just because you can write Ada in C, doesn't make C Ada".

Post Scriptum: one way to prove this is that we could use https://www.youtube.com/watch?v=43XaZEn2aLc as a base.

How to prove.

Assume that we add struct inheritance to Rust (it looks similar to JS) - call it RustInh.

Does adding inheritance to Rust increase expressive power? If yes, then right now Rust can't express OOP concept as inheritance. I.e. is there a C[RustInh] = C[Rust].

And way to prove it is to look at Deref anti-patterns https://github.com/rust-unofficial/patterns/blob/main/anti_p...

I'm still not sure that fully captures my intuition of easy to write.

Re: How I went about learning Rust

#290

Earlier quoted context omitted.

I'm in the same position as OP and was wondering the same thing; finding a job using Go. Is the bloat that you see the most related to error checking? If not what else is it?

The bloat is mostly related to mocking and making a fake client for everything for unit tests, and the practices you have to follow to make that actually work. In Python or Java, you can do something like: class: f1(): self.some_api_call() test_class extends class some_api_call(): In go, you cannot do this. Fair enough, but everyone writes object-style code because it's easier and there's less boiler plate. If you do…

I'm reposting your message with the code formatted as you had entered it (the original white space use is still visible in the html source code; I've just indented it so that HN recognizes it as preformatted):

---

The bloat is mostly related to mocking and making a fake client for everything for unit tests, and the practices you have to follow to make that actually work.

In Python or Java, you can do something like:

    class:
      f1():
        self.some_api_call()
        

    test_class extends class
      some_api_call():
        
In go, you cannot do this. Fair enough, but everyone writes object-style code because it's easier and there's less boiler plate. If you do this, you can't write tests.

Instead, you have to do something like:

    class:
      apiMethod = nil
      f1():
        self.apiMethod()
        
And assign apiMethod when you create the instance of the object; there are no constructors because they're not traditional objects, you need to create a factor method (boiler plate) or build the struct by hand (boiler plate). None of this is terribly challenging in and of itself, but if you work on large code bases, nobody did this because it's extra work, and now you have to refactor it because you want to make a change to the critical business logic and prove you're not introducing a regression (a constraint the l33t coders before you didn't have because they get to go fast and break things).

And finally, often times the thing you need to mock is in someone else's package, and it doesn't implement an interface, or the thing you need to mutate is private, etc, etc. You end up need to mock half of a package sometimes.

None of this is insurmountable, but when you do it day in and day out for years like I did, it's a real slog, and it sucks your soul out of your body. It wasn't uncommon for me to spend literally 20x as long refactoring and implementing tests as it was to ship features. If you look at some unit tests from large go projects, you'll see stuff like struct{struct{struct{struct{...}}}, struct{struct{struct{...}}}} because so much stuff needs to be mocked up. And since interfaces are disjointed from classes, you won't know with certainty which methods you need to needlessly mock for your mock class until you try to compile, because the interface is defined somewhere else and not attached to a base class, it's just a definition floating out there in the source somewhere.

Post reply on HN