7 ms·
Agree completely. For a bit of my own story, a year+ ago I had the option to write a project in Rust and evaluated it vs Go. Long story short, I tried rust, and
by asdkhadsj 8y ago
Agree completely. For a bit of my own story, a year+ ago I had the option to write a project in Rust and evaluated it vs Go. Long story short, I tried rust, and it was a massive headache and I failed. We used Go (as I had been for ~4 years).
Fast forward to ~2 months ago, a work project dictated tight control over memory which, while possible in Go, had me looking at alternatives. I decided to give Rust another try. This time it wasn't just an evaluation, it was needed to work so I bought and Rust book and spent some after hours time learning/etc.
This time, Rust has been an absolute joy. I have no understanding why last time was so painful, and this time it's been so amazing. Maybe it was the book[1]? Maybe it was just a 2nd round of learning based on my previous experience? Regardless, it's been great.
There's just so many mental overheads like what is concurrent safe, what is non-null, etc that are just great to not think about anymore. On top of that, the formatter and LSP are just great. It highlights in my text editor (Kakoune) what variable caused an error, where it gets moved incorrectly, etc. So much just works, it's great.
My only complaint these days is:
1. I find it odd that some things like slice reads can still panic by default. Yes, I can use `foo.get(1)` to avoid panics, but still - it's a bit odd to me.
2. I'm anxiously awaiting async/await. It's quite difficult to be patient.
[1]: Programming Rust: Fast, Safe Systems Development
- steveklabnik 8y agoIt’s probably a combination of both things, but “I tried rust, struggled, quit, came back months or years later and now I have no idea why I thought it was so hard” is certainly a recurring pattern we’ve seen. Glad it’s working for you now!
- insulfrable 8y agoBecause people underestimate the amount of effort needed to learn a new language at first?
- steveklabnik 8y agoI'm not sure it's that simple. I've never heard anyone say this about Go, for example.
- zaphar 8y agoTo be fair, Go is uniquely designed to be easy to learn and become productive with quickly. It was practically a design goal of the language.
- steveklabnik 8y agoSure. I think it's one of Go's strongest points. But it's still a counter-example to the parent's point. Learning a new language does not inherently require a lot of effort, and so expecting it to be reasonably easy, especially when you're an experienced developer, doesn't seem unreasonable to me.
- tonyarkles 8y agoGo does still suffer from people bringing idioms and assumptions from other languages, and that has leaked somewhat into common libraries. I've been away from it for a while (mostly doing very low-level C on microcontrollers these days), but there was a lot of Go code I came across that just screamed "This was written by a Java developer who is learning Go!" I had a great time writing Go web services, and I definitely agree that it was easy to pick up, both for me and other teammates. Figuring out the idiomatic way to do things wasn't always straightforward though, although getting up and running was easy.
- Gibbon1 8y agoHave not used rust but I'm assuming it's because when you're down a rat hole rust stops you cold at every turn. You need to back up and rethink what you're trying to do. But when you don't have a good handle on what rust is complaining about you can't see that.
- atoav 8y agoThe books are incredibly well written. When people are “stopped cold at every turn” they are usually programmers who come to Rust with a metric ton of existing assumptions how to solve certain problems, without really thinking about the concepts of the language itself. When a C++ programmer starts with python they will write incedibly “unpythonic” code, when they do the same thing in Rust, it just won’t compile. IMO Rust is very straightforward and the std library is incredibly good. But you have to really understand certain core concepts and what they mean in terms of structuring your code. Just like that C++ programmer needed to learn what is ideomatic python looks like and why it makes a lot more sense to write python that way, you need to find the rust way of things. But this is the same for every progtamming language out there..
- Gibbon1 8y agoYou've restated the point I was trying to make much better than I did.
- noir_lord 8y agoI agree entirely. One of the reasons why when I learn a new language I deliberately research the idiomatic way to write that language, it saves a bunch of trying to hammer a square peg into a round hole time. Also some languages purely because of the domain they are in can do things in ways that others can't (trivially) do so if you treat each language as "foo" with different syntax you end up hobbling yourself to the lowest common denominator of "foo"'s features across every language you use.
- masklinn 8y agoThere's plenty of languages which take limited / little efforts to learn. So I'd say more that the unfamiliar concepts need to stew or sink in. One way is to just keep at it until it clicks. An other way is to not do that, but once you've got the words for something you start seeing the issue everywhere, and next time around it makes a lot more sense.
- atoav 8y agoFor real Beginners to programming Rust can be hard, because concepts like pointers are hard in most languages that use them. For Programmers that try Rust out Rust can be hard because they are stubornly trying to program Rust as if it were Python/Java/C/C++/Foo – but it isn't. Rust as a language makes certain types of approaches (or anti patterns) nearly impossible. In the beginning it happens quite often that after a day of struggle you will erase a Rube-Goldberg-Machine that does something simple and replace it with the right line of code that does exactly the same while beeing way more extensible. If you find yourself building more and more elaborate structures just to get something very simple done, the problem is very likely your approach (e.g. trying to implement a OOP structure instead of solving the problem) – at least that is what happend to me a lot. Rust's borrowing and ownership concepts, as well as traits and generics make it extremely powerful, but these concepts lend themselves better to certain ways of structuring code than to others. Learning something is in my opinion always about allowing something to change your perspective. If you are not allowing the thing you are learning to change you, chances are that you are not learning, but judging.
- woolvalley 8y agoFrom my friends that have tried rust, creating a graph or doubly linked list without using some special structures is fairly painful or impossible. You can create a graph by using some sort of adjacency matrix or some other kind of structure that keeps ownership in some sort of tree without much pain, but that has it's own downsides.
- rwmj 8y agoThis was also my experience. It's a fine language if you can't (or more usually "won't" for spurious reasons) use a garbage collector. However a lot of things are just easier to do using a GC, and I suspect in many, not all, of the use cases of Rust, a GC would be just fine. (Also I have to rant here a bit: Yes I know the GC you used in Java or Emacs in 1997 was terrible, but modern GCs are very good indeed)
- tasty_freeze 8y ago
- Lorkki 8y agoBoth type inference and borrow checking have also received a whole bunch of small improvements over the past couple years. Subtle enough that you probably wouldn't notice them except in that the language just takes less effort to use. If you use Rust 2018 now, non-lexical lifetimes are a bigger recent improvement: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.html https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ow...
- TheCoelacanth 8y agoAlso error messages have had a lot of effort put into them, so an error that would have been confusing a few years ago, now may no longer be confusing.
- steveklabnik 8y agoThis is true, but it also happened a lot even before NLL. That said, I do think it's an additional factor today, you're right.
- epage 8y ago> 1. I find it odd that some things like slice reads can still panic by default. Yes, I can use `foo.get(1)` to avoid panics, but still - it's a bit odd to me. I wonder if this is similar to C++'s `[]` vs `at`. `at` does implicit bounds checking but, as an optimization, if you are already doing an explicit bounds check, you can elide the implicit check via `[]`.
- Shoop 8y agoIt's somewhat similar, except C++'s [] leads to memory unsafety whereas Rust's [] on slices has bounds checks and will abort the program on failure. Your program will crash but it won't be an exploitable bug (except for a DOS). .get(), meanwhile, returns an Option so that code written using it can recover from OOB accesses.
- masklinn 8y agoExcept Rust's [] behaves like C++'s at (checks and aborts). C++'s [] is called `get_unchecked`.
- int_19h 8y agoC++ at() doesn't check and abort, it checks and throws a specific documented exception that you can catch. So it is, in fact, closer to get(), just using a very inefficient way of reporting.
- masklinn 8y ago> C++ at() doesn't check and abort, it checks and throws a specific documented exception that you can catch. So it is, in fact, closer to get(), just using a very inefficient way of reporting. You can catch a panic, and you can compile C++ with -fno-exception. at() is not closer to get() than to [].
- pjmlp 8y agoIf you do that, you will be invoking nasal daemons, as at() is required by ISO C++ to throw.
- kingbirdy 8y agoHow do you like Kakoune? It's the first I've heard of it
- asdkhadsj 8y agoLove it - was a Vim user for many years before that. I will say that while the Unix-y design is really cool, the plugin system written around Unix (Bash) is a bit of a pain. You technically don't need to use bash at all, but idiomatic plugins tend too.. so.. meh. These days I'm wanting out of the Terminal - but wherever I go, I'll need to take Kakoune's style of modal navigation with me. I love it too much. _(For reference, I'm hoping Xi editor implements the foundation of modal editing, and then I can make Kakoune style editing work in Xi Editor)_
- Sharlin 8y ago> I find it odd that some things like slice reads can still panic by default. Yes, I can use `foo.get(1)` to avoid panics, but still - it's a bit odd to me. Panicking is a perfectly good way to handle the situation where an invariant of the program is violated. That is, it is perfectly fine to index using [] in cases where there cannot possibly be an out-of-bound access unless the program has a logic bug. And if it does have a bug, there's usually not much that you can do except abort because you can't trust the program anymore. On the other hand, if you know that your input might be OOB without violating a precondition, as a part of the normal execution of the program, and you can handle it gracefully, use `get` instead. This distinction between "expected" and "unexpected" errors is an extremely valuable one, and one unnecessarily muddled by languages where all errors are signaled with exceptions. Rust gets it right.
- asdkhadsj 8y agoI don't understand, tbh. Eg does Rust not make great effort to prevent null pointer exceptions? OOB feels quite similar to null pointer. It's strange to me because a lot of what I value in Rust is writing code that handles all outcomes safely and with confidence. Yet that all seems to be out the window if you access array values - as it may or may not work. The safety of [] slice/array access is entirely up to how the dev wrote the code.. which largely feels the same as any other language. Am I thinking about something incorrectly?
- Sharlin 8y agoThe usage pattern is somewhat different. The primary problem with null references in languages such as Java is that they are not opt-in, and they're not even opt-out! That is to say, you don't even have an option (heh!) to encode in the type system the fact that a reference is never null. What's worse, references tend to get passed around a lot, and stored inside objects, and programmers are lazy and don't assert or even think about preconditions, so the root cause of an unexpected NPE can be far removed from the code that finally triggers it. With code that indexes slices, the index computation is usually much more proximate to the actual indexing operation. If ensuring the validity of the index is about upholding an invariant internal to the module, it makes no sense to return an "sorry, I have a bug" error to the caller if that invariant fails to hold. What would the caller do about that?
- yjftsjthsd-h 8y ago> I have no understanding why last time was so painful, and this time it's been so amazing. It has been my experience that if I try to learn something hard and give up and then come back to it a few months later, I have a way easier time even with no apparent changes in process. I suspect some of it is giving your brain time to process fundamentals or something.
- sanderjd 8y agoThis seems true and unsurprising - it strikes me as being similar (or identical) to spaced repetition, which is a powerful learning technique.
- int_19h 8y agoI wonder if it has something to do with the nature of the problems. Rust can be very smooth or a real pain, depending on the data structures you need to model - basically, whenever ownership is unclear and sharing is common, it's going to be more painful.
- atoav 8y agoUsually that just means you have to think much harder about the problem you are trying to solve within the new set of requirements (borrow checker, lifetimes). Weirdly enough these things should also be a hard problem in other non-Garbagecollected languages, but you get away with a lot more when the compiler doesn’t force you. From a purely practical level there is so much already that I had a hard time finding some data type that had no existing and tested solution for it. Looking at the code in the std library can be enlightening.
- int_19h 8y ago> Weirdly enough these things should also be a hard problem in other non-Garbagecollected languages, but you get away with a lot more when the compiler doesn’t force you. It's the same as with static vs dynamic typing - some things are just easier to model with dynamic, because you don't have to fight with the type checker to prove that your program really is sound when you know that it is. But, of course, you might believe it to be sound when it really isn't...