
Rust is the future, C is the new Assembly: Josh Triplett (Intel) - amaccuish
https://hub.packtpub.com/rust-is-the-future-of-systems-programming-c-is-the-new-assembly-intel-principal-engineer-josh-triplett/
======
dang
[https://news.ycombinator.com/item?id=20790681](https://news.ycombinator.com/item?id=20790681)

------
jeffdavis
If you invent the next image format, compression scheme, encryption scheme,
etc., and you write a Go library for it, then it can be used by Go
programmers. If you write a C/C++ library, it can be used by any programmer
(perhaps with a wrapper) on billions of devices.

Now, we add Rust to the list. You can write that library in Rust and it can be
used by anyone, too. That's because there is no GC or other extraneous code,
and because you can make structures with specifically-defined layout in
memory.

Making a list of options go from two to three is a big deal. Especially when,
a lot of the time, C++ ends up looking like C when you need to interface it
with something else. So Rust is kind of like going from one to two optons.

I'm ignoring other good languages, I know, but those are often just not chosen
for a variety of reasons. Rust seems to be breaking out of that trap because
of a good community, a few nice features, the fact that it's new, and a bit of
luck.

~~~
colejohnson66
> Now, we add Rust to the list. You can write that library in Rust and it can
> be used by anyone, too. That's because there is no GC or other extraneous
> code, and because you can make structures with specifically-defined layout
> in memory.

Genuine question: Can you link a Rust binary with a C/C++ binary?

~~~
baq
notably firefox has a few modules implemented in rust.

------
jefftime
I use C a lot on my personal projects, and I have enjoyed learning Rust and
playing with it to potentially replace my use of C. For the most part Rust has
everything I want, but interfacing with C libs and headers can be so
unergonomic. I wish there was a good alternative to bindgen that didn't shoot
your build times up. Offline binding generation works, but then you have to
manually deal with versioning. I don't really know what the solution is, but
it's currently one of the pain points I have with Rust

~~~
JoshTriplett
That's one of the items on the list to get better C parity. Binding to C
libraries _should_ work as easily as C's #include.

~~~
Tuna-Fish
Wouldn't the simplest solution be to just make bindgen emit "from <file
name>@<hash>" into the /* automatically generated by rust-bindgen */ comment?

Then when it loads a .h, hash it, and if the hash is unchanged don't write
anything. This way, the cargo/rust incremental compilation does the rest of
the work. Minimal change to how it works now, yet the compile times go way
down.

If you are willing to live dangerously, you could always use modification
times instead of hashes to avoid having to even read the .h files on compile,
but frankly that sounds like it'd just make enough heisenbugs that people
would start doing clean compiles just in case.

~~~
JoshTriplett
Caching would certainly help improve the performance of bindgen. But I'd also
like to improve the quality of the bindings, avoid the need for a build script
to invoke bindgen, and reduce the amount of boilerplate needed to make safe
wrappers.

------
jedisct1
Hard to predict what the "Future" is.

Rust fills a niche. It's not the answer to everything.

The learning curve is steep, and for many applications, the benefits are
nonexistent.

Although you can use Rust (or anything, even Bash if that's your thing) to
write web applications, Ruby, Python, PHP and Javascript are far more
productive and this is not going to change tomorrow.

Rust's borrow checker doesn't add anything besides complexity here.

Go is also a nice balance between being simple to use and powerful as a system
language (unless "has no GC" is how you define a system language).

Swift has most of the best parts from the language above.

Crystal is a pleasure to write and runs fast.

Zig may eventually get more traction.

Something like Rust, but accessible, readable, that compiles quickly, is
stable and has a natural way to do async operations could quickly make Rust
obsolete.

~~~
onebot
I often see "steep learning curve" cited as a negative about Rust. But I think
it is far less of a learning curve than it is to be a reliable C and C++
programmer.

I am not sure how much Rust you have done yet, but the borrow checker is a
tremendous confidence booster. Especially refactoring code. I have never had
anything where I can feel at ease in making big changes to an existing code
base. As all things, I don't think you notice it once you learn how to write
safe Rust code.

Go is certainly a good balance. One of its best things is the rich standard
library. I wish Rust took more of that approach.

One thing about Rust that is maybe overlooked is that it is, like C/C++, truly
"full-stack". By that I mean you can go from low level embedded
(microcontroller with no MMU) all the way up to web server, etc. I don't think
it is really a "niche" language--at least it has a very horizontal use case.

Having been at this for a super long time, I have seen the popularity
languages come and go from ASM, Perl, Java, Python, .Net, etc. I can assure
you nothing is gonna "quickly" make another language obsolete. New languages
are incredibly hard to get off the ground and be relevant for a long time.

~~~
EpicEng
>I often see "steep learning curve" cited as a negative about Rust. But I
think it is far less of a learning curve than it is to be a reliable C and C++
programmer.

Man of us are already competent in C and/or C++, so to make a move there has
to be a big value prop if it's a large investment. I'm not saying there's not,
but most of us aren't deciding to pick up C, C++ or Rust from scratch.

~~~
holy_city
I think Rust adoption has pointed out that the idea of safe C/C++ developers
are a myth. It's an appeal to authority to be sure, but if Intel and Microsoft
(and others, but those two have talked about it) are finding that their
security-conscious C/C++ developers are still putting memory safety bugs into
production - there's an argument that the idea of "competent" use of C/C++ for
safety critical is possible (in general) needs to be brought into question.

On a personal note, learning Rust has made me a much better C++ developer. I'm
more conscious of various degrees of aliasing and multiple ownership, to the
point where much of the C++ I've written of late is inspired by the borrow
checker's conventions. And since what I do is usually executed concurrently,
I've seen a concrete decrease in bug count and severity without cost in
performance. Which means the time investment in learning Rust has paid off, in
my opinion.

~~~
pjmlp
While I agree, and I do like Rust, C++ still has a winning hand for those of
us on Java/.NET.

Just to give a possible example, given everything that Microsoft has been
doing about Rust.

On what concerns Windows systems programming, Rust must be able to integrate
with .NET, allow mixed mode debugging, authoring of COM/UWP, use of the GUI
frameworks, just as easy as VC++ allows us to.

So I am eager to get to know about whatever Microsoft might announce in this
regard.

~~~
holy_city
You can integrate with COM already through winapi [1] (and author your own COM
objects too with com-impl[2]). GUI stuff is still a long way from being
useful, but a huge chunk of code has nothing to do with UIs. And Rust can
integrate with anything that can call C.

w.r.t debugging, I haven't had much trouble mixing with C++ but I haven't
tried to do anything through C#.

[1] [https://github.com/retep998/winapi-
rs](https://github.com/retep998/winapi-rs)

[2] [https://github.com/Connicpu/com-impl](https://github.com/Connicpu/com-
impl)

~~~
pjmlp
You can also make fire with two stones.

That is the difference between using C++/CX, C++/WinRT or the existing Rust
libraries.

So how do you integrate Rust with VS debugging tools?

~~~
EpicEng
>You can also make fire with two stones.

I'd love to see that trick.

~~~
pjmlp
Here you go,

[https://youtu.be/W_HJ1czydiI](https://youtu.be/W_HJ1czydiI)

~~~
EpicEng
He also needed wood shavings

~~~
pjmlp
Flammable material is always required, regardless of the ignition method.

------
prideout
Rust really does seem to be taking off in the realm of native languages.
Personally I would've preferred something simpler, such as nim or Kotlin
Native.

However I'm excited for the future of system-level programming: we were stuck
with C/C++ for a long, long time and maybe that's finally changing thanks to
Rust!

~~~
Diggsey
Both Nim and Kotlin Native have a runtime in the form of a GC/automatic memory
management, so you'd still need another language "beneath" them to get the job
done.

In the system programming world, "simple" means having the program do what you
tell it _and no more_ , so that there are no surprises when you come to run
it.

Rust has a very complicated compiler, and a moderately complicated syntax, but
the _semantics_ of the language are amongst the simplest out there - far
simpler than C (purely because of the UB), Nim or Kotlin Native IMO, and that
really helps when writing low-level code, or even just when contributing to an
unfamiliar code-base.

~~~
hu3
I don't know how to put this politely.

There's nothing simple about Rust.

The compiler is complex and slow.

The borrower semantics is anything but simple.

It isn't uncommon for the syntax to look arcane.

The standard library is shallow often making developers have to resort to
third party libraries for trivial things.

Rust improved upon languages like Cyclone but it's a far cry from being the
next C/C++ when it comes to potential market adoption.

~~~
lyricaljoke
_The borrower semantics is anything but simple._

I keep seeing people saying this when discussing Rust in relation to C++. It's
not untrue, but I would counter by saying that people who were writing C++
without having a full understanding of ownership and lifetime semantics were
writing buggy code. Rust just makes understanding those semantics required to
get your code to compile.

~~~
tomlagier
I have a somewhat related question -

I took CS 101 ~ 301 in college, and have worked briefly in C++ here and there
during my career. I like to think I have a working understanding of pointers
and references.

Despite that, whenever I go into a C++ codebase (recently, the Chromium
codebase) I get _completely lost_ trying to figure out what the owner and
lifetime of an object is, whether it's appropriate to pass by value,
reference, or clone. I have absolutely no clue the impact of these decisions
aside from a vague sense that pass-by-reference is more memory efficient and
cloning is safest (When do we care? Is it something you can just pick one and
forget about until performance matters?).

How do you start to pick up an intuition for manually working with memory this
way? Is there a set of references that can take you past the beginner level? I
find the C++ reference documentation completely opaque, and most search hits
tend to be too domain specific to be useful.

Is this something that Rust would help with? Is their model easier to
understand when each case is correct? Is it something that comes with language
exposure? Or tooling?

~~~
tene
Rust is a huge help with exactly this problem. The compiler will clearly tell
you exactly where you've made a mistake if you give it code that violates the
ownership rules, like trying to keep a reference past its valid lifetime.

It took me a little bit to get used to, but learning this definitely helped me
learn to think about ownership and lifetimes better. I highly recommend you
try learning some Rust.

------
zwieback
Anything that wants to unthrone C not only has to be better and no worse than
C but also has to beat "C plus domain-specific libraries". A lot of things C
itself lacks can be added with relatively thin libraries. The problem with
that, of course, is that we can always circumvent libraries, conventions, type
checkers, etc. and do dangerous things.

In that sense Rust does seem very interesting.

------
blub
The Rust community definitely believes in the idea that if you repeat
something enough times it becomes reality.

At least the Rust subreddit figured out that there's this other language which
fulfills the same requirements of being a higher level C, except unlike Rust
it has a massive ecosystem, mind share and vendor support - including from
Intel. It does have worse PR, but this is mostly because Rust is unbeatable
here.

It would be interesting to also hear from Josh's colleagues which work on a
large number of C and C++ projects. Do they agree that Rust is _the_ future?
And does that mean that all of Intel's money-making software is essentially
obsolete? Is Intel the company aware of that?

~~~
dhyft
>At least the Rust subreddit figured out that there's this other language
which fulfills the same requirements of being a higher level C, except unlike
Rust it has a massive ecosystem, mind share and vendor support - including
from Intel. It does have worse PR, but this is mostly because Rust is
unbeatable here.

Which language are you talking about? C++?

~~~
blub
Yes, C++. Although I'm not convinced that Intel's ready to move away from C to
be honest.

------
sdinsn
I think Rust is a cool language, but I've never seen any job postings for it.

I'm still not sure what type of applications to use it for to be honest- not
having good support for embedded systems and no CUDA/OpenCL support makes it
not appealing.

------
davidhyde
> What sets it apart from other modern languages is that it does not have a
> garbage collector or runtime system of any kind.

This is not strictly true. Most Rust programs, like most c programs, do have a
runtime. See [https://doc.rust-lang.org/0.12.0/guide-
runtime.html](https://doc.rust-lang.org/0.12.0/guide-runtime.html)

However, this runtime can be replaced which is what makes Rust suitable for
certain systems programming scenarios (like building operating system
kernels). This is the realm of [no_std]

~~~
steveklabnik
I think you're being downvoted a _bit_ unfairly.

1\. Your link is incorrect, as the sibling comments say, but you're also
correct that Rust has a runtime. It's about the same amount of runtime as C,
but like C (as you say), it does exist.

2\. no_std does not remove the runtime. I _think_ the closest you can get is
no_core, but to be honest, I'm not actually 100% sure.

------
Endy
Maybe it's the new Assembly. With what little hacking and programming I am
willing to put effort into, I will always prefer to work at the direct
hardware access level rather than the massive abstraction that is required to
run C & the relevant interpreters. Then again, I prefer working on 6xxx
architecture (6502,6507,6809,etc) and cap out around 286 IBM compatible with
MS-DOS for any real tasks.

------
sleepysysadmin
Rust and Python. I see Rython in the future.

edit/sorry?

~~~
dbcurtis
How do you see that working? Rust and Python come from very different
philosophies. I like them both, but they are a strange mix. Python extensions
in Rust? That could be a good thing. Much easier to write a reliable Python
extension. I imagine tooling for that already exists and I am simply unaware.

Or, maybe Rust semantics with Python’s readability? I would like that. Rust is
the wave of the future, but ultimately the language will not be a long-term
survivor, entirely because of the ASCII-salad syntax. I predict that we will
learn huge amounts about language semantics from Rust, thank the team, and
then replace it with something pleasant to read.

Rust is the Algol of a new generation. I mean that as both high praise and as
a sad prophecy.

~~~
fb03
I too am having problems 'getting into' Rust because of all that salad-y
syntax. It looks like Perl at some times ;__;

~~~
johnisgood
let dest: Vec<String> = dest.split(',').map(|name|
name.trim().to_string()).collect();

impl< $($kind: TryFrom< Value >,)* F > allMut< ($($kind,)*) > \+ 'static,
F::Output:

~~~
steveklabnik
The first line is formatted by rustfmt to be

    
    
        let dest: Vec<String> = dest
            .split(',')
            .map(|name| name.trim().to_string())
            .collect();
    

which makes it quite a bit more clear what's going on, IMHO. Cramming stuff
into one line makes things unreadable no matter what the language.

That second line, while intense, is the syntax for writing macros, not normal
Rust code. As always, it depends on what you're doing, but you almost never
need to write macros yourself.

~~~
johnisgood
Yes, the formatted version seems better. My complaint with Rust is the heavy
use of symbols. I do not know what is going on most of the time because of it.
How would you format this example?

 _fn deserialize < D: de::Deserializer< 'de > >( deserializer: D ) -> Result<
Self, D::Error > {_

In my opinion it is not obvious what most of the code is doing when you have
hundreds of lines of code and each line contains lots of symbols. Again, this
is just my opinion and perhaps my limitation.

I looked at many codebases and found that they were not easy on chaining and
using symbols. I do not deny that they could have written it in a more
readable way, but generally it was not the case in my experience, based on
these projects at least.

~~~
steveklabnik
I think it really depends on what you're used to.

You could format this alternately as:

    
    
      fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
      where
          D: de::Deserializer<'de>,
      {
    

using the `where` clause makes it easier to see the bits, in my opinion. That
said, even with your version, you can read it almost front to back: "A
function named deserialize that takes one type parameter, D, that implements
the Deserializer trait. It takes one argument of type D, and returns a Result
of either Self or D's error type."

The symbols in this example:

* <> are used for generics, which is common in other languages.

* : is for two things: trait bounds; that is, restricting a type parameter by a given trait. I'm not sure where this came from, but it feels fairly intuitive after a bit, at least to me. Second, for indicating the type of arguments. Both are about defining the types of things, so even though they're different, they feel consistent, at least to me.

* ' is used for lifetimes; this comes from OCaml, which many programmers aren't familiar with. Nobody likes this syntax, but nobody could come up with a better syntax.

* () is used for the parameter list to a function, this is extremely common in languages.

* -> indicates the return type

* :: is for navigating namespaces; the first instance is for a module, the latter is for an associated type. Similar to :, these are different but similar things, so the similar syntax makes it easier to me.

It's all just practice. Being familiar with a wide variety of languages helps,
because Rust draws from a lot of other places.

~~~
johnisgood
Thank you for the brief explanation (or the meaning) of the symbols! Is there
a place where it is laid out in a similar fashion? It would help tremendously.

~~~
steveklabnik
Any time!

[https://doc.rust-
lang.org/stable/book/appendix-02-operators....](https://doc.rust-
lang.org/stable/book/appendix-02-operators.html)

(I also just realized HN formatting messed up my re-formatting, I've fixed it
now)

------
codesushi42
C is not the new assembly. This line has been reused for years, even decades.
And it has always been a lie.

Memory safety and automatic memory management come at a cost. Even in Rust. C
will always have a use for critical performance in the embedded world.

~~~
kllrnohj
> C will always have a use for critical performance in the embedded world.

Based off of what reasoning? It's not like C is any faster or more efficient
than Rust or C++. Heck you can often go _faster_ in C++/Rust than you can in C
thanks to the ease of using abstractions that just make things go-faster for
you automatically (such as SSO in things like strings, or constexpr for
compile-time resolution).

The embedded world isn't using C because it's a good fit, they are using it
because of legacy inertia and lack of motivation to move to anything else. IoT
is starting to change that, as all those C memory vulnerability issues turn
into product support costs.

And also realistically embedded isn't even restricted to C already. Very
popular microcontrollers like the esp8266 or esp32 also have javascript
runtimes.

~~~
codesushi42
_It 's not like C is any faster or more efficient than Rust or C++_

Huh? C is certainly faster than C++.

 _go-faster for you automatically (such as SSO in things like strings, or
constexpr for compile-time resolution)._

That is a terrible example. You shouldn't be using the STL (i.e. std::string
copying) for performance critical sections to begin with.

 _Very popular microcontrollers like the esp8266 or esp32 also have javascript
runtimes._

First, esps are not low end microcontrollers at all. Second, no one uses JS
runtimes for performance critical code on microcontrollers (e.g. JS will not
give you direct memory access). What an absurd claim.

~~~
kllrnohj
> Huh? C is certainly faster than C++.

It literally isn't. Quite often the reverse is true, as C++ gives you better
tools for compile-time optimizations.

> That is a terrible example. You shouldn't be using the STL (i.e. std::string
> copying) for performance critical sections to begin with.

I think you're confusing the example with a recommendation to use the STL?

std::string is just an example of SSO. The concept is generally applicable and
used in more places than just the STL.

Although "You shouldn't be using the STL for performance critical sections to
begin with." is also complete fucking bullshit anyway. There's nothing wrong
with the performance of eg std::array. Or unique_ptr. Or vector. Or a variety
of other things in the STL. You're not outperforming any of those with raw C.

It's not 2003 anymore so stop acting like it.

~~~
codesushi42
It is 2019 and even game programmers still avoid STL for performance reasons.

And optimization is taken to another level from that on embedded systems.

I hate to remind you again, but it is 2019 and C is still very relevant on
embedded systems. And Javascript, not so much. _Snicker_

~~~
pjmlp
Surely not the same game programmers that use Unreal with its C++ GC.

~~~
codesushi42
What does that have to do with anything?

Yes, those same game programmers avoid STL.

No one is advocating replacing C++ with C on capable hardware, troll.

------
ErotemeObelus
People who say "C is the new assembly" don't understand why people moved from
assembly to C.

Assembly is bad because it is typeless. Because it is typeless, there is no
way to check for program correctness. Rust is okay because it doesn't require
garbage collection and types, but the best language would be C with a highly-
elaborate strong type system and no closures or other unsuitable concepts for
systems programming.

~~~
damnyou
Why are closures unsuitable for systems programming? Rust does them really
well, not even allocating in the most common cases.

~~~
jerf
Closure often have really weird lifetimes, so typically they've ended up
implemented either with GC of some sort (possibly refcounting), or required
such exceedingly careful handling that the cost/benefit analysis gets a big
fat lump of "cost" that isn't a problem in most other environments because
trying to track the transfer of ownerships across scopes, up and down stacks,
and perhaps even between threads is just insane. Typically the entire
_purpose_ of the closure is precisely to inject some code's logic into a quite
distant other bit of code, so the problem is not amenable to normal techniques
around rearranging things to be on the stack and so on. The very nature of a
closure-type abstraction in C is go to stomping right over the generally-
fragile informal, unsupported organization of what code is responsible for
what memory.

I once was working with libpurple in a glib environment that made heavy use of
segfaults in C. I mean closures. Closures in C that made it really easy to
segfault when calling to a closure that had been freed, or really easy to leak
if you didn't free them. I encountered situations where the common paths used
by the "standard UI" for libpurple worked, but even when I was quite sure I
was handling one of my closures correctly, the system would crash because it
still free'd my closure, even though it should have been my responsibility to
do so, and so on.

Prior to Rust, I'd agree with the common wisdom that closures and systems
programming had gone together poorly. It's a demonstration of the power of
Rust's approach to the matter that closures become practical in system
programming with it; that had not previously been the case.

~~~
damnyou
Right, there's definitely all sorts of issues with closures (esp async ones)
if you don't have lifetime analysis. But Rust is the only systems programming
language that I take seriously.

------
floor_
Rust has a npm package problem.

For reference:
[https://twitter.com/bascule/status/1166583003021283333](https://twitter.com/bascule/status/1166583003021283333)

~~~
dpc_pw
But also has a solution: [https://github.com/crev-dev/cargo-
crev](https://github.com/crev-dev/cargo-crev)

~~~
swsieber
As great as that tool is (I do think it's good) I wouldn't call that a
solution, I'd call that a mitigation. If the ecosystem is terrible
(dependency-bloat wise), then a tool like that doesn't make a big impact.

~~~
burntsushi
I think the biggest problem crev has is adoption. But if it solves that, then
I disagree that it doesn't help with the dependency bloat problem. It would
serve as pressure against adding dependencies, because with crev, adding
dependencies becomes a lot more work because of the code review system. That
in and of itself may be enough pressure to reduce the dependency bloat
problem.

It's a big if---especially adoption---but it makes sense to me.

~~~
feanaro
Something that requires a lot of work sounds like something people will be
hesitant to use.

~~~
burntsushi
Hence my acknowledgment that adoption is the biggest problem to overcome for
crev. :-)

