> Rust is easy to learn. For seasoned C++ programmers, Rust is easy to learn. When they first start out, Rust learners usually spend most of their time making sense of ownership and lifetime. Even if they don't explicitly express these concepts in code, experienced C++ engineers always keep these two concepts in mind when programming in C++.
Yeah, sadly it is. With e.g. Elixir I can literally get into a REPL and prototype my solution in minutes, right there on the spot, and then just copy a few lines from it and have the solution be 90% done (minus tests, of course).
With Go and Rust I have to make a dedicated function somewhere and then have it be called after starting the program. Ain't exactly rocket science but the difference in time to do it and the convenience is still very stark.
I love working with Rust for the stability and speed it gives me but the value proposition and daily coding flow are VERY different compared to a dynamic language. With Elixir I am mostly just brain-dumping and stuff happens extremely quickly and fluidly, with Rust I kind of sigh and accept that the next 10 minutes I'll just be writing and writing. Might even zone out and make a dumb mistake because I have to spend more keystrokes and more time to do something I'll do in a minute in Elixir.
Maybe it's time to look for snippets support in my editor. Or start asking ChatGPT for them.
Try using a test -- can stick anywhere and just run code there (push of a button with analyzer in vscode). Almost like embedding a repl into a module for experimentation.
See this is what I’m scared about in my current job. We have some people who want to use dynamically typed languages and some who want to use static.
I don’t think being able to brain dump code is a good thing and it leads to an unmanageable mess when you have a large codebase. Types are essential as far as I’m concerned, but I constantly have to get into arguments with the dynamic type fans because their “flow” Is being restricted.
Brain-dumping is simply a way to iterate and figure out what works and what doesn't, quickly. After I do it I take the requisite time to emulate exhaustive pattern matching, and add tests that cover the functionality well.
My problem with Rust, and I love the language a lot, is exactly this: I want to quickly find what would work. After that I'm very happy to take the proper time to go things rigorously.
Yes and then someone comes along and makes a change that breaks something seemingly unrelated and it’s less likely to be caught because there is no type system.
And please don’t say tests solve that because they don’t. They help but they don’t solve it.
You won't catch me arguing with that. I work both with dynamic and static languages and usually I'll pick the static ones.
Dynamic languages are very valuable when you can afford to iterate and gradually find out the golden path. For the better or the worse, many businesses are of that type.
That being said, I just ended an Elixir contract and absolutely want to code Go or Rust for money again.
I do appreciate that you write tests. I find it's like pulling teeth with most devs to get them to write anything but the most basic of tests.
I tend to think more than write code, so usually my first go is reasonably close to what I need. But there are always edge cases you just never think about. I'd rather have a strong debugger than a repl imo
> I find it's like pulling teeth with most devs to get them to write anything but the most basic of tests
You are unfortunately very correct (at least in my 21 years of experience as well). I too feel annoyance when I know that I made a piece of code work well but (a) every now and then I am truly wrong and (b) various pieces of the system in the code interact in sometimes unexpected ways, unveiling inputs to your code that you haven't foreseen.
So even though it often takes a heavy and annoyed sigh out of me, I still roll up my sleeves and add the tests because I've shot myself in the foot too many times, and ignoring past experience is just being a stupido.
As for debugger/REPL, they are not orthogonal; you can have both. I'd more contrast debugger with tests themselves -- both are ways to go step by step through a process that you know is faulty somewhere.
REPL to me is just a way to more quickly sketch a v1.0 of a piece of code, nothing else.
I love the idea of Elixir, but I just can't get into it because of its weird choice of sigils. |> for pipes and <- for assignments, seriously? I seriously dislike programming languages which choose two character sigils for basic operations. I also heavily dislike |x| in Rust.
Minor clarification: Elixir uses = for assigment. There's a special construct called "with" that's basically fallible pipes, and that's probably where you saw <-
with {:ok, id} <- get_id(),
{:ok, val} <- get_val(id)
do
show_success(val)
else
{:error, e} ->
# We reach this if either get_id or get_val fails
show_error(e)
end
Not to get on the merits of Rust or Elixir, but while you are absolutely entitled to your preferences I should suggest that perhaps you may miss out something important by ditching languages based purely on the format of sigils.
Not going to judge you. When you feel a bit more generous and adventurous, I recommend you give it another go.
Syntax is easy enough. Like all programming languages, you'll get used to it in a weekend and won't even notice it afterwards.
Elixir is absurdly productive: very terse code, very self-explanatory stdlib API, transparent concurrency / parallelism, and in-OS-process high availability and mostly-self-healing hierarchy of green threads and supervisors observing them.
People on HN and Reddit really love to roll their eyes at stuff that's getting popular, and likely will avoid the technology out of a misplaced spite, just because a lot of people are talking about it. It's a weird phenomena.
(Not saying you're doing it, I just kinda got carried away here.)
It's like whitespace in Python, parens in Lisp, begin/ends in Ruby, or 1-based arrays in Julia. You get used to it and eventually it feels natural when using that language.
The Rust tendency toward “golfing” is why I don’t like it. It’s not even lifetimes, but the way traits are setup. And the lack of unified function call syntax. Sometimes it’s a function, sometimes a method — that distracts a lot from the problem at hand IMHO.
Nah, not specifically about the REPL itself, I just need a way to quickly sketch and run a piece of code is all. I know big IDEs support this but I prefer keeping everything in the terminal -- I'll have to go check if Emacs or NeoVim offer something along those lines.
Maybe take a look at evcxr, it runs in a terminal and is REPL like. When I'm dabbling in rust, I use it e.g. to quickly try out library functions and how to work with the result. But I'm just getting started.
I assume they didn't mean compared to C++. If anything, saying prototyping in C++ is easier than Rust is beyond ludicrous even if you're a seasoned C++ developer.
I'd have an easier time prototyping in Rust than C++, and I've been writing C++ for 10 years and Rust for a little over a year.
However, prototype in something like Ruby (or even TypeScript, and some people mentioned Elixir) is in a different universe compared to C++ or Rust.
Like, it's not even a "fair fight" to compare it meaningfully.
What makes Rust better at rapid prototyping? Cargo?
I find that modern C++ "kitchen sink" approach to features makes it good for rapid prototyping, a bit like Perl on the dynamic side. It won't force you into a specific approach, pick the one that gets you there the fastest. Use raw pointers and malloc(), or use fancy smart pointers and RAII, your choice, you can also do both, you have exceptions, you have goto, you can write(), printf() and cout, you have classes and lambdas and (multiple) inheritance and traits. More options are better for rapid prototyping.
Also, C++ is the most popular language for competitive programming, you can't get more "rapid" than that.
If I wanted to just blast out something quick and dirty, I don't think I'd reach for `unsafe`. It's syntactically inconvenient, with lots of `(*foo).bar` and `MaybeUninit`. And I don't think I could be happy with a prototype that's blatantly full of UB, so for me it would take more effort rather than less.
Now that I say that, I guess someone could write an "unsound helper functions" library that helps you write code full of UB conveniently. It could be an interesting thought experiment. But I don't think the community would be very happy about it...
I agree with the macro part. I have seen people use macros instead of functions as a way to escape the type system. But it's not a problem that comes up with C++ programmers.
Both viewpoints make sense; whether Rust is good for prototyping depends on the domain.
If it fits the borrow checker well (like in CLI apps, stateless servers, data transformation) then the borrow checker fits beautifully and seamlessly.
In other settings (complex turn-based games, some compilers, GUI), the borrow checker can cause some artificial complexity and prototyping slowdowns compared to other paradigms.
I guess it depends on your point of view. For me, having Rust catch issues even when prototyping makes me enjoy prototyping more. I absolutely hate (even when prototyping) when I try to run something, it chugs along for a bit, and then hits a runtime error due to some stupid typo.
In fact I like Rust for prototyping precisely because I don't yet have tests, and the extra compiler diligence frees me to focus on the prototype.
> and then hits a runtime error due to some stupid typo.
I don't think that the parent comment implied prototyping in dynamic languages but rather in statically compiled ones.
FWIW in C or C++ you don't have to do as much code gymnastics to satisfy the compiler so consequently prototyping is both faster and easier when compared to Rust.
Again for me personally, I find the opposite true. With C and C++ I'll find that once in a while, quick sloppy coding gets me something that seems to work for a bit and then fails in subtle and hard to debug ways. That's a time sink that just doesn't exist when I whip something together in Rust.
I was happy to see this as well. As a 'seasoned' C++ dev myself, when I learned Rust, I was pleasantly surprised to see those implicit concepts made explicit in code.
Same. I think that I didn't go through the Rc<RefCell> phase that so many new to Rust go through because of C++ teaching me the same lessons in a much more brutal way. By the time I got to Rust I had learned to structure my code to sort of use pointers/references as capabilities, such that simply having knowledge of the bit pattern of the pointer was implicit access through that pointer since as a codebase evolves someone will keep pointers around or not go through.whatever song and dance you need to do to keep accesses through that pointer valid. That thought process translates very well to Rust.
What I love about Rust is what I love about Python… “explicit is better than implicit”
When I open something up to read it, to try and understand it, to dig in and fix something broken… having everything be exposed in the explicitly written code… is vastly more useful to me than trying to mentally interpret a language as I read it and remember the rules, the meta-programming rules… and all the implicit stuff that can affect how the program will behave.
Lot of programming languages aren’t good at this explicitness, and I’ll be honest, it’s a genuine struggle for me picking up the languages like this, only made worse when the documentation is very prose like and fails to convey how anything actually works, eschewing that in favour of, at length, demonstrating the feel of a programming language through countless demonstration example that lack mechanical “what is this doing under the hood” explanation.
Hot take, I feel like people that complain Rust is hard typically write bade code in other languages. Rust is just preventing you from making common mistakes or using patterns that make your code hard to reason about and debug later.
As a fellow Rust user, please stop saying this. Not everyone who codes like us is a bad programmer. It's this kind of sentiment that gives us a bad name.
Rust may influence us into patterns that are better in some (likely even most) situations, but not always. Sometimes the situation calls for other approaches, and that's okay.
The OP is crapping on people who find Rust hard to learn by broad-brushing them into the "bad programmer" bucket. It's a hallmark of Rust zealots, and one reason why the Rust community has such a bad name. Which is a shame because the language is decent and useful.
As somebody who could possibly be in the category you described, once I learned about Arc+Mutex, I pretty much write code the same way I used to. That and maybe OnceCell/Lazy?
This, this, and this again. Lots of patterns Rust enforces are sensible choices even with a garbage collector, because data races for instance are still a thing even if you have automatic memory management
As someone with a passable level of modern C++ exp it took about a week to pick up Rust. Syntax was the time sink...
Though, people tend to gloss over that C++20 is decently comparable to Rust in terms of semantics and safety, the issue is very few C++ codebases are modern and the footguns are still lurking for the careless.
That said, Rust iterators are very nice and the async story completely mocks the C++20 coroutine nonsense.
A few years ago I met up with someone who just graduated and who's only experience with programming was MATLAB during his degree. To my surprise he'd been hired to use Rust and was telling me how great the recently released async was.
Finally somebody understands this.