Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
[flagged] Rust is not the language for you if you don't like traits (github.com/marshallpierce)
83 points by shantnutiwari on Oct 4, 2023 | hide | past | favorite | 65 comments


This sort of thing is why packages should always be namespaced. Just "base64" without any additional qualifiers makes it seem more official and definitive than it actually is.


I get the impression that some people think of crates.io as purely a place for distributing arbitrary Rust free software, while others think it's also a place where people are building something like a community-developed "batteries included" standard library for Rust.

I think a fair amount of unpleasantness in recent years has come from this disconnect: some people think that by publishing on crates.io you're making some promises (that they might not assume simply for, say, having a repository on github).

To me, using an extremely generic name like 'base64' does suggest that you're in the second camp, and so that you might expect to have a conversation that feels more like "we're equals building this project together" than "I'm the maintainer and my judgement is all that matters".


Don't all languages, that have this kind of community developed packages, have the same problem? I expect golang, npm and python to have similar issues. Python has less issues because they have a bigger standard library but if you want to do anything advanced you need third party packages.

I feel like most of these issues stem from the very young age of Rust (2015 -> v1.0). Give it a few years and these problems will stabilize as the long term crates will survive and the short term will grow stale.


Golang doesn't because all packages are namespaces by domain name (and more often that not that domain namespace ja GitHub which has its own further "org" namespacing)


I think you are right. Though I think that one can have all the benefits of the “community-developed stdlib” with the namespaces approach as well — e.g. Java’s new Date/Time API actually comes from a third-party package called jodatime, it was just so good that it found itself implemented in the standard library of java, and then later on plenty other languages as well.


Rust has done this as well; hashbrown was an external package, but now powers HashMap and friends.


Great observation. This helps me reconcile the tension I feel between my “maintainers own us nothing” mentality and my disappointment with the way the base64 API issues have been handled.


Indeed. I have on occasion joked about starting a "crates-name squatting" business; pick a bunch of common names and buzzwords and hog them and give them up for $$, like domain squatters do.

I see the arguments against organization/namespacing in Rust (ala Maven or NPM) and I kinda shake my head. The reality is, crates.io is a crazy bazaar, people end up taking crate names and then abandoning their projects, leaving that name forever unusable.

e.g. at work we have an internal crate named "event" (on our internal repository) that conflicts with an abandoned public crate of the same name that hasn't had commits in 8 years. This leads to confusion if you get your cargo config wrong. But it's also kinda frustrating that this very generic name is ... lost to time now.


Looks like "swmon" beat you to the punch.

https://crates.io/users/swmon


It's neat how positively I can hear an idea like this and go "haha, what a fun idea," and then see it actually executed on and get a visceral "you are a terrible human" vibe, like that "Contact me if you want to use this name!" description makes me viscerally angry.


That's terrible.


Some prior discussion on namespacing packages in Rust:

https://internals.rust-lang.org/t/blog-post-no-namespaces-in...


I don’t like this crate either, it’s frustrating to use… but you don’t win any prizes for having a go at open source maintainers.

Create an alternative crate if you care enough, or pick a different crate to use. You can even literally pin to a previous version of this crate.

I have zero sympathy for folk coming along to a closed issue, which has been clearly closed and explained and trying to tell the maintainer they know better.


