
Systems Languages: An Experience Report - signa11
https://blog.usejournal.com/systems-languages-an-experience-report-d008b2b12628
======
coldtea
> _If the language has the problem that people are fighting with the language
> in order to become productive with it, perhaps something is wrong with the
> language, and not the programmers?_

If they stop fighting after they learn, then no, it's not a problem with the
language. It's the very definition of learning.

Now, the language might be harder to learn than others, and that might be a
problem in itself.

But not just because people have to struggle at first "in order to become
productive with it". That's true for any language that brings anything new to
the table.

> _The argument of pass by reference, or borrowing is that it’s more
> performant than cloning by default. In general, computers are getting
> faster, but systems are getting more complex._

Rust was not created to piggyback on "computers getting faster".

It was created to be as fast as possible.

~~~
smolder
Good points. Performance not being a primary concern is a meme that really has
grown beyond its place. Performance is absolutely a primary concern in very
hot code, at execution scales where it means big differences in aggregate
hardware/infrastructure cost, energy usage, and so on. Or in space, where
transistors necessarily need to be "low tech" huge radiation resistant ones.
There will never be a lack of applications for highly optimized software, no
matter how small the niche gets. Computing power may be cheap but it is NOT
free, nor infinite, nor universally portable.

~~~
steveklabnik
One area we're seeing Rust get a lot of usage for isn't performance directly,
but low memory usage. You can do a lot more with less.

------
vvanders
I think everyone agrees that "fighting" the borrow checker is annoying,
however at the risk of sounding like a Rust apologist I find that a couple
interesting things have happened over ~2 years with the language:

1\. The borrow checker usually kicks in when I want to take shortcuts that
would bite me in the future. 90% of issues I hit with it can be solved with
copy/clone.

2\. When I take the time to satisfy the borrow checker I find my
_architecture_ is better. Usually I'm tripping the borrow checker because I
don't have a clear single-owner or separation of concerns.

Also, if you're looking for an "easy" to program languages there's tons of
them out there and it definitely doesn't make sense in my mind to use Rust
where C#/Erlang/Java/etc fit the domain space better.

~~~
sbjs
Rust seems so low level that I don't get why people flock to it when C# and
Java would be much better fits? Is it just because they're bored of C# and
Java and want to learn a new language? Even Erlang should scratch that itch! I
would guess that only the Servo team really benefits from Rust, or maybe some
wall street traders who need hyper speed! Every other app should work fine
with something slower.

~~~
k__
I don't understand why anyone would go for C# or Java.

If you want GC and/or fast dev speed, go for JavaScript. If you really need
static typing, go for TypeScript. JS has one of the fastest VMs on the planet
and virtually everywhere.

If you need speed and don't want to mess around with decades of C/C++ legacy
quirks, go for Rust.

~~~
jcrites
Java and the JVM are a fantastic platform to develop on. The development
experience is great and the performance is excellent.

* Java code means what it says and is simple to reason about.

* Top-notch IDEs like Eclipse and IntelliJ IDEA. Great debugging and diagnostic support, both at development-time and in production (e.g., logging and instrumentation frameworks, crash reporting).

