Live data from Hacker News

Two Years of Rust

borretti.me

31–40 of 69 posts

Re: Two Years of Rust

#31
post #8
post #3

My biggest issue with rust after two years is just as you highlight: the mod/crate divide is bad! I want it to be easier to have more crates. The overhead of converting a module tree into a new crate is high. Modules get to have hierarchy, but crates end up being flat. Some of this is a direct result of the flat crate namespace. A lot of the toil ends up coming from the need to muck with toml files and the fact that…

It's a surprising choice that Rust made to have the unit of compilation and unit of distribution coincide. I say surprising, because one of the tacit design principles I've seen and really appreciated in Rust is the disaggregation of orthogonal features. For example, classical object-oriented programming uses classes both as an encapsulation boundary (where invariants are maintained and information is hidden) and a d…

Hard agree. Is retrospect I think the model of Delphi, where you must assemble `manually` a `pkg` so you can export to the world should have been used instead.

It also have solved the problem where you ended doing a lot of `public` not because the logic dictated it, but as only way to share across crates.

It should have been all modules (even main.rs with mandatory `lib.rs` or whatever) and `crate` should have been a re-exported interface.

Re: Two Years of Rust

#32

Earlier quoted context omitted.

> IO can’t be unit tested hence why you mock it. Say, I have this module that uses a private MongoDB as a cache. Its unit tests spin up a standard MongoDB container and use it (and then tear it down). Are they still unit tests or should I start calling them "integration tests"?

Integration. Unit tests should just test code units. All the external stuff should be mocked or not tested. The example in the post is a unit test. It’s good to keep it separate as unit tests are really easy to run and less complicated and much faster. Integration tests are much more complicated and often sort of freeze your code as it locks in the implementation.

How you define "external stuff" matters though. As soon as your function is calling another function, your test can be argued to be an "integration test", as you're now implicitly also testing the logic of the other function.

Alternatively you mock _everything_ and then your "unit test" ends up just being a tautological test asserting that "the code I wrote executes in the way I wrote it". (Not to mention that every time you mock something you are also implicitly asserting what the expected behavior of that thing is).

The only truly reliable tests are E2E tests, but they are too expensive to cover all possible permutations as there are just too many.

This is the catch 22 with testing, and we're always forced to make pragmatic choices about where to draw our boundaries to maximize the value (i.e. actual bugs caught) of them.

Re: Two Years of Rust

#34

The mock example looked pointless. IO can’t be unit tested hence why you mock it. But his code didn’t do anything but confirm his mock worked. He’s writing mocks and testing mocks. The functionality he referenced is just inherently not unit testable. Again, If you try to mock it and test things you end up testing your mocked code. That’s it. I’ve seen this strange testing philosophy pop up time and time again where t…

> IO can’t be unit tested hence why you mock it. Say, I have this module that uses a private MongoDB as a cache. Its unit tests spin up a standard MongoDB container and use it (and then tear it down). Are they still unit tests or should I start calling them "integration tests"?

I think that's still unit tests if that "standard MongoDB container" is actually hermetic.

It's pretty easy to make testing stuff like "We'll conjure into existence a loopback network server" hermetic and likewise for the Entity Framework trick where it runs tests against a SQLite db even though that's not how your real DB works, it's often good enough. Containers are something which could be hermetic, but I am dubious.

Re: Two Years of Rust

#35
post #32

Earlier quoted context omitted.

Integration. Unit tests should just test code units. All the external stuff should be mocked or not tested. The example in the post is a unit test. It’s good to keep it separate as unit tests are really easy to run and less complicated and much faster. Integration tests are much more complicated and often sort of freeze your code as it locks in the implementation.

How you define "external stuff" matters though. As soon as your function is calling another function, your test can be argued to be an "integration test", as you're now implicitly also testing the logic of the other function. Alternatively you mock _everything_ and then your "unit test" ends up just being a tautological test asserting that "the code I wrote executes in the way I wrote it". (Not to mention that every…

By external I mean anything outside the compiled executable.

Or anything that you have to use ipc like sockets or shared memory.

Re: Two Years of Rust

#36

Gripes about the borrow checker I think would be cured with the following surprising fact, and interesting "problem solving" approach to the language's design: In Rust there's at least 5 types of everything, in order of strength: - Value / unqualified / "owned" - Generically, T - Optionally mutable - Mutable Reference - &mut T - you can only have one of these for a given value - Reference / Shared reference - &T - yo…

I feel like it's intuitive for me to think about this stuff as just a second type system rather than to think about the details of how the compiler works or how it'll function at runtime. A given value exists in a kind of superposition, and I pick the form I want it to collapse into (value, reference, mutable reference, etc) based on the tradeoffs I need at that moment. I don't know exactly why this is helpful, or if…