I have mixed feelings on this advice. On the one hand, it's not fair to criticize volunteer maintainers too harshly. On the other hand, the same person would probably see forking + marketing a fork as an attack—maybe not in the case of a small utility library, but certainly in the case of larger projects. A fork would be seen as an attempt to split or take over the community around the project because, well, that's exactly what it is. If you feel no sympathy for the users commenting on the issue you ought to feel not sympathy for the original maintainer in that scenario, and that seems like an unhealthy dynamic for open source as a whole. (For what it's worth I would feel no sympathy for maintainers that act like the one in this issue, but in general I would prefer people to spend some real effort on discussing and resolving disagreements before trying to fork anything important!)


Yeah you're right. I would never use this lib because I completely disagree with the maintainer in all regards here, from the coding choices to the motivations for doing what they did.

There's no point going to the issues tracker to tell him/her that though: just move on and pick a nicer library/maintainer.


There are two guardrails: 0. not being unprofessionally, unnecessarily critical 1. while delivering and receiving necessary constructive feedback about usability. It's a signal suggesting narcissistic tendencies without an ability to cooperate or grow, to be against listening to constructive feedback or complaining about the gift of feedback if it wasn't delivered in precisely your perfectly arranged, expected format and process others aren't aware of.


It's also not that simple.

People forget that base64 has variant _all the time_, that leads to bugs.

So deprecating `decode` made sense.

But then what do you do instead?

a `decode_**` for each standard variant ... not really nice design

a `decode2(data, standard)` better but if you anyway need to import the standard and one additional thing, that thing could be a trait instead of a method and the `2` in the name is quite confusing

a braking change? definitely not worth it

a `prelude` module which exports the engine trait and reexports like `BASE64_STANDARD`? Well he did that.


Why is decode_* not a nice design?


Because you are now encoding parameter choices in function names instead of making them parameters.

I mean it's not terrible design.

But having to do a `use base64::prelude::{Engine, BASE64_STANDARD}` is also not terrible design.

Nor is `use base64::engine::{Engine, general_purpose::STANDARD as BASE64}`, through it's less nice.

So given that there is already and equally good design there anyway, there is no reason to add additional code, especially if that code would make it easier to make a mistake when using it.

I guess if this would be designed now from scratch it would have something like a `decode(data, standard)` function, but `decode` is already in used (even through deprecated) so we can't have that.


I don't see the problem here at all. What prevents somebody from writing a 5 line helper wrapper that provides the easier API either in their project or as a small crate if they want to share the helper between projects?

That's the benefit of having a more explicit API. Doing it the other way and making a generic API on top of a simplified one is harder.


I agree, thinking in layers is super helpful here. I might prefer the higher-level, simpler API was part of the same project as the low-level API (esp. given the name recognition here), but when it isn't, I can go make my own high-level API.

I'm not a rust user; is there anything preventing someone from making a "base64-simple" crate which uses this base64 crate to make a higher-level API?


No. It would likely be 4 lines in a 'utils' folder/file.

I was on the opposite side reading the github comments, notably because of my recent usage of python base64 but your (and GP) comments make a lot of sense, i wasn't using logic but habits. Thanks.


UI/API rule number one: the thing you do most frequently should be the easiest thing to do.

There’s a reason that words like “the” and “it” are not 60 characters long in any spoken language.

If you’re making it super verbose to do very common tasks, you’re fucking up your interface.


I tried to find a copy of Rusty Russell's API Design Manifesto to get another respected voice to back this opinion, but the most-linked to version of it now sits behind a Google sign-in, and (somewhat ironically) search results for Rust API documents/blog posts/reddit threads make other copies hard to find.


Here are the original lists:

How Do I Make This Hard to Misuse? - https://ozlabs.org/~rusty/index.cgi/tech/2008-03-30.html

What If I Don't Actually Like My Users? - https://ozlabs.org/~rusty/index.cgi/tech/2008-04-01.html


Looks like we're out of luck, even with a Google sign-in:

> sweng.the-davies.net points to the site "sweng" which does not exist. Please contact the domain administrator.

There are archives, however: https://archive.ph/NZHmW

...and TIL that despite the name, this is not Rust-specific.


I actually like this design choice. Having dealt with these kind of bugs, only to have to switch to the URL-safe base64 encoding, makes me really appreciate it.

It forces the developer to consider which configuration they want, and in that, actually realize that there is a difference between URL-safe and the standard version.


That was a breaking change, and was a medium-sized headache, in that it broke some crates. As an original design decision it would not have been too bad, but as a breaking change, it was.


Apparently the author also thinks being respectful of others shouldn’t be a default


I think the author is just rally feed up by people not searching closed issues, opening duplicates and being annoying about the same already discussed issues again and again.

That doesn't make it good, but understandable.

Not reading or looking into the context is also a common HN I mean how many people commenting did look up the context?

And why is a small open source crate for a minor annoying design aspect even on hacker news just because it's called base64????????


Don't read the rest of those github comments if you'd like to maintain respect for anyone involved.


I don't disagree with the idea that a relatively complicated base64 API seems painful but...

> Normally I agree with explicit being better than implicit, but I don't see the harm here. If there's no specific interoperability requirements, explicitly choosing a configuration isn't particularly important.

Pretty much the entire point of base64 is interop, so there would always be specific interop requirements.

And since a base64 library tends to be reflexive, a library's default tends to either "way too strict to consume any base64 you can find in the wild" or "so loose you can get a carrier strike group through" e.g. Ruby and Python will strip out any invalid character from the input before attempting a parse, python requires padding to be present but I'm not sure there's any way to make ruby's decode64 fail as long as you give it a string since it does not.


I am not sure what you are looking for, but ruby has strict_decode64 which does fails on invalid characters and invalid encodings, and urlsafe_decode64, which relies on that too. I think they've been there for a few years.


I’m not looking for anything, just pointing out that defaults are insanely variable, and people use them because they are the default. If you don’t know and don’t care and need to generate base64 you’ll use decode64 because that’s the default and it worked fine.

And if I have to interact with that, it’s an interop issue


It does seem unfortunate that what's apparently (given its name) the 'default' base64 crate for Rust can't expose a simpler interface. Most people don't need optimally efficient base64 encoding. It should suffice to expose 'encode' and 'decode' functions that take some parameters configuring the encoding. That's not to say that the more complex design of this library is necessarily bad, just that it seems to be motivated by goals that won't be relevant to most people who just want to encode a smallish blob.

Maybe this illustrates why it's good to have base64 in a language's stdlib. That way 90% of people can just use a couple of simple functions, while libraries like this can still exist for those who really need them.


It’s not about efficiency. It’s about interoperability. There are a gazillion minor variants of Base64. Being explicit about which one you’re using is entirely sensible.


Yes, but you can achieve that just by having a normal function that takes some configuration parameters. The documentation of the library suggests that efficiency was a significant concern, and I assume that’s why the implementation is not as straightforward as it otherwise might be.


> This has already been discussed extensively elsewhere. I am not sympathetic to concerns over useing a trait. Rust is not the language for you if you don't like traits. Feel free to collect a full refund on your way out.

Without weighing in on the merits of the comment, the delivery feels very Poettering-esque.


yes and it has little to do with liking or dislinking traits tbh. having to import a trait to use what boils down to a single pure function is never good design

BUT the convenience methods defaulting to "standard" base64 instead of "url safe" base64 because it's one of the things where people don't think about there being more then one standard/configuration and it then loading to bugs in their code

so deprecating it makes sense, and without a braking change (which makes no sense here) you can't replace it with anything better

and because of the prelude module the import isn't that bad e.g.: `use base64::prelude::{Engine as _, BASE64_STANDARD};`

and even ignoring that most imports are auto generated, sorted and formatted by rust analyzer for most people most of the time

so it's eitherway at most a minor anoyence

so I can understand that the author is feed up with people annoying him about that again and again and again


I know it's not entirely fair, but seeing stuff like this makes me wary of the Rust community.


Yeah, it's not fair because there's no way this person represents the Rust "language community" it's just a couple people arguing on a bug ticket.

And in fact there's others who would make a counter argument that excessive reliance on traits is a bad over-complexity-smell.

The reality is it's fairly large language community already, and lots of people have lots of different opinions.


Every language will have people who make extreme statements of one kind or another. I wouldn't call that representative of the community in general.


I have bad news for you about <any language> community…

People behaving poorly on github issues/PR discussion is so common in every language it tells much more about the internet/open source culture than it tells about Rust users (there's no such thing as a “Rust community” nowadays BTW, it's not 2016 anymore and the language user base has grown so much the user base is now as fragmented as it is for any mainstream language).


Pretty sure the maintainer is also a Discord mod.


new language...same old dickheads...why are these people even contributing anything? they obviously dont care about the users


It’s free software. There is really no obligation that they need to discuss closed issues.

If it matters so much create one of your own. Why have a go at open source maintainers doing things on their own time?


Entitled mindset that equates "open source" with "free stuff to make my day-job easier."


[flagged]


I'm asking sincerely, not snarkily: is that a problem for you? I've worked on a largish project with several other people, and occasionally a new feature would come up that would allow us to simplify the code. We'd tell each other, hey, I'm using new feature `foo` in the branch I'm hacking on. You'll need to be on at least 1.xx.yy to build it. Then we'd all run `rustup upgrade` and verify that it didn't break existing code, and if not, onward and upward.

Alright, I could see how that would be a PITA at a large company with a huge codebase, but I don't think there are yet a lot of Rust shops like that. I see the Rust version treadmill as similar to Python's, where it's nearly always backward compatible (let me stop ya right there, anyone who mentions 2-to-3; we're talking minor versions here) and new features are almost only additive.

