Hacker News new | ask | show | jobs
by usrbinbash 962 days ago
> Rust kind-of owns that space

True. But it's a pretty small space to be in. And there are good reasons for that:

a) The only correctness Rust can, mostly, guarantee, is that there won't be unexpected data races or memory bugs. While this is proudly announced often and loudly, it also isn't the most common problem in code...logic bugs...against which the rust compiler can do as little as any other language.

b) Rust can only give these guarantees because it is ALOT more complex than C. That means harder to read, harder to write, harder to learn. And developer time matters. Alot. If I can already ship features, while my competition is still stuck in onboarding, it won't matter if my code has the odd memory bugs...those can be fixed...I will already have the market to myself.

1 comments

> a) The only correctness Rust can, mostly, guarantee, is that there won't be unexpected data races or memory bugs. While this is proudly announced often and loudly, it also isn't the most common problem in code...logic bugs...against which the rust compiler can do as little as any other language.

A powerful type system helps quite a lot with logic bugs actually.

> A strong type system helps quite a lot with logic bugs actually.

A static type system does, and all the languages that Rust has to compete with in its space, have one.

Go's type system is much less expressive and it has null pointers. An entire giant class of bugs.
> Go's type system is much less expressive

Please, do explain: what does "much less expressive" mean, in technical terms? What specific data modeling can I not do in Go, and what specific bugs can be caused by that?

> and it has null pointers

Yes, so? De-Referencing a null pointer in Go crashes the program, making the bug very obvious. Go made the choice to have null pointers (which do exist in silica), and avoid the complexity of languages who pretend that null pointers don't exist.

It's a tradeoff, and a very good one at that.

> what does "much less expressive" mean, in technical terms? What specific data modeling can I not do in Go, and what specific bugs can be caused by that?

This is a good illustration of how to model data using Rust's type system in a way that gives you compile-time guarantees of correct behavior:

https://docs.rust-embedded.org/book/static-guarantees/state-...

> Because we are enforcing our design constraints entirely at compile time, this incurs no runtime cost. It is impossible to set an output mode when you have a pin in an input mode. Instead, you must walk through the states by converting it to an output pin, and then setting the output mode. Because of this, there is no runtime penalty due to checking the current state before executing a function.

> Also, because these states are enforced by the type system, there is no longer room for errors by consumers of this interface. If they try to perform an illegal state transition, the code will not compile!

> What specific data modeling can I not do in Go

You're getting into the Turing tar-pit. There's nothing you can do in Rust you can't also do in Go, technically. Hell, you can do it all in Brainfuck too, if you so desire.

The big thing, though, is ADTs. Being able to say "the value is one of 3 possible values" is a lot easier than saying "here are three values, you should use the non-zero one".

> You're getting into the Turing tar-pit.

I am fully aware of that. My question is, what specific technical problems are caused by Go not having {feature_goes_here}.

> The big thing, though, is ADTs

Except it isn't a big thing, because for the few use cases where an ADT is actually, really, really, REALLY required, they can be expressed in Go using existing language features.

https://go.dev/doc/faq#variant_types

https://eli.thegreenplace.net/2018/go-and-algebraic-data-typ...

Quote: "It seems that Go can do just fine without adding variant types, due to the challenges mentioned in the beginning of the post and the ease with which the major use-cases can be implemented using existing language features." End Quote

On the one hand, yes, this is more verbose. On the other hand, these use cases are simply not frequent enough to justify making the languages syntax and type system more complex.

Again: Yes, Go lacks many features of other languages. That is on purpose. The language is made to be simple, as in "easy to learn, easy to read, easy to refactor, easy to generate, easy to maintain large bodies of code".

> Please, do explain: what does "much less expressive" mean, in technical terms? What specific data modeling can I not do in Go, and what specific bugs can be caused by that?

> Yes, so? De-Referencing a null pointer in Go crashes the program, making the bug very obvious.

At runtime. i.e. production. You think that is just as good as solving the problem at compile time? I certainly don't.

> At runtime. i.e. production.

At runtime, i.e. initial testing, pre-commit-checks, integration-testing, QA and then production, yes.

So there are a lot of checkpoints where the system can crash before it ever goes live.

> You think that is just as good as solving the problem at compile time?

No, I don't, and I never wrote that I do.

I do think that it's a lot better than not crashing and running inti undefined behavior when dereferencing a null pointer, which is a problem in older languages, and a source of hard to track bugs.

The problem is: solving it at compile time isn't zero-cost.

Languages that pretend that void pointers don't exist are usually more complex than languages that accept their existence as a fact of the underlying hardware. That extra complexity comes at a tangible cost in development time and maintainability. A language that fails early, and with a clear signal, will sometimes crash in testing, and maybe maybe maybe in production here and there, and such crashes may incur a cost. A more complex language will always incur a higher cost in developer time.