Definitely with my time in the language, my head chatter takes `&` operator to literally just mean "borrow" and then you're inheriting 1x indirection operations.

Re: Two Years of Rust

#37
post #32

Earlier quoted context omitted.

Integration. Unit tests should just test code units. All the external stuff should be mocked or not tested. The example in the post is a unit test. It’s good to keep it separate as unit tests are really easy to run and less complicated and much faster. Integration tests are much more complicated and often sort of freeze your code as it locks in the implementation.

How you define "external stuff" matters though. As soon as your function is calling another function, your test can be argued to be an "integration test", as you're now implicitly also testing the logic of the other function. Alternatively you mock _everything_ and then your "unit test" ends up just being a tautological test asserting that "the code I wrote executes in the way I wrote it". (Not to mention that every…

Functions, in the sense that there are global variables, is strongly discouraged by the language. It's usually much easier to define a type so there is a clear delineation.

That is, from Mongo, you use Serde and wind up with only valid records operated upon, of a table of such values.

Re: Two Years of Rust

#38
post #15

> Error Handling I've yet to see anyone demonstrate the elegance Rust error handling for anything but the simplest of cases. It's all fun and games and question marks... until you hit this: $ ./app called `Result::unwrap()` on an `Err` value: no such file or directory And then you start investigating and it turns out that the error value comes from somewhere deep in an unknown callstack that got discard by the author…

?ing Errors and never actually handling them is just a terrible practice. In fact it is just as bad as not doing error checking at all. Misusing a mechanism is not a point against the language.

What makes this error checking good is that you can use it correctly and it is less cumbersome than the try/catch from C++.

>Come on, let's be a bit more honest with ourselves about Result and '?' - it's not a full solution to error handling. After two years I'm sure you've hit this.

Nothing is ever a full solution. But it is meaningless to talk about this without doing comparisons. Do you think try/catch was the superior solution all along?

Re: Two Years of Rust

#39
post #15

> Error Handling I've yet to see anyone demonstrate the elegance Rust error handling for anything but the simplest of cases. It's all fun and games and question marks... until you hit this: $ ./app called `Result::unwrap()` on an `Err` value: no such file or directory And then you start investigating and it turns out that the error value comes from somewhere deep in an unknown callstack that got discard by the author…

?ing Errors and never actually handling them is just a terrible practice. In fact it is just as bad as not doing error checking at all. Misusing a mechanism is not a point against the language. What makes this error checking good is that you can use it correctly and it is less cumbersome than the try/catch from C++. >Come on, let's be a bit more honest with ourselves about Result and '?' - it's not a full solution to…

> ?ing Errors and never actually handling them is just a terrible practice.

I agree, but that's kind of my point - that's all these Rust praise articles are ever showing :).

> But it is meaningless to talk about this without doing comparisons.

Not comparing to other languages/approaches however allows a discussion to stay about Rust and how to make things better instead of yet another fruitless discussion about which language or approach is better in a vacuum. I'm not interested in demonstrating that Rust is better than C++ or vice versa, I'm interested in Rust being good on its own merits.

Re: Two Years of Rust

#40
post #39

Earlier quoted context omitted.

?ing Errors and never actually handling them is just a terrible practice. In fact it is just as bad as not doing error checking at all. Misusing a mechanism is not a point against the language. What makes this error checking good is that you can use it correctly and it is less cumbersome than the try/catch from C++. >Come on, let's be a bit more honest with ourselves about Result and '?' - it's not a full solution to…

> ?ing Errors and never actually handling them is just a terrible practice. I agree, but that's kind of my point - that's all these Rust praise articles are ever showing :). > But it is meaningless to talk about this without doing comparisons. Not comparing to other languages/approaches however allows a discussion to stay about Rust and how to make things better instead of yet another fruitless discussion about which…

>I agree, but that's kind of my point - that's all these Rust praise articles are ever showing :).

Then they are completely misrepresenting what error handling is about. Rusts error handling is good because programs only crash where you allow them to crash. If you are using the error handling correctly, you only crash wherever there is an error you believe should be unrecoverable.

>Not comparing to other languages/approaches however allows a discussion to stay about Rust and how to make things better instead of yet another fruitless discussion about which language or approach is better in a vacuum.

If you are complaining about the error handling of some language surely the most important and productive thing would be to compare it to the paradigms of other languages. If you are unwilling to consider that someone else is doing something correctly, which you are doing wrong you can't improve. Especially when there are two major paradigms, it seems important to talk about the alternative.

What exactly would you change about rusts error handling?

Post reply on HN