Hacker News new | ask | show | jobs
by ktamura 3662 days ago
As a long-time developer marketing person, I must say Rust is kicking ass, not just as a language but as a community. They are deeply strategic.

1. Clear audience target: They aren't going after C++ gurus or C magicians but people who are new to systems programming. From Klabnik to Katz to literally everyone in the community, they are consistent with this messaging.

2. As part of 1, they have invested a lot in teaching systems programming 101 (heap v. stack, etc.), i.e., stuff that you learn in the first course in systems programming in college, but many self-taught, higher-level programmers might not know. This is a great example of authentic content marketing based on a clear strategy working out.

3. Their community is very inclusive. My experience (as a marketing guy who barely remembers how to code) is that people are very helpful when you ask questions, submit a patch, etc. This has been the case for me not just with Rust itself but a couple of Rust projects that I've interacted with.

10 comments

As a C magician, I haven't written a new C project since the Rust 0.8 era. The only reason you would is ease of updating dependencies through distro package managers (because Rust has no stable ABI and performs extensive cross-library inlining). There's no need to market to C people because those who understand the language well will immediately get why Rust is better.

For C++ people, Rust's generics remain less powerful than template metaprogramming (which is Turing-complete, with people building real programs in the tarpit), so there are reasons you might not switch.

Meanwhile, Rust does make it a lot easier to get started with systems programming, which is good! Every tool should help both empower beginners and extend the reach of experts. For example, writing zero-copy parsers in C is fairly hard to get right, and might not be worth the debugging or validation time that even an expert might have to put in. C string manipulation works, but it's verbose and fiddly. In Rust, it's trivial to use the lifetime system to make sure you keep all the input data around long enough and don't read outside the buffer. You could even use #[must_use] and affine types to check that every character of input data ends up attributed to exactly one terminal.

> The only reason you would is ease of updating dependencies

Or if Rust doesn't support your OS yet.

I am working on porting LLVM and writing a MIR to C++ translator in parallel. We'll see which one I get further on.

Because I'd love nothing more than to use Rust.

Is the problem the OS, or the architecture/ABI? I wouldn't expect porting to a new OS to be terribly difficult, though it is a time sink since there's a fair bit of API surface to cover to get Rust's libstd ported, and you'd want to work with upstream so they know your platform matters.

If your OS doesn't look at all like UNIX, then you'll have to give up on libstd (which talks about "file"s and "processes" and such nonsense), but libcore (which presents data-structures and other logic, rather than IO, code) should be fine.

It's a platform with a file format and linker sections that are currently unsupported by LLVM, among other issues.
Windows isn't like UNIX, yet still supports libstd fully. That said, yes, if your OS is so different that it doesn't support files or processes or something, you'd have to stick with libcore. The standard library not so much UNIX-centric as it is "common OS features"-centric. We even went so far as to not pick the UNIX names for common functionality, which can often happen with languages that start on a UNIX and move out.
Similarity isn't a clear-cut yes/no question, but the NT kernel is so similar to UNIX that it was able to adopt a second syscall ABI compatible with Linux. Present operating systems are basically a monoculture in terms of high-level design decisions; Rob Pike complained eloquently about this in 2000, and outside of possibly unikernel development (which still usually has a libc/unix-like layer implementing at least a filesystem) little has changed since: http://herpolhode.com/rob/utah2000.pdf
Yeah, I'm very intrigued by unikernels myself; as far as I know, I'm the first person to have gotten an Iron web app running on Rumprun. I figured I'm the first because I had to send patches to make it work :)

I guess my point is that even if vague designs are relatively a monoculture, that still means that anything that fits inside that box is going to be reasonable to port over. And I'm glad that it's so easy to not use the standard library for other cases; my little kernel doesn't yet have processes or files, and Rust works for it just fine. Well, it doesn't have them yet, anyway... hopefully soon.

