Live data from Hacker News

Rust from a Gopher – Lessons 7, 8 and 9

levpaul.com

41–50 of 58 posts

Re: Rust from a Gopher – Lessons 7, 8 and 9

#41
I agree the modules are annoying. I realize that the "standard" Rust style is import everything you need. However personally I have long worked with code that avoided imports and found it very helpful to read as it was obvious where each type of function was coming from. However the deeply nested imports makes that painful in a lot of Rust libraries.

For example `std::time::Duration`, `std::path::Path`, std::cmp::Ordering`. I wish everything was just directly in `std` such as `std::Duration`, `std::Path` and `std::Ordering`.

This re-export that the article talks about is doing this change (which I think is great!) while keeping a nice file structure. I think it is a shame that Rust conflates how you organize your code and how the user of your library sees it by default. However this seems like the best compromise.

Example of this pattern in my code: https://gitlab.com/kevincox/mario-solver/-/blob/137ac5dea067... (however since this isn't a library I use `pub(crate)` instead of `pub`. It works just fine with `pub` except you get a warning if the file doesn't have any exports which is a little annoying).

Re: Rust from a Gopher – Lessons 7, 8 and 9

#43
post #3

What's the rationale for making files modules? Modules being namespaces, and namespaces being collections, it's not desirable to have a file being a (large) collection of code. The feature that gives mixed feelings to the author (Re-exporting Imports) is indeed a workaround to this; since each file would externally generate one extra namespacing level, one reexports data structures in order to remove that level. This…

Files aren't modules. Modules are defined in the source code the same way as any named "item" in the language, like structs and functions.

The only difference is that content of `{}` following the definition of a module can be read from another file.

You can have a module without a file:

    mod foo {
       fn function_in_foo() {}
       mod bar {
          // this is crate::foo::bar module!
       }
    }

but if you omit {}:

    mod foo;

Rust will look for `foo.rs` to drop its content where the {} should have been. But namespacing is governed by `mod` declarations alone, not files.

Re: Rust from a Gopher – Lessons 7, 8 and 9

#44
post #36

Earlier quoted context omitted.

Interesting. This made me realize that a possible reason why some find the modules concept confusing is that it conflates the concepts of inclusion and namespacing. edit: corrected typo

Rust modules are primarily about namespacing, which is why the book only mentions the inclusion behavior in one short section at the end of the relevant chapter. For a non-namespacing include, there’s the `include!` macro.

The `include!` is not intended to be used as a _generic_ inclusion mechanism¹:

> Using this macro is often a bad idea, because if the file is parsed as an expression, it is going to be placed in the surrounding code unhygienically. This could result in variables or functions being different from what the file expected if there are variables or functions that have the same name in the current file.

¹=https://doc.rust-lang.org/std/macro.include.html

Re: Rust from a Gopher – Lessons 7, 8 and 9

#45
post #36

Earlier quoted context omitted.

Rust modules are primarily about namespacing, which is why the book only mentions the inclusion behavior in one short section at the end of the relevant chapter. For a non-namespacing include, there’s the `include!` macro.

The `include!` is not intended to be used as a _generic_ inclusion mechanism¹: > Using this macro is often a bad idea, because if the file is parsed as an expression, it is going to be placed in the surrounding code unhygienically. This could result in variables or functions being different from what the file expected if there are variables or functions that have the same name in the current file. ¹= https://doc.rust…

I fail to see how you draw your conclusion from that statement. It warns about the macro’s potentially surprising behavior, but doesn’t speak to the designers’ intent at all.

`include!` is analogous to C’s `#include`: it textually pastes the file’s contentents in place of the macro, but I can’t think of another way that a textual (vs. semantic) include mechanism would work.

Re: Rust from a Gopher – Lessons 7, 8 and 9

#46
post #2

As a sidenote, does anyone else find the language identification terms cringey? Rustacean, gopher, pythonista... just atrocious.

