NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
First Impressions of Rust (john-millikin.com)
quietbritishjim 1318 days ago [-]
> it doesn't even properly align the parenthesized expression after line-breaking it:

Fair enough if that's not your preference for how parenthesized expressions should be broken across lines, but this quote makes it seem like it's objectively wrong. In fact it's very much a matter of opinion, and personally I hate the style of line breaking that he describes as "properly" aligned because you end up with a distracting pattern of indentation, and parameters get all squished into a tall narrow column:

    x = long_function_name(first_param,
                           second_param,
                           another_fn(x
                                      + y
                                      + z))
Yuck! In Clang-format, you can avoid this with the "AlignAfterOpenBracket: AlwaysBreak" option, which also wraps the first parameter / operand to the next line if it can't all fit onto one line:

    x = long_function_name(
            first_param,
            second_param,
            another_fn(x + y + z))
Just to reiterate: I appreciate that many people would still prefer the first style, and of course that's a legitimate opinion. My point is just that it's also a legitimate opinion to prefer the second style, not something you can describe as "not properly aligned".

Of course this is a nitpick on an excellent article.

rkangel 1318 days ago [-]
This was the key line: > I eventually gave up on trying to make the formatted rust-fuse code look pretty, and settled for "consistent".

It turns out that most aspects of coding style are subjective and are fine once you get used to them. The *-fmt tools that are now the fashion get everyone past that initial stage of formatting things as you personally would and get you used to a common style.

Maybe one person (the author of the style tool) is completely happy with the chosen style, but consistent is more important than personal preference on details.

arethuza 1318 days ago [-]
One thing I've learned over the years using a lot of different languages is to pretty much ignore my initial reaction to syntax or formatting conventions for any given language - there is a pain period and then you get used to things and move on...

Edit: I'm particularly thinking of PostScript, Lisp and Python - which on first impression seemed crazy but I actually learned to really like.

rkangel 1318 days ago [-]
I have a similar thing when I work on a new codebase (or join a new company for that matter): make a note of all the pain points, but don't do anything with them for a few months.

It'll turn out that a lot of them were for a good reason, but some of them won't be and the existing team has just got used to them ('missing stair'). That's why the notes are important, because you probably have too!

arethuza 1318 days ago [-]
Mind you - I have joined places that were genuinely crazy (no source control, no backups, deployment by RAID...) where some things needed fixed immediately.

That was a long time ago though.

benji-york 1318 days ago [-]
> deployment by RAID

I'd like to hear that story.

arethuza 1318 days ago [-]
The company supplied on-premise server 'appliances' for a particular market niche.

To create a new deployment, find an existing server (usually at an existing customer), take out a mirrored RAID disk and replace it with a blank one. When mirroring complete put old one back in and take your new copy and use it in a new server for the new customer....

Repeatable build process, repeatable deployment process - who needs that when you have the power of RAID-1! <sob>

Fortunately, it was a long time ago....

ufmace 1318 days ago [-]
Wow. That's both amazing that somebody thought to do that and it worked, and terrifying that it became the official solution for production deployments.
pornel 1318 days ago [-]
This taboo of having opinions about code formatting shuts down legitimate criticism of rustfmt's design and implementation.

There are cases where rustfmt is just bad. I'd argue "objectively" bad:

• match arms are formatted individually, so nearly-identical arms can end up looking wildly differently if they hit different fuzzy logic thresholds. In Rust, enum variants aren't types, and macros can't see enum variants in the match context, so repetitive match arms are sometimes a necessary evil.

• deletion of a line can fold a multi-line construct into a single line. This makes diffs bigger and harder to review.

• rustfmt throws away any human influence on layout of code (short of sorting functions alphabetically). It doesn't merely change the boring bikeshedable mechanics like where the spaces go, but significantly rearranges how expressions are laid out and separated from each other.

For example:

    let value = do().something().to().get().a_value_maybe()   
       .or_else(|| some_error_handling_here)?;
I think the code above is great, because the happy path is on one line, and error handling is on the other. Rustfmt intentionally erases that:

    let value = 
        do().something().to().get().a_value_maybe().or_else(|| some_error_handling_here)?;
That is IMHO bizarre. The value is what? Oh, there's spaghetti in the second line.

Gofmt is way better. It fixes formatting errors it understands, but when there are multiple correct ways to format a piece of code, it leaves the higher-level structure as-is. OTOH Rustfmt has an overriding opinion on everything. Non-negotiable heuristics replace all common sense.

There's no other production-quality formatter for Rust, so usage of rustfmt boils down to:

1. We must use something 2. Rustfmt is something 3. Therefore, we must use rustfmt

bluejekyll 1318 days ago [-]
> Maybe one person (the author of the style tool) is completely happy with the chosen style

I remember there being quite a lot of community outreach to discuss pros and cons of all sorts of different rustfmt style options.

All of them were very thoughtful, and made what I think has ended up with a set of decent compromises.

jmillikin 1318 days ago [-]
Your formatting style works too, and rustfmt will switch to it for function calls that exceed the line width limit.

rustfmt is not properly handling alignment in combination with hard tabs. It should either break after the open paren and indent both names, or break near the '+' and align them both.

Good output if aligned:

  field: (value_1
          + value_2)

  field: (value_1 +
          value_2)
Good output if indented:

  field: (
      value_1
      + value_2)

  field: (
      value_1 +
      value_2)
Output of rustfmt:

  field: (value_1
      + value_2)
For the same expression to be half aligned and half indented is an error.
majewsky 1318 days ago [-]
My personal impression from these examples you gave is that line-breaking inside an arithmetic expression is generally a horrible idea. If you have something like

  let result = (first_long_variable + second_long_variable) * (third_long_variable + fourth_long_variable);
My position is that the only way to make this look good under a line length limit is

  let factor1 = first_long_variable + second_long_variable;
  let factor2 = third_long_variable + fourth_long_variable;
  let result = factor1 * factor2;
(where of course `factor1` and `factor2` would be given names that make sense in context)
quietbritishjim 1318 days ago [-]
Thinking about it, you're probably right. One thing you're missing for your comment is different field name lengths, which is important because you seem to care about alignment of field values:

    field1:                 1
    this_is_a_longer_field: 2
Playing with rustfmt online [1], I found that by default it doesn't do that:

    field1: 1
    this_is_a_longer_field: 2
As a sibling comment says, you must have an option turned on an option for this, and your complaint is that this option isn't working for these nested structs. I guess that's the risk of not using the formatter in its default configuration. But I agree it probably is a bug.

(You've presumably also got an option turned on for tabs. I honestly think that is quite a niche preference nowadays - cue flame war - so I can see that there would be bugs in that option too. But although you bring up tabs in your comment here and in your blog post, I don't see that it's related to the bug you're talking about. Once the formatter has (incorrectly, you argue) decided to format those lines as "one more level of indentation than the line before", it chooses the correct combination of tabs and spaces to do that.)

[1] https://play.rust-lang.org/?version=stable&mode=debug&editio...

jmillikin 1318 days ago [-]

  > You've presumably also got an option turned on for
  > tabs. I honestly think that is quite a niche
  > preference nowadays
gofmt always indents with tabs, so I'd argue that it's not _that_ niche.

One might also argue that, as a zero-cost abstraction for consistently applying a developer's preferred indent depth, they are the most Rust-appropriate option </s>.

  > Once the formatter has (incorrectly, you argue) decided
  > to format those lines as "one more level of indentation
  > than the line before", it chooses the correct
  > combination of tabs and spaces to do that.)
I'm not sure that's the case. It seems to be correctly aligning it when using spaces, so I think the issue is that somewhere it gets confused about whether to indent or align. A lot of very old indenters will treat tabs and spaces as interchangeable, which is why you see so much poorly-formatted C in open-source UNIX tools.
nybble41 1318 days ago [-]
> A lot of very old indenters will treat tabs and spaces as interchangeable, ….

Indeed. If you're going to align expressions in a file that uses tabs for indentation then you need to use tabs up to the block indentation level, but spaces after that for the alignment. That's the only way to ensure that the lines continue to be aligned for any tab-stop setting. Many editors will mangle this horribly, however, by replacing some or all of the spaces with tabs. If you're using tabs for indentation then you really need to turn on visible whitespace and also disable automatic conversion of spaces to tabs unless you're sure your editor is one of the few that gets it right.

Macha 1318 days ago [-]
rustfmt's defaults would agree with you. The kind of alignment it did in OP's example is an option you need to turn on.
quietbritishjim 1318 days ago [-]
In fairness I just tried their example in the Rust Playground [1] online and it gave exactly the formatting they showed [2]

[1] https://play.rust-lang.org/

[2] https://play.rust-lang.org/?version=stable&mode=debug&editio...

