moldavi's comments

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

You know nothing of what I'm programming. You don't know when, whether, or how my program accesses or deletes data. You don't know what domain I'm in, whether I'm on a team, or what our priorities must be.

And yet, you proclaim that your approach is how I should always do it in any language, in any situation.

It strikes me as particularly convenient, seeing as that's the only approach that the borrow checker can reason about.

To make it more concrete: if we apply your solution everywhere we run into this problem with the borrow checker, it can flatten a lot of our program's (non-temporary) state into basically relational tables. Sometimes that's okay, but for a lot of situations it can be bad for encapsulation, velocity, and modularity.

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

GP was confused about why the doubly linked list case was so important, so I enlightened, it's an example of an entire class of the borrow checker's problems.

Your response isn't really relevant in that context, and instead escalates to a much larger debate, so best I not engage. Appreciate the thought though =)

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

I've experienced this as well. Any disagreement always comes down to "you just haven't used it enough". I let myself take that gaslighting for years before I decided to just not go to the Rust servers any more.

And then when you question any of the classic Rust axioms (such as safety or speed being only desirable rather than an absolute commandment) a lot of them tend to get rather hostile. It's not a pleasant crowd if you don't think 100% like they do.

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

That absolute claim is simply not true. That's like saying that people need to avoid shared mutability in every program, which simply doesn't make sense for a lot of programs, especially if you have a garbage collector already.

It's only a useful tool that has some nice qualities in some settings. It's not some underlying truth of the cosmos, it's just a situationally useful way to do things.

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

Easier than C or C++ for sure. But I definitely wouldn't say that Rust as easy as a GC'd language like Java or Go.

They have strictly less constraints to deal with, they can let you use the simplest pattern for the situation, and (in my experience) they have less superfluous refactoring sessions due to the overly conservative nature of the borrow checker. I like how Matt Welsh put it in https://mdwdotla.medium.com/using-rust-at-a-startup-a-cautio...:

> What really bites is when you need to change the type signature of a load-bearing interface and find yourself spending hours changing every place where the type is used only to see if your initial stab at something is feasible. And then redoing all of that work when you realize you need to change it again.

Perhaps you're instead speaking of a specific situation or kind of program where the borrow checker happens to be no harder than any other language?

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

Can we please not do this?

It's fine to give a different viewpoint, but it's surprisingly common that whenever someone says anything bad about Rust, a Rust user comes in to say that they just haven't used it enough.

It's like saying "If you don't like my favorite movie, you just haven't watched it enough."

moldavi | 3 years ago | on: Choosing Nim out of a crowded market for systems programming languages

I'm sometimes a bit confused when people say that Rust has less cognitive load. I assume that's compared to something like C or C++, right?

I've used Rust and (imperative-style) Scala a lot, and I have to say, Scala is way easier since it doesn't have to deal with the borrow checker, but it still has an amazing type system.

Nim is statically typed and has algebraic data types, so I imagine it's also as easy as Scala, easier than Rust.

moldavi | 3 years ago | on: Carefully exploring Rust as a Python developer

Rust will never be used as widely as GC'd languages like Java, Go, C#, etc.

It's incredibly well-designed, but you can't design away the inherent complexity of writing safe, secure, fast code. There's no way to make that easy. It will always take a lot of passion or training to really master it. (Yes, I know that some of us here "had an easy time" and it "only took a few weeks", I'm referring to the average person.)

And you know what, that's okay. There are lots of industries where only the most hardcore of programmers use the professional-grade tools. There's nothing wrong with that.

Everyone else will probably continue to use tools like Java, Python, etc. because for most situations, they can get the job done with less training, which means less spent on developer salaries, which is most often more than server costs anyway.

I think the best we can hope for is that Rust is taught in university, like how other industries teach usage of their own professional-grade tools. But even that won't mean that most programmers use Rust, I think.

moldavi | 3 years ago | on: “Rust is safe” is not some kind of absolute guarantee of code safety

I've seen both sides of this, as a Rust user and as a Go user.

Rust users are generally friendly to one another, and to people who are interested in Rust. Hoever, some Rust users are toxic when talking to people outside the community or to people who disagree.

That's why a lot of us (in the Rust community) don't notice it; we spend most of the time inside our own community talking to each other and being friendly to each other.

This is a trait common to any bubble or insular community whether it be about politics, religion, economics, or whatever. It's fairly easy to recognize once you get in the habit of dis-identifying with your own side.