Note that I'm not saying you're wrong if you disagree with me. It's more that the theoretical issues have been, well, theoretical in my personal experience so far.


Yes. I am speaking from specific experience.

I got into Rust around the 1.4 to 1.5 days. Rust 1.50 programs can't be compiled and run with Rust 1.48 rustc. My rustc compiler was literally 3 months old. Both times I went to compile a rust program I found they devs used features not included in the rustc I had. One was a software defined radio spectrogram generator, the other a web scraper and assembler for web serials. I talked to the author of the rust sdr spectrum program and he was able to write a version with older up-to-1.48-only features that worked.

That and the insistence on always using out of repo rustc via curl rust.up | sh etc put me off rust completely.


Was there a reason you couldn’t upgrade to 1.50?


Yes, I don't think doing curl rust.up | sh is a reasonable thing to do. I am only going to get language toolchains from my distro's repos.

Also, now we're ignoring that my rustc was only 3 months old and couldn't compile most things people were writing in rust? That's the point of this entire conversation. Let's not derail.


> Yes, I don't think doing curl rust.up | sh is a reasonable thing to do.

Eh, it's a one-time thing to install rustup. Then you can run `rustup upgrade` whenever.

> I am only going to get language toolchains from my distro's repos.

Ouch. OK, that's the real root of it. I haven't worked in a shop that used Python from the OS repos in... well, ever. We use to download/configure/make the source tarball from python.org. When pyenv came along, we switched over to using that. I upgraded my personal machine to use Python 3.12 earlier this week on the day it was released so I could start testing for compatibility with existing code.