Can someone explain why Rust doesn't have an ABI? I understand that its a still a newish language but hasn't it been around long enough to want to define one? Is the idea that it won't have one just like C doesn't have one and you will have a few like how C has stdcall, cdecl and fastcall?
C does have a standard ABI on each platform (where "platform" is slightly vague, ranging from "a place where people agree to use the SYSV ABI" to "Windows+MSVC"), so you can generally call into C libraries from the same "ecosystem" and not have to notice if they get recompiled between runs; library maintainers can put in some work and make promises about ABI stability.

The reason Rust doesn't have a defined ABI is basically that it wouldn't buy the same benefits it does in C. Specifying an ABI requires a lot of per-platform work (which the C community has already done), and, because of the importance of cross-crate inlining (all generic functions get inlined into call-sites by default), would not be sufficient to provide the benefit of in-place library updates. If you rewrite generic code in libfoo, and libbar depends on it, you can't get around recompiling libbar.

This is basically because Rust is a higher-level language where you use iterators, iterator adaptors, and higher-order functions in the course of writing libraries and applications. In C, you would manually inline things like iteration, writing for loops and populating intermediate data structures yourself. In Rust, this is something that can be factored out into libraries, but that means your code's meaning depends more deeply on the meaning of library code. To optimize away these abstractions and provide good performance, the compiler needs to inspect and make decisions based on library source code when compiling code that calls it. To permit efficiency, Rust basically has to be compiled from leaf dependencies upward.

In general, this is probably worth it, but it means we do need to rethink the C/UNIX style of packaging, which doesn't work very well when a libstd update implies every other package must also update. Some form of compiler middle/backend in the package manager (think Android's ART compiler), or a specialized form of binary or IR diffs (like Chrome uses) would probably go a long way. If we want to solve UNIX's problems, there will be a need for some cascading changes across the OS ecosystem.

Or how about we avoid the whole thing and allow multiple versions of a lib to exist, and then prune the branches as they are no longer needed? Something akin to Nix/guix, Gobolinux, or even GNU Stow.
C and C++ libraries can use ELF symbol versioning.

Say you have a function like

  int foo_do(struct foo *, int);
but to fix a bug and/or tweak the API you change it to

  long foo_do(struct foo *, int, int);
then ELF symbol versioning allows you to do

  __asm__(".symver foo_do_v1_1,foo_do@@v1.1");
  long foo_do_v1_1(struct foo *F, int arg1, int arg2) {
    ...
  }

  __asm__(".symver foo_do_v1_0,foo_do@v1.0");
  int foo_do_v1_0(struct foo *F, int arg1) {
    long rv = foo_do_v1_1(F, arg1, 0);
    assert(rv >= INT_MIN && rv <= INT_MAX);
    return rv;
  }
where the runtime linker will link foo_do_v1_0 as foo_do for programs originally compiled against the v1.0 release, while programs built against v1.1 will be linked to foo_do_v1_1. You can do this as often as you want, though you can't generally go back further than when you first began using ELF symbol versioning to compile and release libfoo. You only need to add an ELF .symver alias for functions that have multiple aliases, but you do need to at least enable versioning (usually by specifying a version file with a catchall "*" entry which tag functions not explicitly aliased) at the point you begin maintaining a stable ABI.

glibc is pretty much the only major library that makes use of this capability, despite the fact that it's been around for well over a decade. Most developers simply don't have the foresight or interest in providing rigorous forward and backward ABI and API compatibility. Partly that's because in the open source world, recompiling packages is much easier than in the proprietary world. And especially in the Windows world (where the CRT was never forward or backward compatible) you often packaged dependencies with your software, even if dynamically linked. And so newer languages like Go and Rust are being built with the presumption that both recompiling and bundled dependencies are the norm--it's what people are doing anyhow, and it simplifies the compiler and its runtime. That it's sad that this is the norm is beside the matter.

Interesting, I had no idea the C runtime on Windows is not forward or backward compatible.

