
First Impressions of Rust - jmillikin
https://john-millikin.com/first-impressions-of-rust
======
quietbritishjim
> 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
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
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
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
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
> deployment by RAID

I'd like to hear that story.

~~~
arethuza
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
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.

------
pcwalton
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

      > 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
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
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
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
> 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
Anyone doing OS development is still on nightly last I checked but aside from
that stable has the features most people need.

~~~
rnestler
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
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".

------
anonova
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.

~~~
ChrisSD
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?

~~~
majewsky
> 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
> 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](https://hub.docker.com/_/postgres) its
clear this is some "official" build.

~~~
majewsky
But when you pull it, it's just `docker pull postgres:12`, not `docker pull
_/postgres:12`.

------
steveklabnik
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

      > 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.

~~~
migueloller
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!

~~~
jmgao
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
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.

~~~
rkangel
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
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
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
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).

------
zamalek
> 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.

~~~
cgrealy
Consistency > prettiness

~~~
berkut
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
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
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.

------
erickt
> 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...](https://rust-lang.github.io/api-guidelines/future-
proofing.html)

~~~
jmillikin
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...](https://github.com/jmillikin/rust-
fuse/blob/a6ad16d1127d36f80e6d02f36e48da56920ca693/fuse/src/server.rs#L53-L57)

~~~
eddyb
> * 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.

------
Fiahil
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
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.

~~~
jmgao
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
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
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
Yes, I think this calculus changes over time. Back in the day, I think this
reason was more important than it is now.

------
panzerklein
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
CSS and I have a strained relationship.

[https://mstdn.io/@jmillikin/103158451151123313](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
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
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
I'm not referring to namespacing in particular, which indeed doesn't concern
me so much for those reasons.

------
jganetsk
> 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
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.

~~~
ncmncm
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
isn't C++ more like "once it compiles, it works, but later you discover 10
places where it segfaults"?

~~~
ncmncm
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
You can down-vote all you like, but it remains true all the same.

------
boris
> 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](https://build2.org)

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

------
wereHamster
> [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
For a self-contained example, see [https://github.com/jmillikin/haskell-
ncurses/blob/master/lib...](https://github.com/jmillikin/haskell-
ncurses/blob/master/lib/UI/NCurses.chs)

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

------
wokwokwok
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
> 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
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
Scrolling works with keyboard. There is nothing weird about shadow dom, it's
part of the standard.

~~~
ssokolow
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
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
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
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
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
Whether reformat is called on save is up to your text editor and has nothing
to do with the language.

~~~
breatheoften
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
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.