I was pleasantly surprised to see my distro has Python 3.11.2 available in its repo, which is more modern than I'm used to seeing in the "native" package. That's a lot better than for the Java folks, who could only install JDK 17 from the distro when 21 is current.

> Also, now we're ignoring that my rustc was only 3 months old and couldn't compile most things people were writing in rust? That's the point of this entire conversation. Let's not derail.

I think you're right: Rust isn't the language for you. I don't mean that in a bad or smart-alecky way. It's more that the people writing the libraries you described found a new feature in the publicly availably new version of rustc, then started using it because it made their lives easier. There wasn't a compelling reason not to use that feature because everyone could freely upgrade to the new version of rustc, just as they had, without breaking existing code.


As an example of where it is a problem: anyone attempting to learn Rust runs into a huge amount of example/tutorial code that isn't all that old but will fail to compile on the latest rustc. It makes for a really difficult learning experience.


That is the opposite problem from what the person mentioned, and not a real problem. Rust is extremely good about backwards compatibility. With only a few very extreme exceptions you can take anything written from 1.0 on and build it with a new compiler.

What the comment said was:

> can't compile something written by a rust dev today with a rustc compiler from 3 months ago

This is taking new code and using it with an old compiler. Because of how deadly seriously rust takes backward compatibility, it tends to not be an issue. Just get the newer compiler to build the newer code.

This also isn't a unique problem to rust. You can't use features in any language with compilers from before they were introduced. Funny enough, even with rust's rapid growth, I actually have less issues with it in rust because of the ease of upgrading.


> Just get the newer compiler to build the newer code.

I think part of the problem is that this is backwards to how people coming from other traditional languages (like C, or C++) think.

With those, you deliberately choose your target compiler in a way to maximise who can build your software. Telling all your users "just get the newer compiler" is rude. If you can reasonably target a 20-year old version of the compiler, so that users on systems who can't upgrade their compiler for reasons you have no control over can still build and use your software, then that's a trade-off worth considering.

Note that you don't always have to choose that, but you should consider it. And when you do decide to move from, say, C89 to C99 (or - gasp - C11), that is a carefully considered decision. It's not just ooh, shiny.

You don't always know who all your users are, or why they may not have the same flexibility as you. But if you want your software to be installed on 10 billion devices, that's the sort of thing you have to consider.

https://daniel.haxx.se/blog/2022/11/17/considering-c99-for-c...

https://curl.se/docs/faq.html#How_many_are_using_curl


I feel that. I've worked in those environments. A previous job we had a C89 code base that very deliberately could only build with certain older compilers. It was made to be able to target ~20 year old OSes and embedded environments. We had to be extremely careful about new features used, and if we tried to update the tool chain.

> Telling all your users "just get the newer compiler" is rude.