* Java is meaningfully cross-platform, though in practice this is mostly useful for portable development (as opposed to portable production deployment). I can develop my services on Windows or Mac, then deploy to Linux in production, with zero fuss. (Don't even need a container)

* Feature-rich standard library. Powerful concurrency primitives and data structures, async, and futures libraries built right into the Java runtime (java.util.concurrent). You can dip into frameworks like Akka for more sophisticated use-cases.

* _Huge_ open source community that's working on projects like Apache Hadoop, Hive, Spark, Avro, Cassandra, etc. Take a look at how many Apache Java projects there are, for example: [https://projects.apache.org/projects.html?language#Java](https://projects.apache.org/projects.html?language#Java) . Top-notch DI frameworks like Netty, Guice, Dagger, Spring. Top-notch REST and RPC programming frameworks like gRPC, Thrift, Cap'n Proto, JAX-RS/Jersey.

* Java code is extremely reliable. Java code cannot crash in complex ways. Try/catch covers the vast majority of concerns for practical error handling and recovery. Java code's consistent use of GC, exceptions, and treatment of sync/async means that all libraries are modular and can be meaningfully and safely composed with each other. For comparison see What Color Is Your Function: [http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y...](http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/)

* Multiple languages that can interoperate: Java, Groovy, Scala, Kotlin, Clojure. The GraalVM and GraalJIT show amazing potential: [https://www.graalvm.org/](https://www.graalvm.org/)

* Because Java is so widely used, many tools and client libraries and such support Java before other platforms.

* A large population of developers understand Java and will be productive immediately on the project (vs. obscure languages).

* Modern, concise syntax that supports anonymous classes and functions, Lambdas, streams, Optionals. Java continues to improve over time and pick up concepts from other languages.
    
    
        List<ProductDisplayInfo> getDisplayList(List<Product> products) {
    		return products.stream()
    			.filter(p -> p.getCategory() == 2 
                                    || p.getCategory() == 5 && isProductUnderDiscount(p))
    			.map(ProductDisplayInfo::new)
    			.collect(Collectors.toList());
    	}
    

* Java has good support for generic programming, unlike some other modern languages (e.g. Go). Generic programming is efficient and doesn't typically have downsides that make people afraid to use it (like in e.g. C++).

* The JVM is a _very_ high performance implementation that can rival native programs on important benchmarks for many server use-cases. I've built a lot of software and have rarely, if ever, run into performance reasons to use a different language. (Usually a small native library with JNI bindings meets the need when that's the case.) Other platforms rarely achieve a fraction of the JVM's performance in server-side use-cases. See benchmarking results from a previous comment I wrote on this topic (internal citations removed):

> Folks might also be interested in the TechEmpower web framework benchmark.
> The top Java entry ("rapidoid") is #2 on the benchmark and achieves 99.9% of
> the performance of the #1 entry (ulib in C++). These frameworks both achieve
> about 6.9 million requests per second. The top Java Netty server (widely
> deployed async/NIO server) is about 50% of that, while the Java Jetty
> server, which is regular synchronous socket code, clocks in at 10% of the
> best or 710,000 R/s.

> NodeJS manages 320,000 R/s which is 4.6% of the best. In other words,
> performance-focused async Java achieves 20x, regular asynchronous Java
> achieves 10x, and boring old synchronous Jetty is still 2x better than
> NodeJS throughput.

[https://news.ycombinator.com/item?id=14153879](https://news.ycombinator.com/item?id=14153879)

* I'm personally a fan of Rust and appreciate its concepts, but garbage collection suffices and is easier to work with for the majority of use-cases I encounter. C# and .NET also have many of the properties above, though not the large open source community.

People who are starting businesses and have a practical, get-the-job-done
attitude would be wise to consider Java. It's versatile enough to do almost
anything on the server-side.

~~~
StreamBright
Rapidoid <3

These are exactly the reasons why JVM is the primary platform for us and
Clojure/Java are the primary languages to use. If you compare languages by
performance, library availability and developer popularity it is extremely
hard to beat Java/JVM

~~~
sbjs
Why Clojure? It's slow and not type-safe. If you want something a little more
dynamic than Java but without losing speed, did you check out Kotlin?

~~~
StreamBright
Slow??? Are you kidding?

------
skymuse
I really hope he doesn't fall into the trap I did when starting out with rust.
I came into it with the perspective of an application programmer and I quickly
became salty when my knowledge didn't translate smoothly into rust code.
"Fighting the borrow checker", for me, was simply a clash of philosophies. My
way of thinking versus the rust way of thinking.

The central issue, for me, is that with rust you MUST understand the memory
model completely in order to be productive. You cannot wing this, you cannot
assume anything. I was not used to this being an application programmer and
this lead to the root of all my suffering. Once I wrote down all the borrowing
rules and deeply thought about it, I finally became productive in the
language.

I see the author shows symptoms of not understanding the memory model. His
code proves it. Instead of being angry, he should try to view rust with an
open mind and ask "why did they design it this way?". Be curious, create
experiments, probe the rust semantics, master the borrow checker. There are
rewards to be had for those willing to push through the pain of integrating
new knowledge.

~~~
sargun
Pretell, how does my code not show an understanding of the memory model? I
understand how the memory model works, I just want the language to _do the
easy thing_ (copy) in most scenarios, and make embedding (Cells, RCs) /
unwrapping more straightforward.

------
rapsey
> If the language has the problem that people are fighting with the language
> in order to become productive with it, perhaps something is wrong with the
> language, and not the programmers?

Or maybe writing correct (i.e. safe) code is more difficult then most
programmers realize and they lack the humility to admit it.

~~~
garmaine
That’s true, but not what that quote is about.

~~~
rapsey
There are two sides to any coin. The complexity of the language is a
consequence of the complexity of the problem it is trying to solve and the
constraints it is operating under.

The borrow checker is not just some crazy torture device that exists for no
reason. Criticizing the difficulty of the borrow checker without considering
why it exists in the first place is completely misguided.

~~~
garmaine
False dichotomy -- there are always more than two sides to any issue. People
find themselves fighting with the borrow checker because their mental model of
what they're writing is not what Rust is interpreting. This is probably
indicative of two things: (1) their mental model is incorrect in some ways,
and (2) Rust's semantics _don 't_ map that well onto how we think about
systems programming problems. If satisfying the borrow checker makes you think
"whoops, that was dumb" then you're in category 1. If it makes you think
"aargh, how do I express this in a way Rust will accept?!?" then you're in
category 2. With an ideal language category 2 wouldn't exist.

~~~
AnimalMuppet
Of course, it's very easy to think you're in category 2 when you're really in
category 1 but don't see how you're wrong...

~~~
garmaine
But are all instances of category 2 actually category 1? That’s a strong
claim.

~~~
AnimalMuppet
It is, and it's a claim that I didn't make. But even if it were true, I think
people won't believe that it's true, because there will be instances where
they won't understand the borrow checker's reasoning.

~~~
garmaine
I think you can understand what the borrow checker is doing and still think it
is being too stringent.

------
exitcode00
No mention of Ada at all. Very sad and disappointing - Rust basically has a
carbon copy of all of its features. It deserves a fair shake..

~~~
okl
Agreed. Whether rust has copied its features - I don't know, but I have re-
implemented many of Ada's features for several projects in other languages
(mostly C), so it seems there is an amount of basic features like storage
pools/memory pools which are usually required for systems programming tasks.

Good for Rust then, I guess.

~~~
sargun
I tried Ada a while ago. It seems like a neat language. Maybe I’ll do a blog
post on it too, but it turned into a rabbit hole.

I think one of the problems was where can I go to ask Ada questions?

~~~
pjmlp
You could start here,

[https://www.reddit.com/r/ada/](https://www.reddit.com/r/ada/)

[https://stackoverflow.com/questions/tagged/ada](https://stackoverflow.com/questions/tagged/ada)

[http://www.ada-europe.org/auj/home](http://www.ada-europe.org/auj/home)

------
bogomipz
The author states:

>'Similarly, a Java programmer must understand the runtime behaviour of the
JVM, but until OpenJDK, the implementation language was irrelevant."

Can someone say why did the implementation language become relevant with the
arrival of OpenJDK? My java app should run on any JVM no? After all that was
the raison d'être of Java no? Or is the author referring to something else?

~~~
sargun
How do you debug the Java runtime, or when you Java program does something
other than desired?

------
kbenson
> We have the Rust Evangelism Strikeforce nudging us towards rewriting
> everything in Rust.

I really wish this would stop being repeated. At this point it's a meme that
was rarely, if ever, actually accurate. People just repeat it because they've
seen comments urging the use of Rust, and this leap is easy to make and
justifies a bit more pushback.

It's not about "rewriting", it's about _new projects_. People are starting new
projects that do the same thing as old ones _all the time_. What you actually
see is a lot of Rust advocates trying to influence those people to use Rust
instead of C or C++, so instead of yet another library implementation in C or
C++, we have one in Rust.

If it's better than the prior implementation, it might be used. This part has
nothing to do with language, and better implementations come along all the
time and are adopted to some degree. For example, Nginx. I remember the days
when your choice for an open source webserver that could scale was basically
Apache (there were a few others, but generally weren't used for serious
sites).

Misrepresenting this cycle is just spreading FUD that activates a constituency
to circle wagons. It's not helping anyone (as we're seeing from _both_ sides
of the political spectrum, which have gone all-in on this tactic lately).

~~~
pvg
_Misrepresenting this cycle is just using FUD to activate a constituency to
circle wagons. It 's not helping anyone (as we're seeing from both sides of
the political spectrum, which have gone all-in on this tactic lately)._

It's a offhand remark in a post that's not about any of this. You're going out
of your way to interpret this small thing in the worst, flame-inviting way.

~~~
kbenson
> You're going out of your way to interpret this small thing in the worst,
> flame-inviting way.

Which supposes a different way to interpret this. Feel free to provide a
different interpretation or this very short and straightforward sentence, and
I'll definitely consider it.

Also, to be clear, I'm not positing that the author _intends_ to cause the
stated effect, I'm stating that the meme does this by it's nature, and the
meme is also self-propagating by its nature and this same effect. The wording
I used (that you quote) can be interpreted assigning intent to the author,
which was not my goal, so I've changed them slightly.

(I would note the change with a note on the original, but I think these
comments are sufficient to document it).

~~~
pvg
_Feel free to provide a different interpretation_

I don't have to interpret it at all, it's not an important part of the post.
And no interpretation requires some weird political swipe.

~~~
kbenson
> it's not an important part of the post.

I feel any statement about about what a group of people are doing, especially
when it can be taken derogatorily or dismissively, should be _accurate_ , or
at least with some basis provided. It was in the article, in my eyes it's fair
game for criticism, _even if the only criticism is that I wish people would
pay attention to whether it 's true, as the criticism in this case is_.

If someone described C developers as "wild cards that think all our security
concerns are overblown" I think a lot of C developers would feel _rightly_
misrepresented.

> And no interpretation requires some weird political swipe.

I compared how the meme works to how memes in politics are working to divide,
as I think that's the most obvious parallel that is easily visible to most
people. Notice how I didn't promote one side over the other, as it's a
_common_ tactic in politics in general, but more visible at both extremes.

~~~
pvg
My point is, it's an absurd amount of verbiage and offtopic thread derailment
and hot air over some dumb joke that is basically irrelevant. You've written
some bizarre grumpy rustacean equivalent of 'this site doesn't scroll properly
on Android'.

------
samuell
> "The thing that nobody told me is that OCaml’s runtime cannot do two things
> at once. It has a Python-style GIL."

That's the reason I kick-started a crowd sourcing effort to collect a table of
such basic facts among compiled "systems" languages:

[https://docs.google.com/spreadsheets/d/1BAiJR026ih1U8HoRw__n...](https://docs.google.com/spreadsheets/d/1BAiJR026ih1U8HoRw__nzbCSFnnHicWrjxpW5l6-O3w/edit?usp=drivesdk)

(There's still a lot of gaps in there which you are welcome to help fill out)

------
dom96
We discussed this article in the Nim forum recently: [https://forum.nim-
lang.org/t/3922](https://forum.nim-lang.org/t/3922).

------
mindB
I had a brief dalliance with pony last year, though I wasn't coming at it from
a systems perspective. At the time, it was the "lowest level" programming
language I had used.

Maybe the author's perspective is just that much different from mine (he's
used to things like C++ and Rust), but "simple" is just about the last word
I'd use to describe pony. Don't get me wrong: Pony is a pleasure to work with,
and it is no more complicated than necessary for the problem it's trying to
solve, but adding the capabilities layer to the normal type system makes for a
language that has a lot going on. I'd expect that the amount of fighting
newcomers do with the capabilities system is similar to how people fight
Rust's borrow checker. Maybe the author just didn't have enough actors that
wanted to share state/communicate where it wasn't an issue for him.

In any case, I highly recommend anyone thinking about picking up a new
programming language to give pony a look, especially if problems you're trying
to solve are amenable to high levels of concurrency and need to run fast. The
pony capability system basically eliminates data race bugs (within pony), and
also guarantees against runtime crashes. It's got a bit of a learning curve,
and the package ecosystem around it isn't great yet, but it's doing unique
things to solve problems many languages aren't attempting to address.

------
dorfsmay
Rust passing by value/reference:

NOTE: The following is my understanding, from discussions on IRC and reading
articles. If I'm wrong, please, please, please correct me (and provide good
backup to what you are saying), because this is fundamental, and for me is one
of the biggest misunderstanding in Rust.

When deciding to use passing by value vs passing by reference, the only
deciding factor should be ownership. If it makes sense to give ownership, pass
by value, if it makes sense to retain ownership, pass by reference. This will
NOT affect performance, the actual implementation of copying memory around vs
reassigning which part of the program owned that piece of memory is an
implementation detail and the rust compiler will try to do the right thing.

I stopped fighting the borrow checker once I stopped treating Rust references
as if there were C pointers, using them to minimize memory copy instead of
concerning myself with ownership. I find the book does a bad job of explaining
this, I'd be happy to give a try to write a chapter about it, but need to
first confirm that my understanding is correct.

------
Apocryphon
Would Swift qualify as one?

Also wondering if the author considered D.

~~~
dvfjsdhgfv
I'm disappointed about the lack of D, too, since the author gave Nim a try.
And it's definitely more mature than, say, Pony (which is an interesting
language for other reasons). Also, you can get excellent performance in D,
really close to what you will get with C, and that's very often the crucial
factor in systems programming.