There's also a phenomenon in human psychology where we tend to forgive "our side's" misbehavior, presumably because it's in service to a higher ideal and therefore forgivable. It's the difference between "passionately spreading the good word" and "aggressive evangelism", two views of the same action. After learning about this I've even seen it in myself, though hopefully I've learned to counteract it a bit.

Note that this isn't unique to Rust, other languages have this too to an extent.

It's something I really hope we can leave behind, because it's hurting an otherwise beneficial message that Rust can bring a new tradeoff that is favorable for a lot of situations.

moldavi | 3 years ago | on: Unreal Rust

For a single player turn-based game, I'm not so sure the tradeoff is as obvious as everyone says, after coding one in C++ and another in Rust.

It's turn based, so I don't need AAA game multi-threaded performance. It's single-player, so cheating doesn't really hurt anyone.

I use sanitizers to catch memory problems, but there have only been a few of those over the years. Maybe ECS just isn't that vulnerable to memory-safety problems?

The borrow checker prevents iterator invalidation problems, but most of my functions are read-only so there's not really a chance for those anyway, or many other single-threaded race conditions for that matter.

After this long using Rust, I'm noticing more and more that the borrow checker is imposing a lot of artificial complexity, when I compare it to my C++ version. We're often told that Rust is hard because the underlying problem is hard, but I've encountered many cases where that's not true, it really is just the borrow checker. And unfortunately, most of them are problems that Polonius won't fix.

Rust has a lot of great features (enums and cargo!) but I think one should think carefully about their domain and architecture before choosing a language, lest they pay too much cost for too little benefit.

Just my two cents!

moldavi | 3 years ago | on: RustDesk – Open-source TeamViewer alternative

Saying it's "idiomatic" isn't very actionable advice for people, the average programmer hears that and doesn't really know when to use Rc over other approaches. I also wouldn't say to always go with the most ergonomic approach, that approach can lead to code that is even slower than other languages.

I would rather advise: don't reuse indices, even if that is the simplest solution that complies with the borrow checker. When one finds themselves reusing like that, that's when to turn to other more expensive approaches such as Rc.

moldavi | 3 years ago | on: RustDesk – Open-source TeamViewer alternative

In Rust, people tend to go for the easiest solution that works within the borrow checker, and not workarounds like Rc or Arc. Otherwise, the performance hit means there's little reason to use Rust over much easier languages.

moldavi | 3 years ago | on: RustDesk – Open-source TeamViewer alternative

That's why I said one should have the discipline and practices in place to avoid this bug.

I think we can do better than saying that indexes into Vecs are "non-idiomatic" in applications... such advice could remove much of Rust's performance advantage, and make folks wonder why we're not just using GC.

Perhaps we could instead say that if one finds themselves reusing slots in a Vec, they should instead use generational indices, hash maps, or Rc<RefCell<T>>, depending on their use case and what kind of performance overhead they'd prefer.

moldavi | 3 years ago | on: RustDesk – Open-source TeamViewer alternative

That's why I mentioned one needs to have discipline, to not use that particular solution.

We agree it's not the best solution. And it's easy for us to say that now, after I've spelled out why. You'd be surprised how many people don't know that this can be a problem.

Also, it amuses me that having a simple index into a Vec would be a "convoluted solution". It's the easiest solution of all the alternatives. It can also be risky for privacy.

Compare that to a GC'd language, where the easiest solution (just hold a reference) doesn't introduce privacy risks.

moldavi | 3 years ago | on: RustDesk – Open-source TeamViewer alternative

In fact, in the pursuit of eliminating memory-safety and security bugs, Rust can sometimes makes some privacy bugs more likely.

For example, in GC'd/RC'd languages, if we have several UserAccount instances and a bunch of long-running operations on them, any particular long-running operation will just hold a reference to the UserAccount itself and modify it at will without any confusion.

In Rust, the borrow checker often doesn't let us hold a reference from a long-running operation in practice, so we work around it by putting all UserAccount instances into a Vec<UserAccount>, and have our long-running operations refer to it via an index. However, we might erase and re-use a spot in that Vec, meaning the index now refers to some other UserAccount.

If the operation uses that "dangling index", it can lead to leaking sensitive data to the wrong users, or data loss.

When using Rust, one has to use discipline to avoid this bug: use IDs into a hash map, or generational indices, or Rc<RefCell<T>>. Each has its own performance hit, but that hit can be worth it to prevent privacy bugs.

In the GC'd/RC'd language, this would still be a bug, but it wouldn't cause any mixups between different users' data.

I'm not saying we should always use GC'd or RC'd languages for privacy-sensitive purposes, but one should be aware of the particular shortcomings of their tools and have proper practices and oversight in place to mitigate them.

page 1