Edit: I just realised the example I showed is different in that it doesn't try to line up all the field values (for fields that do fit on one line) so it must actually have some other option set, like you said.

abstractbarista 1318 days ago [-]
I don't like either of these. Keep it all on one line.
quietbritishjim 1318 days ago [-]
You mean never wrap code and have a really long horizontal scroll? These things are subjective and you're certainly entitled to your opinion, but is say that's fairly hardcore.
nybble41 1318 days ago [-]
You could let the editor soft-wrap the lines in place of horizontal scroll. Done well this could be the best of both worlds—adaptive to different screen/editor sizes, and the viewer decides how to indent or align the wrapped lines according to their own preferences. However, proper expression alignment would require solid language support from the editor. (Wrapping with simple indentation wouldn't be too difficult.)
david2ndaccount 1317 days ago [-]
I have vim set up to do this, it’s so nice.
pcwalton 1318 days ago [-]
You should be able to get the size of c_ulong without any dependencies using std::mem::size_of::<std::os::raw::c_ulong>(). I usually use std::os::raw instead of the libc dependency in my own crates, even though some people consider it bad style to do so. (Working in graphics it's often the case that I don't need anything from libc except a few data types.)

Another note: The notion of a "compilation unit" in Rust is fuzzier than in C/C++, because of incremental compilation. The goal is to be able to point rustc at a crate and have rustc/cargo internally decide which parts of it should be recompiled and which can be cached. A good chunk of this is already done today—for example, rustc will internally split up single crates into multiple LLVM compilation units to get better parallelism during the codegen phase—but more can definitely be done. Basically, Rust leans more on "compiler heroics" than C/C++ traditionally has, in that the compiler effectively splits up source files automatically instead of the programmer manually doing so.

jmillikin 1318 days ago [-]

  > You should be able to get the size of c_ulong without
  > any dependencies using
  > std::mem::size_of::<std::os::raw::c_ulong>().
That's very useful, thank you! I hadn't noticed `std::os::raw` before, but it's exactly what I wanted.
AbuAssar 1318 days ago [-]
Author’s opinion on rust:

"I really really enjoy using Rust. It is nearly everything I want in a systems programming language, and the few parts it's missing are due to legitimate technical difficulty. The amount of careful thought I've seen put into its design – crafting async/await to work in no_std environments, or the new inline assembly syntax – has produced a language that is not only better than what I could have designed, it's better among axes I was not even aware existed prior to reading the Rust RFCs."

thenewwazoo 1318 days ago [-]
I went into this expecting yet another barrage of complaints about lifetimes, but was very pleasantly surprised. This is probably one of the most thoughtful experienced-programmed new-to-Rust reviews I've read in a long, long time. I frankly don't have much to add, except to say that, once you really understand the language and start building complex projects, this article really does describe the real issues you run into.
saagarjha 1318 days ago [-]
I think I am familiar with Rust–I spent a week or so working with it–and I ran into many of these exact issues. I appreciate it very much when someone can give a viewpoint of of using a language beyond the superficial one ("arrays start at one in Lua"), or complains about something core to the language ("C pointers are confusing") and actually says something you will run into but is not obvious from having a basic knowledge of the thing ("while Python supports functional programming, it does not do so very well"). Rust's (intentionally) anemic standard library, strange dance around nightly ("we never break things…except in nightly, which we know you are using for your project because we gated all the features behind it") and a general sort of superiority towards npm when cargo/crates.io shares many of the same issues are the ones I ran into personally. And again, you don't have to be an expert to see these, but they're in this sweet spot between nonobvious and "something that'll go away if you use the language more".
Diggsey 1318 days ago [-]
> which we know you are using for your project because we gated all the features behind it

I don't think that's really fair, or at least hasn't been true for a long time now. Use of the stable channel far exceeds use of nightly according to all the surveys. At my company we've always stuck to the stable channel, and even in my own personal projects where I have no need for stability, I don't remember the last time I used a nightly feature, simply because I haven't found the need to...

I don't believe there are many cases left where you're forced to use nightly: most of the cases where people are using it is because there's a "nice to have" feature, not because that feature is actually essential. Even rocket, which was famed for using a ton of nightly features, now works on stable Rust.

vlovich123 1318 days ago [-]
Anyone doing OS development is still on nightly last I checked but aside from that stable has the features most people need.
rnestler 1318 days ago [-]
I'm curios which features OS development need from nightly. Maybe inline assembly?

I've been doing some bare metal embedded projects in Rust and didn't need nightly for quite some time.

monocasa 1318 days ago [-]
I use the following in my kernel project: asm, const_fn, const_generics, exclusive_range_pattern, global_asm, panic_info_message, start, untagged_unions.

Of those, I could get away with just global_asm, start, and const_generics if I had to, but the others certainly make my life easier in a kernel space without an allocator.

I'll be the first to admit that some of those are "I'm just going to embrace nightly if I'm stuck on it anyway".

pjmlp 1318 days ago [-]
If you want to profile your builds or compiler, nightly is still required.
kibwen 1318 days ago [-]
That's beside the point of what's being discussed here. The concern is that using unstable feature flags in your code, which only work on nightly, allows your code to be broken by compiler upgrades. But using nightly doesn't magically introduce unstable feature flags. There's no compability hazard from merely compiling a compiles-on-stable codebase with a nightly compiler for whatever reason.
pjmlp 1318 days ago [-]
Sorry if I thought tooling capabilities were a relevant compiler feature then.
p1necone 1318 days ago [-]
It's a hard balance to keep. On the one hand you don't want to hold back features that you know people need, but on the other hand - once something is in stable rust the design is kind of locked in forever.

It's still a fairly young language - I think it's a good thing they're being conservative with not setting too much in stone prematurely, while still having stuff released as part of nightly to see relatively widespread use. As the language matures more and more you will see less and less important features that are missing from stable.

k__ 1318 days ago [-]
"we know you are using [nightly] for your project because we gated all the features behind it"

yes, that kinda sucks.

steveklabnik 1318 days ago [-]
I am curious which features you and your parent use that are still nightly only! The majority of our users are on stable, but there's always gonna be some cutting edge stuff that people use.

(I'm a big user of asm! myself, but other than that, stick to stable.)

pjmlp 1318 days ago [-]
Recently I had to install nightly just to profile my build.
ansible 1318 days ago [-]
The asm!() to llvm_asm!() was a pain.
kibwen 1318 days ago [-]
The silver lining is that the reason for that change was because a proposal for stable inline assembly is actually making progress now, which is IMO fantastic and long overdue.
nindalf 1318 days ago [-]
Shouldn't it have been a simple find-and-replace?
ansible 1318 days ago [-]
> Shouldn't it have been a simple find-and-replace?

For a single crate, sure.

When you're managing multiple crates, an older nightly compiler version (because the software hasn't been tested much on the newer nightly), and git submodules... it isn't so easy.

I wasn't actually doing the work, but from the outside it seemed like a pain.

indolering 1318 days ago [-]
> strange dance around nightly ("we never break things…except in nightly, which we know you are using for your project because we gated all the features behind it")

Creating a beta channel or getting more of those features released in stable requires money or time.

rnestler 1318 days ago [-]
There is a beta channel already. But you'll only get the features which will land in the next stable release anyway 6 weeks in advance.
p1necone 1318 days ago [-]
Imo lifetimes aren't that complex. They're just a wholly new programming language feature - learning lifetimes is hard because you're simultaneously learning the syntax and the concept.

Compare to something like generics where it's roughly the same idea in most languages that feature them, you just need to learn the syntax and maybe some edge details that differ between languages (Contravariance and Covariance say hello!).

If you've ever helped someone who's entirely new to programming learn their first language you might see some parallels with experienced programmers learning entirely new features like lifetimes.

EamonnMR 1318 days ago [-]
I don't think the problem with lifetimes is that they are complex, it's that other languages handle lifetimes for you, but Rust outs to onus on you to manage them. C++ also has complex object lifetimes but if you don't invoke that complexity you don't need to deal with it.
theon144 1318 days ago [-]
>C++ also has complex object lifetimes but if you don't invoke that complexity you don't need to deal with it.

I would tend to disagree?

In C++, I regularly ran into issues where I "invoked" the complexity with memory/object management completely incidentally, and as the saying goes, shot myself in the foot (or rather, both feet, because lifetime management issues often result in heisenbugs and other really nasty phenomena).

Rust makes that complexity explicit, which is really an analogous argument as with static/dynamic typing; it's not that the dynamic languages "handle typing for you", and "static" simply requires more work. Rather, you're forced to deal with it at the very start, instead of down the road.

Then again I'm rather new to Rust, so I might misunderstand you?

EamonnMR 1318 days ago [-]
You're quite right, but it's worth being mindful that for many projects, down the road never comes. It's a very expensive insurance policy.
Ygg2 1318 days ago [-]
The only way to handle lifetimes is:

A) Introduce burden on programmer