I'm curious about your thoughts on why the "recompiling and bundling dependencies" approach might not be the best way compared to ELF versioning facilities? Do you just feel like its a less elegant solution?

Thanks

Eventually we will want to do updates, unless you prefer bugs to not. When we do, we'll need strategies to tame the quadratic space blowup caused by lack of sharing across the dependency tree relative to the current model.
Yes, but it means they can be done in the background without disrupting the workflow as much.

Install/build the new version while keeping the old in place, then flip over to the new when ready, and then starting taking out the old one.

Thanks for the detailed response and insight.
Don't prematurely publish your interface.
I suppose I'm in their target audience, then. I've not done any systems programming, but do have a curiosity about it, and Rust has caught my eye.

But my main problem is a lack of a project -- a ThingIWantToDo that would be well suited to a systems programming language like Rust. And I don't even know what kinds of problems or projects are well suited to systems programming -- so far, when I've had an itch to scratch and gone to scratch it, I've found Python able to do what I want.

Now I realize that Python is in no way appropriate for all classes of problems, and that there problems for which it is not fast enough. But thus far, the only project I'd like to tackle that I know Python will be too slow for is doing real-time audio processing on Linux with lv2 plugins and JACK. But lv2 and JACK are C APIs, so that's incentive for me to learn C, not Rust.

Understand, this isn't a knock against Rust. As I said, it's caught my eye. I just haven't found a compelling reason to actually get involved yet. I am hoping I eventually will.

> But lv2 and JACK are C APIs, so that's incentive for me to learn C, not Rust.

Maybe, but it might be an incentive to learn just enough C that you can wrap the C interface in Rust. The point of having an API is to have well defined behavior at a particular boundary, which can reduce quite a bit (but not eliminate) a lot of the reasons to use the language it was implemented in on the caller side.

I suspect learning rust will probably make you familiar enough with the basics of C that you won't have to do much specific C learning to use most libraries.

Here's an example of a lv2 plugin written in Rust: https://github.com/poidl/eg-amp_rust and here's a WIP rust wrapper for JACK: https://github.com/nicklan/rust-jack
Magicians, schmagicians. I say that as part of (possibly) that group. We've just learned to "cover our father's nakedness" so to speak.

I just hope Rust practitioners can do a few things where they have to use 'C' ( properly ), much as I think assembly is a good thing for 'C' programmers to do.

I hope the relationship between 'C' and Rust is collegial - ideally, it would approach being the same people over time because legacy code. Nothing divides like language, and flexibility is a great way to harden your skillset.

> They aren't going after C++ gurus or C magicians but people who are new to systems programming.

If this actually is their strategy, is it being done voluntarily or out of necessity? I ask, because I've witnessed enough scepticism about Rust from C and C++ programmers. Rightly or wrongly, there are enough of them who don't appear to be receptive to Rust, and likely never will be. So the Rust community may never be able to appeal to these C and C++ programmers, even if they wanted to. The only option may be to appeal to the non-C and non-C++ programmers.

> I ask, because I've witnessed enough scepticism about Rust from C and C++ programmers.

I don't think there's a single language on the planet that hasn't had skeptics, especially at the beginning. Remember how skeptical everyone was of Python at first due to its significant whitespace?

Programmers are very tribal about their tools.

> Remember how skeptical everyone was of Python at first due to its significant whitespace?

A large group of programmers still hates Python for this reason, to this day. They've just moved on and are probably completely ignoring Python these days.