I’m noticing a trend of mostly younger people misusing “cringe” and I wonder if it may have to do with dumb videos on YouTube misusing it, or maybe the word is changing. To cringe is to feel disgust or embarrassment that results in a physical reaction such as a grimace. Generally, this can be felt watching very socially awkward situations. Is this what you mean? Or is there a better word, like immature, silly, strang…

The word “cringe” has morphed into “that makes me cringe,” yes. It’s more a certain segment of internet culture than “young people,” though.

Re: Rust from a Gopher – Lessons 7, 8 and 9

#47

Earlier quoted context omitted.

As someone who mostly writes Rust these days, I find it really nice that I can always (as long as I don't use wildcard imports) use intra-file search to find either the definition or the file that contains the definition. Whenever I have to touch Go code (for reading and debugging) it's really annoying to just end up going "okay, I've got the folder, now what". Or, even more annoyingly, I've just got an interface and…

> Or, even more annoyingly, I've just got an interface and no clue about where to find the implementation. That bites me often times. Does gopls help in this regard? Can any tool besides the compiler help me to answer, what methods in a particular piece of code implement what interface?

Not even the compiler knows, since interfaces are resolved at runtime. You could build a list of potential implementations, but then structural typing means that it can't know the difference between an intentional and accidental implementation.

Re: Rust from a Gopher – Lessons 7, 8 and 9

#48
post #37

Earlier quoted context omitted.

I’m noticing a trend of mostly younger people misusing “cringe” and I wonder if it may have to do with dumb videos on YouTube misusing it, or maybe the word is changing. To cringe is to feel disgust or embarrassment that results in a physical reaction such as a grimace. Generally, this can be felt watching very socially awkward situations. Is this what you mean? Or is there a better word, like immature, silly, strang…

I think cringe fits here. If I met a developer who said they were a gopher or rustacean or whatever. I'd feel physically embarrased for them.

"physically embarrassed". I like it; great distillation of the concept.

Re: Rust from a Gopher – Lessons 7, 8 and 9

#49

Earlier quoted context omitted.

One important technical reason is that you need to be able to add attributes to modules, like these examples: // Only compile this code if the “foo” Cargo feature is enabled. #[cfg(feature = "foo")] pub mod foo; // Platform-specific stuff, as with std::os. pub mod os { #[cfg(windows)] pub mod windows; #[cfg(unix)] pub mod unix; } // You can even choose which file to load the module from. #[cfg_attr(windows, path = "w…

Interesting. This made me realize that a possible reason why some find the modules concept confusing is that it conflates the concepts of inclusion and namespacing. edit: corrected typo

It confused me for a long time because:

- Other languages like C++ and C# emphasize how much namespaces are _not_ connected to files at all

- I just ignored it and wrote everything in one big file, because the Rust compiler is just as slow either way. Even in C++ it's arguable whether splitting a file will result in faster or slower compiles, because of the outrageous behavior of #include

But once I realized every file is a module, it slowly started to make sense.

Re: Rust from a Gopher – Lessons 7, 8 and 9

#50
post #10

Earlier quoted context omitted.

As someone who mostly writes Rust these days, I find it really nice that I can always (as long as I don't use wildcard imports) use intra-file search to find either the definition or the file that contains the definition. Whenever I have to touch Go code (for reading and debugging) it's really annoying to just end up going "okay, I've got the folder, now what". Or, even more annoyingly, I've just got an interface and…

Dont most IDEs solve this. I do C# for my day job, if I have an interface I put cursor on it and hit a key and go to the definition, whatever file it's in. Another key will cycle the usages of the interface. This has been solved for years. More recently we've had things like Peek as well.

But if you have to rely on an IDE, it's hard to innovate in language design.

Rust does have rust-analyzer, but it uses piles of RAM and often just doesn't work. I'll periodically try it for a few days and give up on it again. Maybe it's a bug in Kate's LSP support.

Post reply on HN