B) Introduce burden on runtime (GC basically)

You just get to pick your poison. Do you want the upfront cost in syntax (Rust) or do you want the down the line cost (C/C++).

k__ 1318 days ago [-]
Coming from a dynamic typing background, I have to say Rust didn't feel much worse than Scala or OCaml to me.
anonova 1318 days ago [-]
I find it absolutely frustrating that Rust packaging/crates.io doesn't support namespaces. The arguments I've read are always theoretical/what ifs, but I've yet to be convinced the current situation is better than the practical benefits of namespaces.
TheCycoONE 1318 days ago [-]
Conversely the arguments I've heard for namespaces is that multiple people want to reimplement or make bindings for the same C library.

In maven central, in my anecdotal experience, namespaces usually either distinguish forks of the same library, or to group related libraries. There has never been, in my experience, a case where I wanted two packages with the same name in different namespaces.

I think a better system of handling unmaintained crates; with the possibility of reclaiming a name would go a long way with the author's use case. I don't have any great ideas here: package with no update in some time (a year?) is eligible. Someone requests to take over name - the author is notified and has a period of time to click an "I'm still here" button. If they don't - new author gets the name. Some 'super version' number is incremented so crate authors opt into the new or old foo. That last part is where I'm the most hesitant.

stefan_ 1318 days ago [-]
Of course a single project is very unlikely to depend on two different packages with the same name. But a global repository of all packages is conversely extremely likely to have many many people all wanting one name - it's essentially a .com registry.

Reusing project names is just a straight no-go when that is what other peoples projects depend on. As soon as a package has a dependency, (name, version, source) need to be absolutely immutable.

boris 1318 days ago [-]
As the person you are replying to suggestes, a version epoch could be a solution.
mlindner 1318 days ago [-]
There's a bigger problem that someone has reserved a ton of common names and they're all empty projects with nothing in them.
viraptor 1318 days ago [-]
Or even in a non-malicious case: https://crates.io/crates/logger

"logger" is now forever a middleware for the iron framework. Same with "router". Iron is pretty much obsolete now.

rat87 1317 days ago [-]
that sounds like a good thing.

It might have been good if the rust team themseleves had pre-squated

get rid of all the common names arguments and have everyone use prefixed or unique names

rkangel 1318 days ago [-]
Everyone complains that 'fuse' is taken so they have to use something with qualifiers (e.g. rust-fuse), and then they propose to fix this with a solution that requires that everyone uses qualifiers for everything.

It's a bit more consistent in that no-one gets good names, but is it really such a problem that a few people happened to get in early enough that they could call their library 'fuse'?

jmillikin 1318 days ago [-]
I'm fine with qualifiers, but I don't want useless qualifiers.

"rust-" or "-rs" is useless because it's on crates.io. "lib" or "-lib" similarly, unless it's part of a pair with a binary of the same name.

Here's a partial list of FUSE server implementations on crates.io:

  * fuse
  * cntr-fuse
  * drakey-fuse
  * fuse_mt
  * fuser
  * fuse-rs
  * polyfuse
  * fuse3
  * yarf
Why do we make people come up with custom prefixes or opaque codenames when they could all be ~user/fuse ?
tibbe 1318 days ago [-]
Why not user-fuse?
1318 days ago [-]
atombender 1318 days ago [-]
Names can be powerful. Owning a name like "fuse" implies that this is the thing called "fuse".

A flat "top level" namespace encourages treating names, especially short names, as something with intrinsic value. You end up with the same problems that the .com namespace has, such as name squatting and first mover advantage.

Qualifying all names removes this property from names and levels the playing field. There's no value in "owning" github.com/somename/blah. Or, to take the NPM approach, @somename/blah.

Macha 1318 days ago [-]
But then everyone just wants @fuse/fuse rather than fuse. If one project is @fuse/fuse and the other is @atombender/fuse, the first is going to have more legitimacy, just as if they were called fuse and atombender-fuse.
atombender 1318 days ago [-]
In reality, that does not seem to have happened, because the top-level is your name, and people have a different relationship to their own "branding", for the most part. People/companies also usually have more than one package.
ChrisSD 1318 days ago [-]
How do we decide which person/entity gets a namespace? What about namespace squatting? What if there's a dispute? What do we do about all the currently un-namespaced crates? How would Rust (the language) understand namespaces? How would cargo work with them?
dthul 1318 days ago [-]
If we really wanted, Cargo could start supporting namespaces and everything currently on crates.io could go to a new default namespace (and would still be reachable under the non-namespaced name for older versions of Cargo).

I don't think Rust itself needs to know about namespaces (as in: johndoe/fuse would still just expose a crate named "fuse". Crate name collisions can be handled with Cargo's already existing renaming ability.)

Yes, then the issue of namespace naming comes up. I guess that would be less of an issue than package-level collisions or squatting, but still, you don't want any random person to get the "google" namespace for example. Which could only be avoided by either manual review or something like DNS based verification (which has lots of drawbacks itself).

MrBuddyCasino 1318 days ago [-]
> DNS based verification (which has lots of drawbacks itself)

Maven is doing this to great success. The namespace issue has been solved successfully, just copy what they do. It took years until they arrived at the current system, and it works well. What drawbacks are you thinking of?

dthul 1318 days ago [-]
My initial concern was that a DNS approach would force anybody who wanted to publish to crates.io to own a domain. In a parallel thread someone mentioned that Maven allows to acquire a "com.github.username" namespace in case you don't have (or don't want to use) your own domain. That might work for crates.io as well, since it already requires you to have a Github account anyway.
YorickPeterse 1318 days ago [-]
Honestly these questions are not that hard to answer. Just look at the likes of GitHub, GitLab, or really any source code hosting platform that supports the creation of groups.

> How do we decide which person/entity gets a namespace?

You get a personal one, named after your user account. In addition, you can create up to N namespaces. After that, you either have to request more or pay a small fee. This prevents namespace squatting, while still giving you the option to register a few for specific projects.

> What if there's a dispute?

First come first serve seems pretty reasonable. Just because your company is named X doesn't mean you have a perpetual and exclusive right to use that name wherever you want.

> What do we do about all the currently un-namespaced crates?

You would have to leave them, and perhaps disallow un-namespaced crates after a certain point of time. Maybe take a look at how NPM handled thsi.

> How would Rust (the language) understand namespaces?

A crate `foo/bar`, with `foo` being the namespace, should just translate to something like `use foo::bar`.

Drdrdrq 1317 days ago [-]
You mean like this?

> Just because your company is named Microsoft doesn't mean you have a perpetual and exclusive right to use that name wherever you want.

Hmmm. :)

YorickPeterse 1316 days ago [-]
There's a thing called trademarks, and the case is indeed different for those. But even in that case, one would have to file some sort of dispute; you don't necessarily get to use the name everywhere forever, no questions asked.
majewsky 1318 days ago [-]
> How do we decide which person/entity gets a namespace? What about namespace squatting? What if there's a dispute?

My proposal is to give everyone a namespace corresponding to their crates.io username, so if I want to publish a JSON library, it would be "user/majewsky/json".

Everything not prefixed with "user/" is a shared namespace which is handled by a team of curators. If someone wants to publish into the shared namespace, they need to apply for a package name. So if I think my JSON library should be the standard, I could apply for having it aliased to "json" or "encoding/json" or whatever. The curators would be allowed to impose an overall structure in the shared namespace to aid those who browse it.

Crucially, the curators should have the right to revoke an existing lease. If someone publishes their JSON library into the shared namespace as "json" and then later down the line abandons the project, other community members should be allowed to apply to take over that name. Of course, existing releases would stay untouched, but if I stopped maintaining my JSON library at 1.3.7, someone else should be allowed to take that over and publish 1.3.8 or later.

I would also impose the limitation that 0.x versions are not allowed in the shared namespace. If you want a nice package name, you should be ready to commit to at least a somewhat stable interface.

> How would Rust (the language) understand namespaces?

It's not hard to imagine a Rust that works with namespaced crates. What is hard is finding a solution that's backward- and forward-compatible.

berkes 1318 days ago [-]
> Everything not prefixed with "user/" is a shared namespace which is handled by a team of curators.

The docker "hack" of using `_` is quite a smart hack here, and works well; for me at least. E.g. https://hub.docker.com/_/postgres its clear this is some "official" build.

majewsky 1317 days ago [-]
But when you pull it, it's just `docker pull postgres:12`, not `docker pull _/postgres:12`.
boris 1318 days ago [-]
Not bad, we might steal some of these ideas for build2 if you don't mind.