Python has come a long way, but for domain reasons, the significant whitespace isn't my primary beef. Packaging is, because I haven't captured all the gnosis yet.
Thanks! To be clear, I do very much want C and C++ programmers to be using Rust as well, I just think there's a lot of opportunity in the "new to systems" group. They're also just my group of people, so I find it easier to pitch things to them. I can talk about anything Ruby at any level with a Ruby person, but I first picked up C++ in the late 90s, and hadn't been active in systems-level stuff for a long time when I came to Rust, so I'm a bit removed from feeling their pains directly.
C gets out of the way and lets you do useful things that are "undefined behavior". How convenient is it it Rust, to, say, use the unused bits in a pointer (due to alignment) and put a type tag in them?
Like in C you can cast the pointer to an integer and back. Rust allows such hacks if you mark them with a "hold my beer" keyword:

    let the_bits:usize = unsafe { std::mem::transmute(pointer) };
You can also use `std::mem::forget(*pointer)` to avoid fighting with Rust about who manages the memory.
You can actually turn a pointer into an usize without using an unsafe block. For example, here's how you'd do it with a reference:

    let the_bits = pointer as *const _ as usize;
The ISA is generally pretty well-defined, a lot of the undefined behavior is introduced by C.

So I don't think it's fair to say that C "gets out of the way". It won't let you get the overflow flag, or alias arbitrary pointers, for instance.

Okay, now you've piqued my curiosity. Is that something to do because it's really smart and clever and fun, or is there a certain problem or class of problems where doing that is unambiguously the best or least-worst solution?
Haskell does it automatically as an optimisation: if an algebraic type has fewer than 2-3 cases, then it inline the tag bits directly into the pointer, thus saving an indirection on pattern match.

Some C data structures also make use of low level bit tricks like this to save space and reduce indirections. For instance, the hash-array mapped Trie uses a 32 bit mask to both track which indices of the current node are actually populated, and incidentally, how large the node currently is. It's quite clever.

These are always my foot examples to evaluate any alleged systems programming language. No language less powerful than a theorem prover is currently capable of expressing these idioms safely.

Rust actually does a bit of this internally in the form of the null pointer optimization. If you have an Option<&T> (or Option<*T>) value, it's actually stored as a single pointer-sized value, with None being represented by a null pointer on the assumption that null is not a valid pointer.
As to3m says, this is often done in programming language interpreters.

If most objects in your language were heap allocated and you want to store a small integer you would allocate a new object on the heap with space for one integer, set up its headers, etc. You could instead set one of the unused bits in the pointer to indicate that it's an integer and not a pointer, then store the integer in the remaining bits, avoiding the heap allocation at all. The Lisp world calls this a fixnum.

The more pointer bits you can steal, the more kinds of data you can store directly in the "pointer" itself. It's also possible to store the type of objects that are actually allocated on the heap in tags on the pointers to them, but I don't know if that's done any more.

You might do it if you were writing an implementation of a language such as Scheme.
> developer marketing person

What is that?

> They aren't going after C++ gurus or C magicians

Don't they have anything to gain from using Rust?

Sure they do. But when you say "gurus" and "magicians" these are people who have spent decades with the language and are awesome at it. It's possible that Rust may improve their lives, but it would take years before they have that same level of proficiency. Not because Rust is hard, but because they are so good at C++ and getting that good in anything is hard.

Rust does market to C/++ people, a lot. We just don't market to the super-awesome C++ folks. It's the same reason I preferred Word 2003 over the new stuff for half a decade. I had years of memorized shortcuts, custom macros, and general ui familiarity. I could eventually learn the shiny new Word and become as good, but the activation energy for that is too much and I was happy with 2003.

Rust isn't only going after non-systems folks. The community is roughly half systemsy. But it may seem this way because Rust tries very hard to not alienate non-systems people with jargon and unexplained systems concepts.

A developer evangelist. Think someone doing a talk about new Java 9 features at a Java conference.

C++ gurus and C magicians already have invested too deep into their languages to throw everything away and start from zero.

For example I love Rust and play occasionally with it, but for the time being C++ is my native language on the job when I need to use a native language outside .NET or JVM.

I know it since the C++ARM "standard" and we depend on standard OS tooling that Rust is still catching up with.

The day will come when our customers will be able to do mixed debugging between JVM/.NET and Rust. Or produce COM as easy as C++ compilers do.

