4 ms·
Yeah… Please no. I’m getting a bit of a macro fatigue in Rust. In my humble opinion the less “magic” you use in the codebase, the better. Error enums are fine.
by jgilias 1y ago
Yeah… Please no.
I’m getting a bit of a macro fatigue in Rust. In my humble opinion the less “magic” you use in the codebase, the better. Error enums are fine. You can make them as fine-grained as makes sense in your codebase, and they end up representing a kind of an error tree. I much prefer this easy to grok way to what’s described in the article. I mean, there’s enough things to think about in the codebase, I don’t want to spend mental energy on thinking about a fancy way to represent errors.
- Waterluvian 1y agoAgreed about magic. Please correct me if I’m misunderstanding this, but something that surprised me about Rust was how there wasn’t a guaranteed “paper trail” for symbols found in a file. Like in TypeScript or Python, if I see “Foo” I should 100% expect to see “Foo” either defined or imported in that specific file. So I can always just “walk the paper trail” to understand where something comes from. Or I think there was also a concept of a preamble import? Where just by importing it, built-ins and/or other things would gain additional associated functions or whatnot. In general I just really don’t like the “magic” of things being within scope or added to other things in a manner that it’s not obvious. (I’d love to learn that I’m just doing it wrong and none of this is actually how it works in Rust)
- jgilias 1y agoYou can import everything from a module with a *, but most people seem to prefer to import things explicitly. But, yes, you can generally figure out easily where things are coming from!
- itishappy 1y agoDoesn't something like the following break the trail in pretty much all languages? from package import *
- Waterluvian 1y agoYup. And I’ve not seen that used in forever and it’s often considered a linting error because it is so nasty. So maybe what I’m remembering about Rust was just seeing a possible but bad convention that’s not really used much.
- 57473m3n7Fur7h3 1y agoIt’s a bit confusing sometimes with macros that create types that don’t seem to exist. But usually when I work with code I use an IDE anyway and “go to definition” will bring me to where it’s defined, even when it’s via a macro. Still generally prefer the plain non-macro declarations for structs and enums though because I can easily read them at a glance, unlike when “go to definition” brings me to some macro thing.
- burnt-resistor 1y agoYes. Macros are a hammer, but not everything is a nail. Declarative macros (macro_rules) should be used to straightforwardly reduce repetitive, boilerplate code generation and making complex, messy things simpler. Procedural macros (proc_macro) allow creating arbitrary, "unhygienic" code that declarative macros forbid and also custom derive macros and such. But it all breaks down when use of a library depends too much on magic code generation that cannot be inspected. And now we're back to dynamic language (Ruby/Python/JS) land with opaque, tinkering-hostile codebases that have baked-in complexity and side-effects. Use magic where appropriate, but not too much of it, is often the balance that's needed.
- quotemstr 1y ago> Yes. Macros are a hammer, but not everything is a nail. Overuse of macros is a symptom of missing language capabilities. My biggest disappointment in Rust (and probably my least popular opinion) is how Rust botched error handling. I think non-local flow control (i.e. exceptions) with automated causal chaining (like Python) is a good language design point and I think Rust departed from this good design point prematurely in a way that's damaged the language in unfixable ways. IOW, Rust should have had _only_ panics, and panic objects should have had rich contextual information, just like Java and Python. There should also have been an enforced "does not panic" annotation like noexcept in C++. And Drop implementations should not be allowed to panic. Ever. God, I hope at least yeet gets in.
- zbentley 1y ago> Rust should have had _only_ panics, and panic objects should have had rich contextual information, just like Java and Python. It could have gone that way, but that would have “fattened” the runtime and overhead of many operations, making rust unsuitable for some low-overhead-needed contexts that it chose to target as use-cases. More directly: debug and stack info being tracked on each frame has a cost (as it does in Java and many others). So does reassembling that info by taking out locks and probing around the stack to reassemble a stack trace (C++). Whether you agree with Rust’s decision to try to serve those low-overhead niches or not, that (as I understand it) is a big part of the reason for why errors work the way they do. > There should also have been an enforced "does not panic" annotation like noexcept in C++. And Drop implementations should not be allowed to panic. I sometimes think that I’d really love “nopanic”. Then I consider everything that could panic (e.g. allocating) and I like it less. I think that heavy use of such a feature would lead to people just giving up and calling abort() in library code in order to be nopanic-compatible, which is an objectively worse outcome than what we have today.
- throwaway894345 1y agoBoth sides have been a pain for me. Either I’m debugging macro errors or else I’m writing boilerplate trait impls all day… It feels like a lose/lose. I have yet to find a programming language that does errors well. :/
- dingi 1y agoAnnotations were once condemned as 'magic' for doing things at runtime. Now it's apparently fine to use a language where most non-trivial code depends on macros. Tools that rewrite your code at compile time, often invisibly. But hey, it's not magic if it's your magic, right?