> other community members should be allowed to apply to take over that name. Of course, existing releases would stay untouched, but if I stopped maintaining my JSON library at 1.3.7, someone else should be allowed to take that over and publish 1.3.8 or later.

This part is iffy: if you release a patch, it implies that it has backwards-compatible interface. So this will realistically only work for taking over the maintenance of the old package, not for replacing it with something entirely new. I think a version epoch might work for the latter.

majewsky 1317 days ago [-]
That's something the curators would have to look out for. If you're building a green-field solution, I'd also suggest to outright reject library versions that don't follow semantic versioning. A patch version bump that changes the API? Not allowed, go bump your minor version and come back. A minor version that breaks existing users? Not allowed either. It's a really easy check. I'm honestly baffled no one's doing it yet.

(Side-note: I'm only talking about libraries here, not applications.)

ChrisSD 1318 days ago [-]
Great replies so far. I'd add that if people want namespacing to actually happen they need to collaborate on an RFC (https://github.com/rust-lang/rfcs/blob/master/0000-template....). Ideally someone would post a pre-RFC to internals.rust-lang.org so it can be improved before formal submission.

Any such RFC needs to take in to account previous discussions (and appreciate that the crates.io team is small). E.g.:

https://internals.rust-lang.org/t/crates-io-package-policies...

https://internals.rust-lang.org/t/namespacing-on-crates-io/8...

https://internals.rust-lang.org/t/pre-rfc-packages-as-namesp...

jmillikin 1318 days ago [-]
I've never written a Rust RFC before, but I know how to start forum topics. Let's go!

https://internals.rust-lang.org/t/pre-rfc-user-namespaces-on...

lmm 1318 days ago [-]
> How do we decide which person/entity gets a namespace?

Do what maven does, and follow a reversed domain name convention. Or just first-come-first-served.

> What about namespace squatting?

It's much less of a problem, because having to use a different namespace is much less intrusive than having to use a different package name.

> What if there's a dispute?

What kind of dispute are you imagining? It's much harder for someone else's package name to cause a problem for you if packages are namespaced, since there's no way for someone else's package to end up in your namespace, whereas if you have to just use a convention like author-packagename then disputes are much more likely.

> What do we do about all the currently un-namespaced crates?

Either put them in a (deprecated) unnamed/root namespace, or turn each one into its own namespace (i.e. libfoo becomes libfoo:libfoo).

> How would Rust (the language) understand namespaces?

It doesn't need to, as far as rust is concerned a package is a package - they're handled at the cargo level.

> How would cargo work with them?

Dependencies would be (namespace, name, version) rather than just (name, version). And you just... do the sensible thing? This isn't a new idea, other languages have done this.

twic 1318 days ago [-]
As a baseline, just do it exactly like in Java/Maven, where it has been absolutely fine for almost twenty years.
dthul 1318 days ago [-]
I don't know Maven much so please correct me if I'm wrong, but I believe there is a substantial difference:

In Maven anybody could publish a package that starts with "com.google". The namespacing proposals I have seen for crates.io assume that namespaces are exclusive to a single entitity though. So once someone that is not Google reserves the "google" namespace, Google itself would not be able to publish crates under that namespace anymore.

aorth 1318 days ago [-]
I just published my first Java package on Maven Central via Sonatype OSSRH this week and when you sign up you have to verify your "groupId" (aka your namespace) using either DNS TXT records or with com.github.username where they ask you to create a repository with a given name to prove you control it.

So you could easily publish a package using the com.google namespace on your blog or whatever, but not on Maven Central.

twic 1318 days ago [-]
Meanwhile, JCenter doesn't do any checking like that.

Which definitely leads to an oddity in Java land - most libraries are in Maven Central, which requires some effort to submit to, but which is reasonably carefully policed, and some are in JCenter, which is easy to submit to, but is not policed. And then some libraries are in registries run by their maintainers.

Modern build tools make it easy to add registries. In practice, JCenter doesn't seem to have problems from the lack of policing. So this is very much an oddity rather than a problem.

Quekid5 1318 days ago [-]
> In Maven anybody could publish a package that starts with "com.google".

I don't think that's the case. If you want to get on Maven Central (at least via SonaType OSS) you have to prove that you own an email address on the relevant domain.

If it's your own private package repository, then sure, but then that's not an issue for anybody else.

vaylian 1318 days ago [-]
I think it is unreasonable for people to need to own a domain (or at least pretend to own it) just to publish a package. Not everyone is part of some company or runs a website.
dthul 1318 days ago [-]
In a parallel thread someone mentioned that Maven allows you to obtain a "com.github.username" namespace based on your Github account, which is already a requirement to publish on crates.io anyway.
twic 1318 days ago [-]
Having namespaces seems like an absolute no-brainer to me, and i find the visceral opposition some people have to it entirely baffling.
renewiltord 1318 days ago [-]
Why not `anonova-logger` instead of `logger`. You can namespace by naming if you want.
j88439h84 1318 days ago [-]
One thing is that anonova doesn't control the anonova namespace.
rat87 1317 days ago [-]
sure but who is going to steal it?

it seems easier to do that for the common case then deal with the complexity of namespaces

renewiltord 1317 days ago [-]
Fair enough.
rat87 1315 days ago [-]
what are the practical benefits of namespaces that you don't get with

username_logger, username_fuse, etc.

?

A lot of the supposed benefits seem like downsides. The ability to have

bob_ward/docker and lilly_smith/docker seems like a misfeature

I guess you could argue it makes to avoid malicious packages w/ similar spelling but then they could just try the same thing with even less suspicion w/ similarly named namespaces

peacefulhat 1318 days ago [-]
What do you want to do with namespaces? I don't understand.
jgraham 1318 days ago [-]
What I personally want from namespaces on crates.io is basically the same as I want from org names on GitHub; the ability to manage permissions at the level of a organistation rather than each package requiring a unique setup, making it harder to audit and admin all the packages belonging to an org. It also seems like a win for consumers to know when they're using code from a specific vendor vs when they aren't. The consumer trust problem you can possibly solve with naming conventions — although it's hard to ensure that everyone has the same conventions unless it's enforced — but the admin problems you can't.
DougBTX 1318 days ago [-]
Yes, it would be great to have packages grouped by organisation. It would make it much easier to see in a package list how which organisations you're depending on, rather than just how many crates.
DougBTX 1318 days ago [-]
Imagine if every repository you pushed to GitHub had to have a globally unique name, rather than account/whatever-you-like.
qayxc 1318 days ago [-]
So account-whatever-you-like then?
Whitespace 1318 days ago [-]
That is not the same, because ownership of _account_ isn't enforced if it's just a string. Imagine someone else uploading qayxc-resume, for example.
vaylian 1318 days ago [-]
give everyone an equal chance to pick a good name
steveklabnik 1318 days ago [-]
Hey hey, this post is great! A few small comments:

> It's not obvious to me why they do this – it's a documentation generator, why does it care what version of the Rust compiler I'm using?

rustdoc, being a part of the Rust distribution, has the same stability guarantees that Rust does: once it gains a feature, it will never go away. We (well, not me I don't really work on rustdoc, to be clear) need the capacity to try out new features without committing to them, same as features in the language.

> PyPI launched in 2003, and CPAN has been running since 1995

Neither of these support namespacing though, right?

> Cargo's unit of distribution is the crate, which is a problem because Rust's compilation unit is also the crate.

Cargo's unit of distribution is a package, which is one or more crates. It is true that there can only be one library crate per package, however. This is one area where people don't use the correct words super often, honestly.

> Of course build times are slow if changing one line of a leaf file requires rebuilding dozens of modules.

This shouldn't change based on if you're using Cargo or not; if it's re-building dependencies every time you touch a file, that is a bug.

jmillikin 1318 days ago [-]

  > rustdoc, being a part of the Rust distribution,
  > has the same stability guarantees that Rust does:
  > once it gains a feature, it will never go away. We
  > (well, not me I don't really work on rustdoc, to be
  > clear) need the capacity to try out new features
  > without committing to them, same as features in the
  > language.
I guess I expect rustdoc and rustc to be much less tightly coupled, so that I could use (for example) stable rustc and nightly rustdoc on the same code.

In the current model, I can't use nightly rustdoc features without also using nightly rustc, because the annotations are processed by both systems.

You could imagine an alternate model where rustc stabilizes `#[doc(...)]` and leaves everything in there up to rustdoc's interpretation, and nightly rustdoc might enable new parameters to the #[doc] annotation.

  > Neither of these support namespacing though, right?
That's correct. I meant that mostly in terms of "package registries are not a new and untested idea". It's like using strings for file paths: not obviously a bad idea, turns out to be unworkable for obscure reasons, and as a new language Rust got to avoid that particular mistake. It feels like crates.io didn't (/ doesn't) have a similar process of avoiding known mistakes.

  > This shouldn't change based on if you're using Cargo
  > or not; if it's re-building dependencies every time
  > you touch a file, that is a bug.
Given a crate with a hundred files, each one fairly independent of the other (i.e. a broad shallow build graph), changing one requires (if I understand rustc correctly) recompiling them all. Otherwise the `crate::` references can't be type-checked.
steveklabnik 1318 days ago [-]
> I guess I expect rustdoc and rustc to be much less tightly coupled

Yeah, and that could work in theory. The thing is, rustdoc uses the compiler as a library, so they actually are pretty tightly coupled. This causes a lot of pain but also has a bunch of upsides. I really want to see a rustdoc that is not, but it's gonna take a long time.

> That's correct.

Cool, I thought so, I just wasn't 100% sure! I think it's interesting how different people take away different things here, to me, this demonstrates that you don't have to have namespaces; many of the largest ecosystems do not and have not had them. We did learn a lesson there, just didn't come to the same conclusion that you did. This one is more controversial within the community though, many people do agree with you.

> Given a crate with a hundred files

Yes, but that doesn't change with rustc vs cargo though; it's still a single rustc invocation to compile all those files. (And, it doesn't quite do so, there is some degree of incremental compilation going on, but it's not as fine-grained as it can be. Working on it!)

jmillikin 1318 days ago [-]

  > Yes, but that doesn't change with rustc vs cargo
  > though; it's still a single rustc invocation to
  > compile all those files.
When using Bazel instead of Cargo the developer can split the build graph into much smaller crates (down to one per module if desired), and still treat the entire assembly as one package.

I should emphasize that this is a limitation of Cargo, not rustc. rustc does just fine with big libraries, it's only Cargo that makes it difficult to write hundred-crate packages.

steveklabnik 1318 days ago [-]
Ah, so you're not saying that you take the same project and port it from Cargo to Bazel and it somehow does less work, you're saying that it's easier to make projects with a larger number of smaller crates with Bazel than Cargo? That would be the bit I'm missing, Bazel and Cargo should invoke rustc the same amount of times per crate: once. Cargo doesn't change the compilation model of the language.

(Sorry, I feel a bit dense here, but I am very curious to understand exactly. I haven't used Bazel a ton yet, but am very interested in it.)

jmillikin 1318 days ago [-]
Yep, exactly. If I were building rust-fuse with Bazel I would probably split it into about 4 crates (fuse_kernel, fuse_io, protocol, server). This is what I tried to do in Cargo and gave up because of the crates.io packaging requirement.
steveklabnik 1318 days ago [-]
Gotcha. You can use path as a dependency if you also use the version as a dependency, and it’ll use the path locally but the version when you publish. Maybe that needs to be better documented and would have just fixed your issue. (This is described at https://doc.rust-lang.org/stable/cargo/reference/specifying-... )
jmillikin 1318 days ago [-]
That requires publishing the internal crates as separate entries in crates.io, if I understand correctly, which I don't want to do (see the final section on crates.io's packaging model).

Ideally I could have a single crates.io package, with a single tarball, containing multiple crates. The internal crates would not be exposed to users, wouldn't have versions, wouldn't be on docs.rs, and so on.

steveklabnik 1318 days ago [-]
Yeah, that is true, it does.

I do think that's an interesting idea. I'll have to mull on it. Thanks again. I've been thinking of a few things here, very interesting :)

escardin 1318 days ago [-]
> Cool, I thought so, I just wasn't 100% sure! I think it's interesting how different people take away different things here, to me, this demonstrates that you don't have to have namespaces; many of the largest ecosystems do not and have not had them. We did learn a lesson there, just didn't come to the same conclusion that you did. This one is more controversial within the community though, many people do agree with you.

Maven is from 2004 and has namespaces. Maven has it's problems, but the Java package management ecosystem gets many things right that later systems have not.

jmillikin 1318 days ago [-]
You are correct that Maven is one of the first package registries to use a principled approach toward namespacing.

I didn't mention it because -- and this may be rude to Maven -- I consider Maven's coordinates syntax to be closer to "primitive Go" than it's own distinct thing. If software hosted on `example.com/foo/bar` has the package name `com.example.foo/bar` then it's introducing ambiguity without much benefit.

lmm 1318 days ago [-]
It's not just the hosting, it's decoupled from where the project is hosted. Some packages do just use an arbitrary groupId. The reversed-domain-name convention makes sure you'll never get two different groups claiming the same name, and aligns with the convention for how code is namespaced in Java, but it is ultimately only a convention.
M2Ys4U 1318 days ago [-]
>The reversed-domain-name convention makes sure you'll never get two different groups claiming the same name

Surely that's only true at any one instant? Domain names change hands all the time.

For example: All non-EU citizens in the UK that have .eu domain will have them forcibly de-registered at the end of the year. What happens to a eu.example.foo package then?

lmm 1316 days ago [-]
True, but it's hard to imagine a developer accidentally buying a domain that had previously been used by an unrelated developer and wanting to release packages under the same namespace.
steveklabnik 1318 days ago [-]
Sure, but that’s not really what I was talking about. Citing maven would have made the point stronger for exactly that reason!

(And the lesson isn’t that either, the claim was never “this feature is terrible and ruins the language”, there very much are successful examples. The claim is that the lack of the feature does not mean failure.)

migueloller 1318 days ago [-]
Would you be willing to expand on why using strings for file paths turns out to be unworkable? Very curious what the obscure reasons are!
jmillikin 1318 days ago [-]
Short version: file paths are an OS-specific construct, and not all OSes have paths that can be round-tripped through Unicode.

The first bad option is to say "paths are bytes", which is true on traditional POSIX platforms. Then you run your code on macOS and discover it's processing your bytes as UTF-8 and applying Unicode normalization. After fixing that you try porting to Windows and get to learn about `wchar_t`.

The other bad option is to say "paths are (Unicode) strings", which works fine on Windows and macOS. It works 90% of the time on POSIX, but you'll eventually find users with non-UTF8 file paths and then you're in trouble.

My first hand experience with this going wrong is GHC, which started off with raw bytes, then moved to strings using a bad conversion function, then they tried to work around the issue by placing non-UTF8 bytes into a Unicode reserved area.

Java also has problems because it represents paths as strings and tries to use the libc locale for decoding. https://github.com/bazelbuild/bazel/pull/10111 is an example of how this breaks software in ways that are difficult to work around.

migueloller 1318 days ago [-]
Thanks for the response!
jmgao 1318 days ago [-]
If your String type must be valid Unicode (which is true for pretty much every language that isn't C++), it cannot represent all paths. On most unixy filesystems, filenames are arbitrary byte sequences which aren't valid UTF-8, and on windows, NTFS stores filenames as UTF-16, but it allows unpaired surrogates.
throwaway894345 1318 days ago [-]
What languages require string types to be valid Unicode? Go for example let’s you put anything in a string; it’s only Unicode if you put Unicode into the string including via creating string literals.
cptroot 1318 days ago [-]
I think python also takes the approach where strings must be valid unicode. Both Rust and Python use their String types to represent valid unicode, and something else ([] and byte strings, respectively) to represent other encodings and invalid unicode.
rkangel 1318 days ago [-]
Requiring strings to be valid unicode simplifies the internal workings of (and use of) a language greatly. Dealing with unknown input becomes a single operation at the boundary after which you can safely assume everything is validly printable or processable as text.
throwaway894345 1317 days ago [-]
I think there is some convenience in being able to use the type system to denote input which has already been validated; however, I can't see how a language runtime benefits from this property with respect to unicode. Notable, printing and processing text aren't operations a runtime typically deals with. Libraries including the standard library might benefit from this property, but even then I wouldn't say the benefit is "great". It's a nice property, but I don't think it makes or breaks anything.
rkangel 1317 days ago [-]
It's worth pointing out that Python 3 thought it important enough to make a backwards incompatible change to separate 'bytes' from 'strings' to effectively get the same result.
throwaway894345 1316 days ago [-]
Probably, but I think that’s more to do with the typing convenience (which is even more puzzling in Python’s case since it isn’t statically typed).
ChrisSD 1318 days ago [-]
Rust, Java, Swift...
erik_seaberg 1318 days ago [-]
Is that technically UCS-2 rather than UTF-16?
ChrisSD 1318 days ago [-]
Technically not since ~2000. Windows uses UTF-16 throughout the OS. That is, Windows strings will be encoded and decoded as UTF-16 not UCS-2.

However the tricky bit is that the kernel doesn't enforce this so it's possible for programmers to intentionally make broken UTF-16 strings. A broken UTF-16 string shouldn't be considered UCS-2 just because it happens to be a valid UCS-2 string (otherwise all bit patterns could be called "UCS-2" so long as they are an even number of bytes in length).

steveklabnik 1318 days ago [-]
(To add on to the sibling comment's great answer, here's Rust's docs on this https://doc.rust-lang.org/stable/std/path/index.html and https://doc.rust-lang.org/stable/std/ffi/struct.OsString.htm... )
rstuart4133 1317 days ago [-]
More interesting is what you do use for file paths, if you accept that both strings and bytes don't work. The answer will be I guess a dedicated FilePath type that knows paths are lists of blobs, and the blobs can further be divided up into prefixes and an extensions.

But that doesn't really solve the problem. You still have to convert file paths to strings to print them, and strings to file paths to accept them as from the terminal and databases. For that to work the round trip had better be safe on any given platform otherwise the user can't copy and paste.

Not addressing this problem has been python3's undoing when it is used as a shell scripting replacement. Actually, it's an undoing any time you want to treat "text" as interesting ascii swimming in an unknown encoding, particularly when you want to modify that ascii. HTML with an unknown encoding is a prime example.

eddyb 1318 days ago [-]
You can use #[cfg(doc)] and #[cfg_attr(doc, ...)], but it looks like that still requires #![feature(doc_cfg)], so I guess it wouldn't be compatible with stable rustc anyway, until it's stabilized itself.
thayne 1318 days ago [-]
> > PyPI launched in 2003, and CPAN has been running since 1995

> Neither of these support namespacing though, right?

But both have policies that prohibit name squatting, whereas crates.io has a policy which explicitly allows it.

zamalek 1318 days ago [-]
> I eventually gave up on trying to make the formatted rust-fuse code look pretty, and settled for "consistent".

Even though it's a bit ugly, this is a big win.

As for why it does this, from my experience, rust-fmt will try to keep lines under a column limit but not greedily. e.g. if a params list would extend past the limit, then all params get a newline. It seems to try to balance horizontal estate and vertical estate and I've become used to that (even though it is inconsistent at times).

Any formatting rule is going to fall over eventually. Rust-fmt seems to make sane choices the majority of the time.

qchris 1318 days ago [-]
Just in case anyone's not familiar with it, I figured it's worth pointing that rustfmt is also really customizable, using a `rustfmt.toml` file in the source directory. It might take a little time to get right, but it's not as if you're stuck with the default options, and a .toml file is pretty easy to play around with.

[1] https://rust-lang.github.io/rustfmt/?version=master&search=

ssokolow 1318 days ago [-]
Unfortunately, `rustfmt.toml` isn't expressive enough, even on nightly.

I've had to make use of `rustfmt::skip` in various places to keep it from doing things like mangling the groupings and explanatory comments in `const` arrays or making code gratuitously tall and thin.

...and that sometimes means either `git gui` cherry-picking and only running rustfmt infrequently or applying `rustfmt::skip` too broadly because of errors like "error[E0658]: attributes on expressions are experimental"

(I'm in the process of migrating from cherry-picking to over-broad `rustfmt::skip` so I can use format-on-save.)

bananaface 1318 days ago [-]
What's more important IMO is the erasure of time & mental overhead that are normally spent formatting. Formatting is (broadly) a giant waste of time. I honestly do not care if the result is ugly.

And that ignores the synergistic benefits of erasing all style-based co-ordination problems & arguments & bikeshedding & whatever else from the entire codebase. IMO it's a no-brainer.

zamalek 1318 days ago [-]
> erasing all style-based co-ordination problems & arguments & bikeshedding & whatever else from the entire codebase.

Exactly this. I sat across from the poor soul who was assigned to creating the coding standards for our C# stuff. It tooks months. Nobody was happy, everyone had their own way of doing things: var vs. no-var vs. obvious-type-var, CONST_VALUE vs ConstValue. The work has been completed (the person in question quit soon after), people are still unhappy, there are still (and will always be) open questions. People nit coding standards in code reviews instead of looking for real issues. What a shitshow. If you remove autonomy concerning coding standards from the get-go, people never form these opinions.

If code is not optimally pretty, that sucks. Establishing coding standards is an bottomless pit of despair. Almost any opinionated formatter is worlds better than the worthless sisyphian task of establishing your own coding standards.

jdashg 1318 days ago [-]
It's a local maxima, but it prohibits maximally readable code.

I just don't think it's a big win, but I've found it's a hard rhetorical battle to fight. Everyone's more cynically fearful of ugly code rather than having that extra leeway to write extremely readable code. I've definitely found this can throw the baby out with the bath water.

cgrealy 1318 days ago [-]
Consistency > prettiness
berkut 1318 days ago [-]
Is it just prettiness though?

When I worked in the defence industry (~15 years ago now), a lot of the coding standards for C/C++ (which was starting to be used more and more over ADA at the time) were very strict on the matching alignment of things like open / closing braces, so things like hanging braces were not allowed, both opening and closing braces had to be on their own lines.

The argument behind this was it made the code clearer, and more easy to match clauses / scoping - in a way arguing it was "safer" in terms of interpretation of the code.

hurrrrrrrr 1318 days ago [-]
Maybe, maybe not. Is the potential benefit even worth fighting over? Style is just full of so many subjective details that every discussion ends in. And everybody has their favorite it's un-fucking-readable. My oppinion converged on "Fight it out and tell me what options in $formatter I need to set. Don't even tell me reasonings, just the options. leaves room". I'd rather drink coffee than have the next horizontal real estate vs. parameter alignment debate.

The argument to match clauses/scoping for example is weird in a world where a formatter automatically applies indentation. It might make sense when you have to manually check them on print-outs without an Editor. I'd argue GNU style fulfills that role even better or Horstmann if you care about vertical real estate (or be daring and combine the two). And now everyone hates me.

berkes 1318 days ago [-]
I lean to the other side.

In a way that I tell the requester "you better have some really, really good reason for wasting my time on this".

Hell, I've even had a new hire prepare an entire presentation to convince us to change the line-length to something different than "The Language Standard".

"We follow the language standard" and if you don't like it, convince upstream (This was Rubocop/Ruby) is another one I've used in the past.

Naturally both people just gave up. There really is a better way to spend time than on tuning and tweaking a linter. Nearly all linters have some way to document and define very local exceptions for that case when some external__dependency_IsMxing_camel_case or whatever.

shmerl 1318 days ago [-]
That depends on how ugly that consistency is.
rstuart4133 1317 days ago [-]
> Even though it's a bit ugly, this is a big win.

As someone observed above it's the only win you are likely to get, as ugly often boils down to "something I have seen before".

There a few idioms that are actively helpful or harmful. For example, python making whitespace significant neatly meshes with human visual system. We are really good a picking up changes in indentation, not so good at lining up curly brackets. But best of luck trying to get 1/2 the population to accept that, even though it's objectively accurate.

On the other side, allowing too many levels of operator precedence seems to be harmful. I loved the conciseness when I was young. It was only later I noticed people struggled with some of my code because of it. Pascal (I think?) solved the problem by making combining some operators without parenthesis a syntax error. But since I only used Pascal when I was young, I hated it whenever I did use it.

So yeah, consistency is the only easy win. And as you say it's a big one: consistently formatted code is much easier to read than a miss-mash.

ncmncm 1318 days ago [-]
When I worked for Ian Taylor (one of the creators of Go) it was a firing offense to waste time lining up columns or parentheses. Petty arranging is a waste of valuable time, time stolen from your employer if you have one. Just a one-unit indent provides all the information you need to convey to the reader.

Rust's formatter not making up artificial alignment columns is the best thing about it.

erickt 1318 days ago [-]
> Closed-world ("sealed") traits. Rust's rules against private types in the public API are good civilization but they make it difficult to define pseudo-private traits like Mount that I want users to name but not implement or call into.

Rust actually supports sealed traits by using public traits in private modules. See this for how to use it, and how it works:

https://rust-lang.github.io/api-guidelines/future-proofing.h...

jmillikin 1318 days ago [-]
I'm aware of that workaround and do use it in `rust-fuse`[0], but I'm not satisfied for two reasons:

* It's not understood by rustdoc, so I have to manually document that the trait is sealed.

* It technically violates Rust's rules against private symbols in the public API, so a future version of rustc might deprecate or remove that functionality.

[0] https://github.com/jmillikin/rust-fuse/blob/a6ad16d1127d36f8...

eddyb 1318 days ago [-]
> * It technically violates Rust's rules against private symbols in the public API, so a future version of rustc might deprecate or remove that functionality.

It's public though, just not externally reachable, the private module doesn't make the trait private.

For example, if you wanted to, you could reexport the trait in the parent module (and I guess the drawback with the "sealed" pattern is accidentally doing that when it would be unsound do because of how you relied on it being "sealed", in unsafe code).

I don't think I've heard anything about plans to restrict anything based on reachability, and it would be massively backwards-incompatible so I doubt it would even be considered for an edition.

oconnor663 1318 days ago [-]
> a future version of rustc might deprecate or remove that functionality

Are you sure about this? My understanding is that stable Rust limits itself to compatibility breaks that are both rare and trivially worked around. (Like adding a new inherent method to a standard type that happens to have the same name as your trait method.) Even in a new edition, I think there's a very heavy leaning towards changes that can be automated by `cargo fix`. Removing this idiom seems like it would be much too big of a change. (The obvious automatic fix -- just inserting `pub` as needed -- would presumably make a bunch of currently safe APIs unsound.)

swsieber 1318 days ago [-]
I could see it being deprecated with an edition transition and a blessed solution.
Fiahil 1318 days ago [-]
After working on rust for almost 2 years, I finally reached a point where I can see (and wait for) a few improvements.

First is completing the `impl Trait` saga. I see a couple of areas where I'm obliged to box a trait to get the compiler to accept the code. Not the end of the world.

Second is allowing conversions of AsyncRead to Stream. currently you have to do a weird dance to get chunks of tokio::File as Stream of Bytes. I think something is missing. Something as straightforward should be easy even if it's not part of std.

Last, is adding support for Generators and their transformation into Stream. Then, getting a Stream of Val would be as simple as `yield val` in a function. I'm sure their current API on nightly will change before it's merged to stable rust, and I even hope they will get rid of the "return type" in gens (it complicates things a little bit).

After that last point, I can see Rust replacing python for most of the data prep work we have in data science/AI.

adamnemecek 1318 days ago [-]
Unix-stuff as a part of the standard library is a terrible idea. Making your own crate is simple enough. Same with OS-dependent functionality.

Re: crates namespaces, that is a crates decision, not necessarily Rust'. You can always publish your crate on github and include it with "package = { git = ... }" and you'll get the same thing as in go.

steveklabnik 1318 days ago [-]
> Re: crates namespaces, that is a crates decision, not necessarily Rust'.

Sorta kinda. Crates are a Rust language concept, and they do not support namespacing. You'd have to hack around that to get it to work.

jmgao 1318 days ago [-]
Why is that not true for the rest of the standard library? You don't really need a HashMap in your standard library, or mutexes, just a memory allocator and atomics.
steveklabnik 1318 days ago [-]
Historically, the criteria for inclusion in the standard library is, does it fall under one of these three categories:

* Used in the vast majority of Rust programs.

* Reasonably common things that require a lot of unsafe to implement.

* Traits for interoperation purposes.

HashMap and mutexes fall under #2. The idea is that they'll receive significantly more scrutiny, and this is a good thing for the ecosystem.

(These are guidelines, not hard and fast rules, so not literally everything fits here, but that's the framework that was used to think about what should be included or not, generally.)

ChrisSD 1318 days ago [-]
To be honest I think #2 was applied a bit too broadly. Sure rustc gets scrutiny but the std isn't the easiest library to contribute to. Not only is it large (by rust crate standards) but it's also tied to the compiler which adds another barrier to contributions.

Mind you, increasingly parts of the std are more like wrappers around third party crates e.g. hashbrown and parking_lot.

steveklabnik 1318 days ago [-]
Yes, I think this calculus changes over time. Back in the day, I think this reason was more important than it is now.
lmm 1318 days ago [-]
If the "platform" concept works out then those things probably should move out of the standard library. Look at how many people had to upgrade language versions to deal with DoS attacks on their HashMap implementations, when it should've been just a case of upgrading their HashMap library.
panzerklein 1318 days ago [-]
Suggestion for page styling: replace "overflow: scroll" with "overflow: auto" to get rid of unnecessary scrollbars in code blocks. Unless you like them the way they are, of course.
jmillikin 1318 days ago [-]
CSS and I have a strained relationship.

https://mstdn.io/@jmillikin/103158451151123313

I'll put this on the list of things to fix next time I go digging at the stylesheet.

Ericson2314 1318 days ago [-]
Yes thank you for not fauning over Cargo like many other reviews.

The simple fact is Cargo did not learn from prior art to the extent Rust did.

Things have gotten better, but Rust is still better designed. Hopefully Cargo can someday catch up.

kibwen 1318 days ago [-]
If this is referring to namespacing, that's a crates.io concern, not a Cargo concern. Cargo is fully capable of using other registries, and there's nothing stopping those registries from using namespaces to organize and disambiguate crates.
Ericson2314 1318 days ago [-]
I'm not referring to namespacing in particular, which indeed doesn't concern me so much for those reasons.
avasthe 1318 days ago [-]
I would be curious to hear what are your criticisms of cargo, too. Recently I am trying to study about dependency management in different languages, and cargo, along with bundler seems to be praised quite a bit. I can't correlate it with quality because both rust and ruby camps are quite vocal.
jganetsk 1317 days ago [-]
> Closed-world ("sealed") traits. Rust's rules against private types in the public API are good civilization but they make it difficult to define pseudo-private traits like Mount that I want users to name but not implement or call into.

What about a public type with no public fields nor public methods? Doesn't that accomplish exactly what the author is looking for?

kanobo 1318 days ago [-]
Once a Rustacean always a Rustacean - a first impression will inevitably lead you down a never ending road but luckily there is a great community to support you.
rsa25519 1318 days ago [-]
Definitely. I must admit, I came to Rust with a lot of baggage from other languages. I've learned a lot from reading about why Rust doesn't let me do things, often causing me to no longer do those things in other languages.
ncmncm 1318 days ago [-]
I gave Rust a good solid tryout.

It turned out to be insufficiently expressive to put into libraries the semantics I want to encapsulate. I went back to C++, and have been very happy. (It's also nice that lots of people want to pay to have it done.) As with Rust, I can write 2000 lines and, once it compiles, it works.

The hardest thing about going back to C++ from Rust was getting used to putting semicolons where Rust doesn't require them. Years later it still trips me.

supergirl 1318 days ago [-]
isn't C++ more like "once it compiles, it works, but later you discover 10 places where it segfaults"?
jdashg 1318 days ago [-]
This really depends on your development style and experience, but not in general, no.
brutt 1318 days ago [-]
Yep. It's why Mozilla invented Rust in first place.
ufmace 1318 days ago [-]
Kinda yeah, but more worryingly, 10 years later you discover it had an exploitable buffer overflow vulnerability the whole time. Now you have no idea who else has known about it, how long they've known, what systems they've compromised in what way using it, etc.
ncmncm 1318 days ago [-]
That is how the propaganda goes. But in modern C++ style, memory errors just don't have many opportunities to happen. I.e., with the more powerful libraries C++14 and up enables, there is little temptation to drop to a risky level. And, anywhere you choose to, you can give it your full attention.

So, overwhelmingly the bugs you do get are specification bugs: the code does what was asked, but the ask was wrong. The only way to avoid those is to pay attention. Anything that steals attention generates them, in C++ as in Rust.

Old, pre-C++11 codebases (and codebases still written that way, or in C-with-classes style) suffer more. Mozilla and Google have a lot of old code.

ncmncm 1317 days ago [-]
You can down-vote all you like, but it remains true all the same.
twic 1318 days ago [-]
What couldn't you express satisfactorily?
ncmncm 1318 days ago [-]
Almost every feature of C++ is there to aid making powerful libraries. It has dozens that Rust lacks, more added with each Standard, and they work in synergy.

The primordial enabler in '98 was template partial specialization, that made the STL possible: same name with different types uses a different implementation.

boris 1318 days ago [-]
> I've found Bazel and rules_rust provide a good alternative to Cargo, since Bazel can twist your build into any DAG you want, but most Rust users are unlikely to be excited about injecting 50MB of Java build system into the middle of their workflow.

If anyone is interested in another alternative to Cargo that doesn't involve Java, there is build2[1] and it's libbuild2-rust[2] module. It's a general-purpose build system so you can have mixed-language projects, etc.

[1] https://build2.org

[2] https://github.com/build2/libbuild2-rust

wereHamster 1318 days ago [-]
> [In Haskell] I spent a lot of time debugging dangling pointers and race conditions.

Uhm, ok, pointers in Haskell… must be really low-level programming, because ordinary Haskell doesn't deal with pointers.

jmillikin 1318 days ago [-]
For a self-contained example, see https://github.com/jmillikin/haskell-ncurses/blob/master/lib...

My Haskell binding to CPython is larger but of about the same shape.

1318 days ago [-]
wokwokwok 1318 days ago [-]
Seems a little unfair to cargo to give it a scathing review when your alternative ecosystem is C++ or Haskell.

The basic complaint boils down to "packages aren't namespaced" and "someone already took the 'fuse' package", which has been a long running controversy for exactly that name-squatting reason.

However, Cargo is great.

> Rust's default build system (Cargo) and package repository (crates.io) are the opposite. They combine the worst parts of Cabal/Hackage and NPM, resulting in a user experience that is somehow inferior to both.

No. They don't. That's your opinion, not a fact, and I completely disagree. Lots of people disagree. Your arbitrary assertion is unsubstantiated and I reject it. :) Perhaps you meant "resulting in a user experience that I found somehow inferior to both".

If you don't like it, and you prefer to use bazel, then by all means be welcome to do so... but I think a little bit of acknowledgement is in order that ... frankly, that behavior should be discouraged.

We want a unified good build system for rust, not a ridiculous mess of difference package managers and build systems like in some other language ecosystems. Sometimes, conformity is a better approach, and I would be deeply saddened to see rust go that way.

I'm very impressed with the efforts to bring wasm support to cargo, and the other initiatives.

Be nice. Lots of people work really hard on cargo. They're doing a great job.

nsm 1315 days ago [-]
> We want a unified good build system for rust, not a ridiculous mess of difference package managers and build systems like in some other language ecosystems. Sometimes, conformity is a better approach, and I would be deeply saddened to see rust go that way.

I would like to disagree on this. I would prefer to see the Rust ecosystem play better with other build systems, instead of requiring all Rust to use Cargo. This becomes important when you are using Rust as part of a larger, multi-language code base. At my day job, we have Rust, Python and Typescript, and we use Bazel for much of the build, getting a bunch of advantages that Bazel brings to the table - remote caching, being able to query the dependency graph, selective testing and so on. These latter are not available in cargo, and would be significant work to re-implement infrastructure based on querying cargo instead of querying bazel.

I think there are 3 different things that Cargo tries to do, which would be better of with strong (and well documented) boundaries between them, so that users could mix and match each of these.

1. Compiling a crate - This is usually one rustc call. I'd venture saying that build.rs files are another layer, but I haven't thought about it enough. It is pretty common in Bazel-land to have build.rs wrapped in a `rust_binary` that is a dependency for the crate itself (usually `rust_library`). This is the easiest to plug into other build systems. 2. Compiling a set of crates/packages - Assuming a system where all the crates are on-disk, Cargo does the job of invoking rustc correctly with the dependencies passed and the right set of features selected. For Bazel, this is what rules_rust implements. The thing is, rules_rust has to figure this out by inspection of Cargo, instead of being able to rely on editions or compiler versions. (FYI, I've never used rules_rust. We have our own internal rules for Rust and we had to figure out things by inspection. Particularly Cargo specific environment variables that are not a part of the Rust language/stdlib, but are assumed to exist by libraries). 3. Package management - i.e. how to get dependencies from the network/someplace else onto disk. I'd suspect this is one place most large orgs would prefer not to rely on Cargo, because it necessarily locks them into some kind of delivery mechanism that is specific to the ecosystem, instead of having a dumb file server. i.e. we would need one for npm/yarn, one for pypi and so on, where each of these frontends know how to go from the "language package name" to the file on disk. I much prefer Bazel here where external dependencies are specified just by HTTP URLs and a sha256 hash to verify contents.

I'm almost _not_ on board with each language building their own compiler driver and package manager, because they end up duplicating so much work - some kind of caching mechanism, some kind of toolchain mechanism, some kind of resolver mechanism and so on...

svnpenn 1318 days ago [-]
This guys website is weird.

I first noticed as scrolling doesnt work with the keyboard. Upon inspection of HTML hes using weird shadow dom stuff.

Why do people do stuff like this? Its a static site, modern HTML and CSS are huge and can handle nearly any situation.

rat9988 1318 days ago [-]
Scrolling works with keyboard. There is nothing weird about shadow dom, it's part of the standard.
ssokolow 1318 days ago [-]
That's like saying "There's nothing wrong with using setjmp/longjmp. It's part of the standard."

I firmly believe that you shouldn't need client-side JavaScript for anything fancier than things like progressively enhancing a form field into a clickable star-rating widget unless you're writing an actual "web app"... definitely not for a blog. I'm just glad the text of his articles remains readable under the influence of my default uMatrix settings, even if none of the site-navigation boilerplate is.

Heck, if I thought it could be done without failing Lyndon Johnson's "the harm it would cause if improperly administered" test, I'd ask for laws that penalize people for pushing that sort of computating to the client where it can't be cached for more than just that one machine. They could be justified as a way to cut down on CO2 emissions.

As-is, if I can ever find the time, I want to see how much performance gain and "model has desynced from visible rendering" resilience I can get in my Firefox by ripping out Tree Style Tab and replacing it with something that uses the sidebar's DOM as the authoritative data model, built using <details>/<summary> expander/collapser nesting. (I've already prototyped the HTML for that as a simple transformation of what Markdown or ReStructuredText renderers output for nested <ul> outlines.)

nybble41 1318 days ago [-]
This is one of the last sites that I would criticise for use of client-side JavaScript. It uses one small script to implement a few simple web components. The power required to run that script is negligible compared to what the browser itself requires merely to render static HTML. You probably produced more CO2 just breathing while writing that comment than can be cumulatively attributed to this script across all visitors to this site to date.

The shadow-DOM thing svnpenn commented on is a red herring. It doesn't interfere with keyboard scrolling, which works perfectly well. The shadow DOM is merely used to isolate CSS styling rules so that they apply to an instance of a component rather than sharing a single global namespace. The elements are still rendered as part of the parent document.

EamonnMR 1318 days ago [-]
I'm surprised they didn't mention the elephant in the room: the borrow checking, boxes, and other ways that the code forces you to do the work of making sure your code is bug free before it will compile.
ragnese 1318 days ago [-]
Probably because that's the entire point of Rust and has already been blogged to death. There's nothing new to say about the borrow checker or boxing heap-allocated objects.
breatheoften 1318 days ago [-]
An insufficient auto-formatter is very frustrating ...

I think there are very smart older programmers who don't appreciate this fact properly. They sort of have a belief that there does not exist a "sufficiently good" good code formatter for all users -- and so therefore code formatter should have tons of configuration options to satisfy a range of style choices.

I think that opinion belongs in the past (with the discussion of tabs vs spaces). We have witnessed the existence of sufficiently high quality opinionated code formatters (java, gofmt, prettier, ...) -- and these code formatters without style choices produce a better world.

The way to get there is to find and prefer the non controversial formatting choices -- that means style preferences are abstracted away and consensus building grows from examples of code that everyone agrees is wrong and wants to fix.

The rust formatting issue he highlights makes me really annoyed -- the format chosen by the auto formatter for that sample code is not the best for that situation -- and I'm pretty sure it would be non-controversial for folks to agree on that ... am i right?

I'm doing some swift in xcode after awhile using an ide that lets me have "reformat on save" and the experience of "reformat on save" is good enough that I think it probably should be adopted as a first class goal of language designers -- there should be a language level "reformat on save" story that language designers assume will be used ... Baking in reformat on save as an assumed feature at language design time could allow creation or recovery from "write only" syntaxes -- (nice to write but ambiguous to read) -- either added on purpose or by mistake. Would also allow for really powerful Language evolution cleanup opportunities and the opportunity to introduce semantic changes where old functionality is preserved with complete compatibility until the source file is interactively edited from within an editor (eg the semantic change produces a code diff) ...

da39a3ee 1318 days ago [-]
Whether reformat is called on save is up to your text editor and has nothing to do with the language.
breatheoften 1318 days ago [-]
Yes but there is no reason a language ecosystem can't assumes that this functionality is present, implemented in canonical form, and that it is a language use error not to enable.

If the language designers assume the capability exists and will be used -- they can specifically evolve the language based on this assumption. All thats needed is a super high quality, compiler-provided implementation of the functionality -- and to set the expectation -- "sorry you have to wire this functionality up -- otherwise your code is going to be more likely to break if you edit the source files over time while also upgrading your compiler over time."

I'm benoaning the fact that no languages I'm aware of have advertised such a position as part of their evolution plan ...

da39a3ee 1318 days ago [-]
I think that you should have a second think about whether what you're saying makes sense.

To "save" some code means that an application writes it to hard drive. But writing to a hard drive is entirely orthogonal to the operation of a compiler. For example, a compiler should be able to compile code that is never written to hard drive -- exists only in memory. The hard drive is just one possible source of code to be compiled.

I do agree with you though that autoformatting code on save is a fantastic experience. It works beautifully with Rust, and so now I do it (less beautifully) with Python/black. I just think that although it's a great developer experience, it's several steps removed from anything that anyone would want tied to the compiler.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 06:42:36 GMT+0000 (Coordinated Universal Time) with Vercel.