But these are things that beginners in systems programming aren't usually doing.

As a C magician, rust provides too many clear improvements over C to ignore it. I certainly don't feel like I am 'throwing everything away and starting from zero,' as much of my C (and other language) knowledge transfers over to rust.

I'm not a C++ guru, but I think modern C++ is powerful enough that it doesn't feel lacking in features compared to rust, like C does. There is less of a draw for seasoned C++ programmers.

Rust seems to be gaining a lot of momentum and I am becoming more and more confident that it will be regarded as a major language for embedded and general systems programming and possibly even a successor to C.

For me C was already lacking when I got to learn it in 1992 , because by then I was quite comfortable with Turbo Pascal 6.0.

Just check the feature list and type safety differences. The only advantage from C was being less fragmented than Pascal dialects.

So I became a C++ hipster (if that would be a thing in the 90's).

We used to have the same heat from C guys that C# and other language users nowadays have from systems languages.

Hence why I am always supportive of new programming languages that target the same use cases.

Developer marketing: marketing to developers. Marketing gets a bad reputation among developers, but it's vital for any technology to be marketed: keeping documentation up to date, answering questions for newcomers, explaining strengths/weaknesses, etc.

>Don't they have anything to gain from using Rust?

Who's "they"?

The magicians.
They might have something to gain, but they're probably deeply invested in the tech already.

People are very hard to dislodge from such positions, unless the new positions have overwhelming benefits such as: a new environment does not support the old tools/programming language; a radical paradigm shift has happened that risks to make completely obsolete their previous knowledge, etc.

Rust is more of an incremental improvement over C++, than a radical leap forward. So C++ magicians are less likely to want to switch over.

I still use 'C'. I do this primarily because the legacy code base is staggeringly large. I'd jump on a gig doing Rust in a heartbeat, all other factors to the good.
> Don't they have anything to gain from using Rust?

Sure they do, but they're not throwing away a decade of hard-won experience in their specialties just to tinker; at least not with production code bases. The barrier of entry for beginner systems programmers is lower.

As a C++ enthusiast, I wouldn't use the words "throw knowledge". All the concepts you can find in Rust are almost matching one to one to a C++14 equivalent (albeit pattern matching for instance). The difference being the enforcement of these good practices by the compiler. It would most likely take me 2 days to read the latest rust doc and 1 month of practice to be proficient.

Thing is, it's a bit like switching from Python 2 to Python 3. Why would I move to this new environment where I would need to recode everything from scratch? Python 3 will take decades to overthrow its predecessor, how long will it be for Rust? Will it ever succeed? Will the C++ committee react and borrow some of Rust awesomeness? Can I find co-workers willing to learn Rust?

Someone who markets to developers. The language and context should clear up the ambiguity that they don't mean they are merely a developer that works in marketing for something like, say selling potato chips
So like a lite developer advocate
It used to be called advertising, then marketing, then evengelizing and now advocacy, yes
This is something that should be done as well by the guys doing D.

Even if they can succeed by going after the C++ gurus as well.

Thanks for pointing out the community aspect - they're welcoming, pragmatic and don't foeget, the documentation and examples are rather good.

Rust is what it took C++ 20 years to become, except anew and reimagined.

It's ready and usable, today.

Can you give an example of 2? Where have they invested in teaching systems programming 101? Is there a specific blog? Thanks.
The Rust book has this chapter, for example: http://doc.rust-lang.org/stable/book/the-stack-and-the-heap....
Ah neat, I did not know about the book, thanks.
No worries. I'm currently in the process of re-writing it for the second edition...
Would it be worth including a chapter(s) on writing Linux system utilities using Rust?

I hope you announce it on HN when the rewrite is finished.

I don't want to put Linux above other platforms by only including it. And it's already a huge task on its own.

I will for sure. It's also going to end up getting published by No Starch.