With Rust you don't have the same things holding you back. Features and targets are extremely well supported and for a long time. This compatibility is a die hard sacred tenant. This a good thing! It should be celebrated and shouted from every roof top! It isn't rude that the level of engineering allows this to be a low drama affair. Without the use of RUSTC_BOOTSTRAP it is very rare to have something holding you back on an older, stable compiler. I can think of one major bump of supported OSes a while back and that's it.

You can stay on older versions of the compiler if you really want to, but don't expect to be able to build new code that uses new features.


That's just not how Software is done in this century, like it or not. Please update your software regularly.


[flagged]


I make it a point to seek out negative opinions of the projects I work on, because a lot of the time there's at least a kernel of a bug report behind every complaint.

> BULLSHIT!!!

> Have you tried listening to yourself?

But this? This is the exact kind of attitude I find every now and then that makes me throw my hands in the air and think "why the fuck do I bother", before I retire to my issue tracker for a while.

> It's not a problem that nobody can use the tutorials to learn the language because the language keeps changing every three months and the tutorials no longer work?

The GP is arguing that it is not a problem that occurs and that the complaint in the root comment is about the opposite problem. You're misreading the person you're so passionately replying to.

> It's a real problem.

Can you point at any change in the past 12 months that would make the teaching of the language with an older tutorial no longer useful/confusing/a problem at all?

> I know a lot of people who won't give Rust the time of day because of this issue. It's hard to take the language and community seriously while this real problem persists.

I always try to get to the underlying problem that can be solved, if not for the person complaining, for anyone that will come after. But here? I am struggling to see anything actionable. The language doesn't change as much as you're implying, we make an effort to ensure that the developer experience for newcomers is as good as it can be. We have a lot of work ahead of us, but I look at what we've done since 1.0 and it makes me proud of where we are today.

There are two separate concerns:

- building new projects with older Rust, what the root comment is complaining about, which is a factor of how quickly the ecosystem adopts newer language/std features. The options there are to use older versions of the libraries or update their Rust version. Anything else is complaining that Office 97 cannot open files from Office XP.

- building older projects with newer Rust, what you claim to be a show-stopping issue with Rust. I haven't seen evidence that this is a prevalent issue. I would love to see it if you do have it.


If you encounter these kind of things, and the tooling doesn't explicitly and clearly tell you what, when and why things have changed, that's a bug and I would appreciate a bug report.


> a huge amount of example/tutorial code that isn't all that old but will fail to compile on the latest rustc

[citation needed]

Rust has maintained backward compatibility to a level even beyond what golang has done. Code written for Rust 1.0 will compile on latest Rust, minus a very scant few edge cases where it should never have compiled in the first place except for a compiler bug.


You could conceivably encounter cases where cargo init sets your project to 2021 edition and you're following a 2015 tutorial and encounter compilation errors due to edition differences, but when these happen the error should have enough information to make it clear this is the case.


Do you have some examples of that code that isn't all that old but will fail to compile on the latest rustc?


Not my experience at all. Rust "editions" fairly clearly address many concerns around this.

But I do think that crates.io is a wild west in terms of quality and consistency. Just like npm is. And while crates.io is intimately bound up with cargo, and with Rust dev generally, it doesn't equate with Rust.

I personally think there's a good argument to be made for certain kinds of closed, commercial software projects to just avoid it entirely and carefully curate their 3rd party deps and avoid going out to crates.io to get them.

I'd personally prefer (for some projects) a model of "vendoring" (checking-in) third party dependencies.


I really wish people would drop the "explicit is better than implicit" mantra.

What "explicit" means vague. Does it mean you want the code to be verbose? Noisy? Because that's silly, and Rust doesn't even have a history of doing that. We went from try! to ?, we went from impl Future to async/await. I'd rather people talk about what they really mean than just repeating that line over and over again.

edit: also it's really weird the OP seems to keep wanting to post this thread. If you don't like their library, fork your own?


I personally would like to have the raw interface or both the raw and simple interface available. Some package maintainer (in whatever language) would assume everyone has the same requirement as them and make only the 'ultra simplified interface' available. And it's generally a big headache if it didn't met your requirement. So you end up copy paste and modify or forking the whole project.

But that could totally be avoided if you just export both of them instead of hard-locked the interface. People don't really want to fork the god-damn project just to change the two character you hard-coded.

Even marking them unstable and making it unsupported would be far better than locking it down completely.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: