Hacker News new | comments | ask | show | jobs | submit login
Rust can be difficult to learn and frustrating, but it's also very exciting (influxdata.com)
287 points by pauldix 3 months ago | hide | past | web | favorite | 274 comments



Rust is the answer to the question "can we have speed, correctness, and expressiveness in one language?" My company has been running Rust in production for awhile now, and it's exceeded every expectation. It's fast, it's safe, and it's so productive it's hard to find a reason to use anything else.

We've also found that the learning curve is, in our opinion, a bit overstated. We've ramped up several new grads on Rust with the O'Reilly Rust book. We see real productivity in about two weeks, which is actually faster than it was to ramp them up on our C++ code base. The compiler errors are amazing and it's almost like giving them a built in tutor.

I'm very bullish on Rust becoming the language of choice in the 2020s for everything from operating systems, web services, desktop applications, and more. It's that good.


I think the learning curve thing is depends on what's the language that you are compare it with.

C++ for example, is a hard language, but the learning curve is ... progressive (rise bit by bit).

Rust on the other hand, is like climbing a cliff: You're exposed to everything as soon as you start learning. That's all the Rust things (memory safety model and borrow etc) plus the rest of the knowledge that you need to learn when you normally learning a language (std library & stuff).

Luckily though, Rust did many thing in later years made it a little bit easier to use and learn. Like the rewritten books and manual and in my opinion most importantly few twists to the language.

My biggest (maybe nothing in the big picture) complain about Rust now is maybe it's too community driven, which can sometime cause minor fragmentation.

As a personal developer, if I've already followed every best practice writing my code, then to be honest, after the code is finished, I'm not willing to rewrite my code just to make it dated or work again (I mean, I'll pay my time to do it, but my hate meter will rise). Currently, Rust cannot fully deliver that.

I think Rust need strong leaders to layout a clear and stable plan, so more things can be standardized across it's ecosystem (Somewhat like what Go did, for example, io.Reader && io.Writer is life changing for me). In that way I can keep my hate meter at a safe level.


Traits for interop are a prime consideration for std, even if we try to keep it small. But we can only add things when they’re ready; that’s part of the stability you desire.

Look at the Future trait, as an example. And rust has had the equivalent of io.{Reader, Writer} since 1.0.


I know. But for me personally, the `io::Reader` and `io::Writer` is still not comfortable enough. Mainly because it's return values, `io::Error` to be specific. Because I found that in many of my cases, predefined `io::ErrorKind` is not enough for me, this results my abuse of `io::ErrorKind::Other`.

In Go, `error` is an interface that can later be asserted, so I can return any `error` then deal with them as late as I need.

This gives me ability to write some complex `io.Reader` and `io.Writer`. For example, an `io.Reader` that can Decode data stream, and returns both CodecError and IoError when it encountered any.

In Rust, if I want to write a similar thing, a HPACK decoder that returns both `io::Error` and `HPACK::DecodeError` for example, I need come up with another `Result` type that wraps both errors. This can sometime be tiring and makes the code inflexible (As one simple change to the `Result` may effect the entire call chain up and down).

BUT ... Maybe it's Go's fault, it treats me too well, make me want something that I cannot have for free (performance cost) else where.


> In Rust, if I want to write a similar thing, a HPACK decoder that returns both `io::Error` and `HPACK::DecodeError` for example, I need come up with another `Result` type that wraps both errors. This can sometime be tiring and makes the code inflexible (As one simple change to the `Result` may effect the entire call chain up and down).

Well there's stuff like error-chain to take care of the boilerplate...

Also, I believe you could define the equivalent of Go error in Rust as a trait and box it (ie. a trait object). It could be used much the same way as in Go with the additional benefit of Result being a sum type. I'm personally not a big fan of this approach but I guess it might work...


> you could define the equivalent of Go error in Rust as a trait and box it (ie. a trait object).

I know this basically how Go's error handling works (Put error data on heap and pass the reference), but I'm not fan of it (the put data on heap part of it) too :(

I will try out the error-chain, thank you for reminding me that.


The “failure” crate is an alternative to error-chain as well.


> I think Rust need strong leaders to layout a clear and stable plan, so more things can be standardized across it's ecosystem (Somewhat like what Go did, for example, io.Reader && io.Writer is life changing for me). In that way I can keep my hate meter at a safe level.

Just to add my opinion, not to disagree: I followed the development of Rust for several years now (starting before 1.0). Rust's approach to language evolution is very much community-driven (like you said). But this also led to many really good ideas coming from people with different backgrounds. Today, Rust feels like a highly optimized breed of good ideas taken from many programming languages and I know of no other language that feels like that. Sure, every new language gets inspiration from older languages, but Rust appears to be more "extreme" than other languages (and I do not mean "extreme" in a negative sense). This was most visible in the pre-1.0 era. People had different ideas how the language should work and the Rust team tried different things and iterated on the things they learned. And I think this was totally worthwhile.

Let's talk about Python for a moment. I really like Python. It is a language with clear conventions and idioms. And most likely it achieved this state thanks to Guido van Rossum who had very clear ideas about what the language should be. And one of the core ideas is simplicity. Python (being inspired by ABC) was meant to be easy to learn (because of it's simplicity).

Now, let's go back to Rust. Rust also has clear ideas: "Rust is a systems language pursuing the trifecta: safety, concurrency, and speed" (Quoted from: This Week in Rust). And yes, "consistency" or "ease of learning" are not listed as the core ideas. However, when you look at the Rust roadmap for 2017 you will also see that the team has prioritized the following items:

* Rust should have a lower learning curve

* productivity (which includes easier usage of the language)

These issues are definitely on the radar of the Rust team. But I also think that these issues can only be tackled by an entire community which shares and discusses ideas. Rust tries to be much more than other languages and I think it is highly unlikely that a single leader will know how to direct the language in a specific direction. There are still a lot of things to be figured out. For example, let's see if the failure crate becomes the standard for error handling in Rust.


<quote>C++ for example, is a hard language, but the learning curve is ... progressive (rise bit by bit).

Rust on the other hand, is like climbing a cliff </quote>

c++11+ is a hill that is so freaking high that you do not see the top.. like Olympus Mons.

honestly i do not see much difference in learning c++ or rust - in order to write good programs you should know most of the c++ standard and that's a lot to absorb.


Good point about the learning curve. I don't think Rust is especially difficult overall, but you need to understand a lot before you get anywhere. Haskell kind of have the same problem, where you need to understand advanced features like monads before you can even write hello world.


> C++ for example, is a hard language, but the learning curve is ... progressive (rise bit by bit).

Except that you've always got a footgun in each hand, with no safeties and no trigger guards.

Rust keeps its footguns locked in the gun safe. You get them out with the `unsafe` keyword.


> I'm very bullish on Rust becoming the language of choice in the 2020s for everything from operating systems, web services, desktop applications, and more. It's that good.

I don't mean to burst your bubble here. But people need to feel productive quickly with a language, otherwise they'll drop it and move to something else which makes them feel that way.

Looking at this thread there are plenty of examples of "I love Rust, but..." or "It's a great language once you get past...". My favorite: "There's an awesome web framework but you have to use Rust-nightly..."

Javascript is thought of as a terrible language by language snobs, and yet it has a huge following. Haskell, on the other hand, is much beloved, and doesn't. Don't get me wrong, it's got its share of love, but hasn't seen the explosive growth that python or java has.

The lesson from the early 2000's is that C++ may be a superior language to Java (I used to think that way), however people were so much more productive with Java. They didn't have to worry about memory management, segfaults, crazy C++ semantics, etc. Companies were more willing to throw hardware at a problem to reduce risk/time in development. And that is still true today.


> I don't mean to burst your bubble here.

You won't.

> But people need to feel productive quickly with a language, otherwise they'll drop it and move to something else which makes them feel that way.

This is relative. Rust is far easier to learn than C++. It has a compiler that will even enforce that you don't shoot yourself in the foot. It also has nice tooling to get you up and running quickly. It has good documentation. It has a free book. We've had no trouble getting our new grads up and running with Rust. It's not that hard.

> Javascript is thought of as a terrible language by language snobs, and yet it has a huge following.

Having a huge following doesn't make it less terrible by the measures of PL theory or sensibility. It's also the only choice on the web, but that may soon change, Rust has first class support for wasm so it's in a good spot there.

> Haskell, on the other hand, is much beloved, and doesn't. Don't get me wrong, it's got its share of love, but hasn't seen the explosive growth that python or java has.

By most accounts the Haskell ecosystem and user base are quite large considering it is intended as a research language, and the community is still growing. Rust isn't intended for research, and it's incredibly young compared to Java or Python, so it has plenty of time to catch up.

> but people were so much more productive with Java.

Hahaha. You mean people wrote a lot of Java. Let's please make the distinction between productivity and writing a bunch of enterprise crapware churned out by barrelful.

> They didn't have to worry about memory management, segfaults, crazy C++ semantics, etc.

That's exactly what Rust does for you.

> Companies were more willing to throw hardware at a problem to reduce risk/time in development. And that is still true today.

Actually companies are becoming more aware that speed is a feature, and that Moore's law isn't holding out. We're also moving to smaller form factors: phones, watches, glasses... the future is not on the desktop by any means, and no one wants to waste capacity in a datacenter needlessly.


See the thing is that I agree with most of your statements, so you're really not changing my mind with your arguments.

> Actually companies are becoming more aware that speed is a feature

No. If that were true, Python wouldn't be the fastest growing language, and we'd be hand optimizing everything in assembly and using languages that allowed us to do that (C). That was the entire point I was making. It's why Java won.

I can't figure out if Rust is serious about being a true competitor, or just merely riding the peak on the Gartner Hype Cycle [1].

[1] https://www.gartner.com/en/research/methodologies/gartner-hy...


Python is growing because it's a good scripting language, and there's a need in the ML community for a standard language to write scripts in. The ML community is growing like crazy, thus Python grows. Even though Python is secretly calling Fortran for scipy, or Tensorflow (C++), or PyTorch (also C++), all of which would make good candidates for Rust replacements. So obviously speed is necessary to enable what people are doing in Python.

I make the distinction between script and what we software engineers do, because I had the misfortune of spending half a decade in research doing ML, and those guys are not writing production programs. They're hacking out Jupyter notebooks and writing precariously balanced code that barely works.

That doesn't make Python suitable for large applications. It doesn't diminish the fact that CUDA is growing, SGX is growing, embedded is growing, that we're now unlocking 100G fiber, that we've reached the limits of single core performance, that intel is rolling out 8+ core consumer CPUs. Python is not going to shine for any of these things, but Rust will.


tl;dr: despite being relatively slow Python is a fantastic glue language. Some people thing rust is well positioned to steal Python's dinner.


To be fair, it's much more likely that Julia will be stealing Python's dinner, rather than Rust.


Django is not going to be rewritten in Julia. Neither is Linux going to be rewritten in Python. Different languages have different domains. Some of these comments seem to think all languages is competing in the same domain as if Rust is a direct competitor to Julia or JavaScript.


The context of the comment I replied to was that Python was fantastic glue code _for scientific computing_. Julia won't won't impinge on Django's usage share.


Rust will not steal Pythons dinner, they are used for completely different domains. The comment was saying that Rust might be a realistic alternative to C/C++/Fortran for modules which are not written in Python.


That's not what I said. I said Rust was a good candidate for all the things Python is using to actually do useful work. The underlying libraries written in Fortran, C, and C++.

Don't tl;dr; if you don't know how to r.


Speed matters, it’s just that it’s far from the top priority.

All else being held equal, developers and stake holders will choose the faster language, it just makes sense.

The trick is that speed is typically seen as diametrically opposed to usability, since quite a few languages achieve speed by turning all the safety rails off or existing way too close to the metal for comfort.

If rust could deliver speed without compromising on ease or safety, and I honestly don’t know if it can, then it will absolutely crush the competition.


Safety and speed are the big words on the box. Usability is harder, because it's somewhat a matter of opinion. As someone who has professionally worked with the expression based Haskell, Erlang, Elixir, and OCaml, I find Rust to extremely expressive. If you come from that camp and feel that OOP is a bad toolkit of abstraction and that higher order functions, typeclasses, type parameters, and ADTs are much more powerful, then I think yes, Rust ticks all the boxs.


> If rust could deliver speed without compromising on ease or safety, and I honestly don’t know if it can, then it will absolutely crush the competition.

It has to be more than safe and fast. It has to be a productive language to use. A dev can't sit for 6 months trying to figure out how to write a website, when he can pick up RoR and do it in a day.


That’s why I said “ease” too.


I think Rust should stop looking at C++ as the becnhmark / comparison point for complexity. The expectations that developers have from languages has increased over time, and Rust itself has contributed to raising that bar.


We don’t generally consider other languages as a measure of what complexity is “okay” or something, and are extremely aware of Rust’s complexity. Rust has a lot of requirements that directly lead to a lot of that complexity. But it’s neccesary, not incidental. Or that’s the hope, at least. Rust is also not perfect.


A lot of (but not all) complexity is solved in C/Python/Java by throwing a data structure at the problem. But is it a fair statement to say that not all data structures will work in Rust? Or is it better to say that some data structures work better in Rust than others?


Writing certain data structures in safe Rust can be hard, but not impossible. I’m not aware of any data structures that simply cannot be written in Rust.


Of course, since anything that can be written in C can be written in unsafe Rust.

Though, reading the post above yours, I was thinking more about the use of data structures than the implementation of them. In C++, when faced by the need to efficiently iterate through a data structure in different, incompatible orders, the tool of choice is often just to make intrusive linked lists with multiple next pointers per element. I think I've even once implemented something that was a priority queue (heap), two different lists and a tree at a same time.

While doing that in Rust is by no means impossible, it seems to me that the use of such a structure would be much more clumsy in Rust, to the point where I would try hard to solve the problem in some different way.

The languages are all turing-compatible anyway, so it's not about what can be done, it's about what approaches does the language make easy and promote. Overall I really like the kind of code idiomatic Rust tends to end up like.


Thanks for the thoughtful post. I do have a question, that maybe you can answer?

> The languages are all turing-compatible anyway, so it's not about what can be done, it's about what approaches does the language make easy and promote.

Turing completeness is kinda besides the point. We probably wouldn't be talking about it on HN if it wasn't. :)

I guess what I'm wondering is does Rust encourage simpler but possibly slower data structures, or are there some complex data structures which are simpler to ensure safety than other simpler ones?

In other words, does Rust encourage simplicity at the cost of speed?


As with all performance questions, the answer is “it depends.” For a look into this question, see http://dtrace.org/blogs/bmc/2018/09/28/the-relative-performa...


Hey thanks for the response.

I'm happy that rust has a good set of performant data structures, but on the other I feel like it's too soon to say Rust is the big winner here as the author does. I've been very skeptical on fantastical claims by language promoters.

But taking the pain out of making common data structures is a good start.


I think if you'll look into the author's credentials he is far from a "language promoter."


Comparing Haskell to JavaScript is silly - JavaScript is popular because it is the only option in the browser. It has noting to do with the quality of the language itself. If VBScript had won, everyone would be using that. If Netscape had decided to use Scheme or Haskell as the scripting language, this is what everyone would be using.

Rust is competing in the space of C and C++, it is not competing against Java or Python. People are not gong to write operating systems in Python because it feels more productive. For simpler desktop applications you may have a point, but heavyweights like Word or Photoshop are written in C++ and Rust may be a realistic migration. JavaScript or Python is not.


>heavyweights like Word or Photoshop are written in C++ and Rust may be a realistic migration

Especially we've gotten used to so many of C++ shortcomings that we don't see them, but someone learning both Rust and C++ will (I'm sure) have a better experience in Rust. Even just the built in tooling (Cargo test, Cargo crates, rustup, etc.) feels so much more mature than when you're in 2018 looking at how to compile some C++ without an IDE.


Text editors like vscode and atom (electron) go head to head with sublime (c++). The dominant editor now is vscode.

For Rust to win it must be adopted by Gaming or gaming engines.


If Netscape had used Haskell the WWW might never has taken off. Or att least scripting it might not.


Despite Java's growth, C remains the language of choice for operating systems and C++ for web browsers, desktop applications, games and high performance web services.

Rust is really only competing with C/C++, not JavaScript or even Java (or Go).


Some of those reasons are political, not technical.

Like C on embedded vs C++.

On Windows large majority of apps are in .NET with some C++.

On OS X and derived systems it is all about Objective-C and Swift for desktop apps. C++ is mostly used for drivers, LLVM tooling and Metal shaders.

Android is Java with some C++.

ChromeOS is all about JavaScript.

So no, C and C++ have lost the desktop, nowadays they are used for the graphics composition engine, while the remaining APIs are built on top of it with another set of languages.

If Rust is supposed to beat C and C++ on the desktop, it needs to be able to integrate into the IDE tooling alongside the mixed language tooling experience.


C is not used in the embedded space for 'political' reasons but for the fact that in contrast to C++ you have full control over what your program does and don't have to worry about when certain functions get magically called and why the size of your two-int struct is suddenly way larger than the 64 bits you expected it to be.

Sure, this is all a matter of 'using it right', but from my experience many developers in the commercial embedded space are not programmers by trade and this learning those intricacies is a real hurdle for them.


Sure it is for political reasons when even C99 is seen as too modern, and many are unwilling to let go of C89 and Assembly even if the OEM toolchain supports modern C.

And for another point of view of someone more relevant than my insignificant self,

CppCon 2016: Dan Saks “extern c: Talking to C Programmers about C++”

https://www.youtube.com/watch?v=D7Sd8A6_fYU

"Embedded Development with Dan Saks"

http://cppcast.com/2016/10/dan-saks/

Thankfully there are industry certification standards like AUTOSAR, which now require C++, so those devs can choose to keep grasping to C and switch industry or learn more modern languages.


That's relevant when you target <1$, >.15$ processors, but they are rather niche.


I'm waiting for game engines to pick up Rust.


Not sure why downvoted. A language aimed at replacing systems languages like C++, which happens to be the go-to language for game development, seems like a reasonable choice for a game engine.

There's actually a website dedicated to tracking this - http://arewegameyet.com/


Actually it is quite interesting, thanks for sharing.

I think to be on pair with C++, a Rust based engine needs to have some Unreal like tooling.

Which actually seems to be a couple of WIP on that website, so I will now get to track their progress. :)


To be competitive to C++ on the AAA world, Rust engine tooling need to be on pair with Ogre3D, Godot, Cocos2d-X, SpriteKit, Unreal, Unity, CryEngine.

So it would be interesting to see what Seed Studios will come up with.


> Despite Java's growth, C remains the language of choice for operating systems and C++ for web browsers

Does it? Existing project use what they have chosen long time ago, we can only discuss choice for new ones. And new OSes often choose something else. I am not aware of any new webbrowser, so can't say anything about that.


> But people need to feel productive quickly with a language, otherwise they'll drop it and move to something else which makes them feel that way.

Yes, I agree, but that's not the full picture. People want a language in which they can be productive quickly, but once they master it, they, or at least some of them, will then look into quality and performance. Languages like JavaScript or Python (and even Go to some extent) are popular and easy to pick up, but there's not much room for further progress. JavaScript is already stretched to its absolute limits when it comes to performance and it's still not performing very well. And when it comes to quality, well, TypeScript is a thing for a reason.

I don't believe Rust will ever be as much of a language for the masses as JS, but it has a good chance to become a niche language for those who need or want more performance and/or quality than they can get with langs like JS or Python.


> Rust is the answer to the question "can we have speed, correctness, and expressiveness in one language?"

My biggest gripe is that they left out readability.

I like the semantics of Rust, and appreciate the performance and the transparent memory model. I am extremely excited to try Rust on an embedded project.

Bur honestly, the syntax is gruesome. Coming from Python, Rust looks like two rabid gerbils had a war dance on my keyboard.


>Bur honestly, the syntax is gruesome. Coming from Python, Rust looks like two rabid gerbils had a war dance on my keyboard.

What exactly is terrible about it? The snake_case I got used to, I kind of like having braces, and that's not really a killer argument either, because most languages have them, apart from that I find Rust also much cleaner than Python syntax. I'm really not sure what you mean. Is it the lifetime annotations (because they're somewhat necessary).


Okay, tell me if this is readable to you:

   fn accumulate<'a, T: Monoid>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) -> T
   where
        T: From<&'a str> + From<String>,
this is JUST the function signature

yes, every single thing in there is necessary, it can be written in a more gruesome way, but the where clause clarifies it a bit

But let me cheat a little bit

    ( $(#[$attr:meta])* enum $enumer:ident { $($i:ident => $e:tt $( ( $($m:ident),* ) )* ; )* } ) => {
how is this macro syntax looking?


#1 I find is not worse than C++, granted there's more complexity here than in Python but in terms of cleanness its ok IMHO. Because as you said there's nothing unnecessary. Rust addresses different problems than Python, so we should compare apples with apples.

On the second one you got me though, I find the macro syntax a bit horrible. Sometimes I just want simple text substitution.


C++ templates also aren't winning any readability awards.


I'm comparing it to Haskell syntax for the same thing, which is much cleaner


Haskell does not have borrowing and lifetime specifiers though, which is what makes the Rust example more dense.


Haskell has nice syntax for generics, no stupid <> to forward declare type parameters


It is somewhat unfair to compare this to Python, since a lot of the simplicity in Python comes from the semantics (dynamically typed, garbage collected and so on). Rust need to express all this information (types, lifetimes etc.), so it will necessarily be more dense. The question is if this information could be expressed in a more readable syntax. This might be possible, but I would like to see a suggestion of how.

I guess the signature could be made more readable by using a few type aliases. The hardest part to read is the nested types.

I'm with you on the macro syntax, it is very hard to read. It is not easy to create a readable macro syntax though. All languages I know have hard-to-read macros, so this is not yet a solved problem.


Here is a simpler syntax:

   fn accumulate tuples: &[(&'a Str, &Fn(i32) -> Bool)], i: i32 -> t
   where
        t: Monoid + From &'a Str + From String,
this is how Haskell with lifetimes and borrowing would look like (if arguments were not curried)


This is arguably less readable, because it's missing some delimiters for your eyes to latch onto.

It's also not realistically parseable- the Haskell/Ocaml-like removal of <>s and ()s relies on application being left-associative, and if you read this under that rule you've changed the meaning (e.g. `From &'a Str`).


I like removing superfluous punctuation, but if parentheses are removed from method signatures than they should also be removed from invocations, which in turn comes with its own set of readability issues. I'm not a fan of the $ operator in Haskell, for example.


This also reminds me that, in Python 2.x, the following code...

for i in range(100000000):

...creates in memory a list with one-hundred million integers.

Expressive yes, but sometimes it can be double-edged for new comers (and not new comers).


As someone with a C++ background who loves Rust and wants it to succeed: Code where the lifetime syntax is used much can look really horrible and confusing, and to people new to Rust it might feel like it's for no reason.


Well... compared to Python is kind of an apples to oranges comparison. Compared to Java or C++ I find it to be incredibly direct and expressive. Rust definitely doesn't stop you from writing spaghetti, but no language does.


I don't think the potential for spaghetti code is the problem, I think it's more the terseness of Rust code that makes it hard to read (speaking as someone who doesn't know Rust very well, but has a mild interest in learning it). I agree with the above complaint - it does feel a bit terse and that makes it harder to read IMO.

Languages like Java are more verbose which does make it a bit more frustrating to write but on the flip side I find them easier to read.


That's in part due to the compiler not yet being the best in type inference, and should get better (as far as explicit type signatures are required).


Python is pretty to look at, but I hate working in white space sensitive languages. If I have to have another argument about tabs vs. spaces I am going to toss my monitor out the frickin’ window.

Also, it makes autoindent in Emacs worse.


Well, tabs versus spaces is not a Python thing, that will bite you in any language eventually. Blame the VT-100 terminal.

Here is the thing about indentation versus curly-braces-and-semi-colons: It boggles me that people find it acceptable to use one mechanism to communicate block structure to the compiler, and a completely different mechanism to communicate block structure to humans, and have no way to automatically check that they have the same semantics. This is a frequent source of bugs, and is entirely preventable. When it comes to the ergonomics of computer-convenient versus human-convenient, humans should win. Therefore, significant white space is clearly preferable simply from the standpoint of eliminating the source of an entire class of bugs.

But the main thing that makes Rust harder to read is all the punctuation noise and short, cryptic keywords. While one friend once said: "A good programmer can write FORTRAN in any language.", I don't feel compelled to help them.

Readability matters.


> It boggles me that people find it acceptable to use one mechanism to communicate block structure to the compiler, and a completely different mechanism to communicate block structure to humans, and have no way to automatically check that they have the same semantics. This is a frequent source of bugs, and is entirely preventable.

Strongly agree. The solution that Rust, Go and other new languages have adopted is shipping a formatting tool to consistently make the semantics of indentation and braces match. I personally can't help but think that this is a worse-is-better solution when compared to significant whitespace, but at least it works. Every Rust CI I am setting up will fail the build if `rustfmt --write-mode=diff` feels like you didn't run rustfmt before committing.

> But the main thing that makes Rust harder to read is all the punctuation noise

Given the decision to favor explicit casts, references and dereferences over implicit ones, this cannot really be helped. In some ways, once you get used to it, it helps readability, because it always communicates what the things being worked on are.

> and short, cryptic keywords.

I agree that this was probably a mistake. Cannot really be helped now, though.

Overall, I think the readability argument against Rust is overstated. Sure, when you are starting out it looks like line noise, especially if compared to python. But it didn't take me more than a week or two before it basically became entirely clear and readable. The radical explicitness of the language helps readability in many ways that make it much better than C++.

Of course, much better than C++ is a low bar to pass.


I think Go shipping a single canonical formatting tool was an inspired decision that eliminates a massive point of contention in software teams. I expect the majority of new languages to ship a canonical format tool in the future.


GCC will now warn about (some cases of) misleading indentation, which is a step forward. And clang format can autoformat based on the brackets, I believe.

I still prefer whitespace to indicate blocks though.


PEP-8 (more than 15 years old) recommend spaces, so unless you are deliberately looking for a fight, the question is settled.

Autoindent is a solution to a problem that doesn't exist in Python in the first place. Having two independent representations for blocks, one for human readers (indent) and one for compilers (braces), leads to nasty bugs when they get out of sync. Autoindent is a tool to keep them in sync. In Python there is a single representation, so nothing can get out of sync.


But the tooling for editing the code has no support for indenting blocks as trivially as adding braces. Sure, you just run clang-format or such on the block/file, and get all the visual stuff sorted out.


What editor does not support indenting a block? In most editors I know you select the block and hit tab, or shift-tab to outdent.


The difference is that I can add braces in the middle of multiple lines, just need to get my changes to match up, and then I can tell it to reformat the changed section/the whole file. For block indenting, I have to select each block I want to operate on before issuing the block indent command. Braces let me skip the selecting, requiring the same cursor movement but allowing batch insertion of selection begin/end markers, in a sense.


Or reformat the entire file according to global formatting styles, like IntelliJ.


Wait, let me get under your window...

> If I have to have another argument about tabs vs. spaces I am going to toss my monitor out the frickin’ window.

Clearly the correct answer is spaces. /s

Seriously though, I like python because not only is it pretty, it's also concise. While it's not perfect, a lot of time has been spent on language features to make them easily comprehendable.

The lesson for me from python is that UX is important, even in programming languages.


>Python is pretty to look at

Python is ugly and inconsistent as hell due to lack of methods (no maps or reduce in collections for example), indentation, lack of expressions (nearly everything is a statement) and one statement lambdas.

Though rust is beyond good and evil indeed, I really don't get this obsession with brackets and C-like abominations like &*staff. Ada or SML are doing a much better job.


> I hate working in white space sensitive languages.

I think it's funny how people still have issues with this in 2018.


There is no such thing as white space insensitive language.


Fortran IV came close. You could put spaces in the middle of identifiers, keywords, and numbers, and the compiler ignored them. The language did not require spaces as separators anywhere. Spaces were only significant in Hollerith constants (what we'd call string literals today) and in columns 1-6. Columns 1-6 were reserved for line numbers, comment signifiers, and continuation marks.


Indeed, the classic resulting bug was the do loop with a typo. Instead of comma the program had a period. So this

   DO I = 1.100
was interpreted as assignment

   DOI = 1.1

Though contrary to urban legend it did not result in the loss of any rockets.

   http://catless.ncl.ac.uk/Risks/9.54.html#subj1


Aside from strings, isn’t C white space insensitive?


    intmain()
    {
        r etu rn0;
    }


The tokenizer is. `ab` is different from `a b`.


I had a play with rust at the start of the year while I was evaluating if it would be good for the api backend for my new website. I was using rocket as a framework. The language itself seemed quite ready for use and the book was very helpful but I found all the libraries I needed were half finished and didn't have the features I needed or if they did they had docs that assume you will read the source code and work most of it out yourself. I spent ages trying to work out how to set up postgres with it and got stuck on stuff about connection pools and multithreading.

I ended up just using rails in api mode which is a shame because it chews up the limited memory on my server.

Most of these issues would go away if I was a rust pro and I could just write my own libraries and read the source but it really didn't feel like rust was helping me become productive fast like ruby did.


Ruby is also a dynamically type, interpreted language with a GIL, that's much older than Rust. You're sacrificing a lot in terms of speed and correctness up front to get something that's easier to jump into.

Rust crates should have documentation though. Rust has great tooling around writing docs in comments and generating the documentation from those. Rust is also statically typed, which makes it easier to reason about what a function does without the docs. In fact, lifetimes give you even more information about the relationship between inputs and outputs than a normal statically typed language.


I have never felt a typed language slows me down. In a dynamic language you still have to mentally understand what the type of a function is. You can't just throw any data in to it and have it work.


> In a dynamic language you still have to mentally understand what the type of a function is. You can't just throw any data in to it and have it work.

JavaScript would like a word with you.


If you could just throw any data into JavaScript functions and have it work, we wouldn't need TypeScript.


The poster is poking fun of the fact that you can partially apply or over apply a JavaScript function and it will still run.


One often doesn’t need TypeScript. TS solves some classes of problems that would otherwise become crippling in projects of certain sizes and of certain levels of complexity, but, by design, JavaScript tends to happily let you throw any data into functions and have it work (by some definition of “work”).


If you define work as not throwing an error. You can't just put anything in to a function and have it return a useful result. Thats why typed language programs like haskell programs often define datatypes that are just an Int because user_id is not the same kind of data as product_id even if they are just an int.


Are you?

Every app I've ever written that talks to postgres spends way more time...waiting on postgres than doing anything else.

It's like the joke about getting a faster processor so you're 99% idle instead of 95% idle.


I always found it easier to improve the time waiting for postgres by tuning critical queries than to track down runaway memory usage and tune garbage collection. I also felt like I spent a lot of my wall clock time during active development waiting for apps to start up and run tests or whatever. There are best practices which speak to most of this, but they were hard won.


But that doesn't come for free with Rust. You still have optimize the DB. And then does it really matter which language you use, since the DB is still going consume most of the time generating a web page anyway, right?


My point was that I found the database to be the easier bottleneck to optimize. The other bottlenecks I mentioned, which I found more difficult to optimize - memory usage, GC, and startup time - are things for which Rust has a good story.


You should really be memcaching the database aggressively. I got it to the point that PHP was taking more time than the database for most pages because most pages DON'T need to be updated that frequently.


Seems like Elixir + Phoenix would be a better alternative over rails for you


Maybe. I also tried Haskell and Yesod but had the same issues. It seems the size of the userbase for a language/framework massively impacts how fast I can do things. With haskell I was posting multiple questions on stack overflow every day but with ruby I find almost everything I need already answered.


I imagine the learning curve is a lot more manageable when you have an office full of full time Rust developers. If you’re on your own you become painfully aware of how often you need to solicit help, and the time it takes to familiarize someone else with your problem over chat or forum post really eats away at one’s motivation.


Well the Rust community is super welcoming, and the meetups have been really positive. They even have the #rust-beginners channel. :)

I find Rust to be fairly easy to reason about. The compiler has awesome messages, and even links you to your error type with more information. I also HIGHLY recommend reading the O'Reilly book AND the official Rust book (the free one) if you feel like you're "just not getting it".

Rust is a language that rewards understanding, and stops you from making mistakes when you don't know how things are actually working. This is a revolutionary plus. At the end of the day, Rust's rules are what other languages enforce through convention and the school of hard knocks.

After all, is that not the point of computing? To have the computer check things for you that a human is prone to error on?


> Well the Rust community is super welcoming, and the meetups have been really positive.

For sure. The Rust community takes the cake when it comes to owning criticism, wanting to make things better (as opposed to excusing issues), and self-organizing to affect change (e.g., the working groups). I like Go and its community is well above average, but it stands to learn from Rust's community IMHO.

> the meetups have been really positive. They even have the #rust-beginners channel. :)

I know, but a slack/irc/email/etc channel is a really poor substitute for having humans in a room who already have context about the problem you're trying to solve.

> I find Rust to be fairly easy to reason about. The compiler has awesome messages, and even links you to your error type with more information. I also HIGHLY recommend reading the O'Reilly book AND the official Rust book (the free one) if you feel like you're "just not getting it".

Hard to make heads or tails of this without knowing what you're comparing it to. I do agree that Rust does a fantastic job (via its error messages, documentation, books, etc) at addressing the hard problem of dealing with a compiler that pedantically enforces not-very-intuitive invariants, and I respect Rust for believing that those invariants are worth the trouble. I think they _are_ for lots of applications, but I think Rust needs to do quite a lot on the learnability/intuitability front before the economics justify using Rust for general purpose application development. For the time being, for most applications, it's just so much _cheaper_ to use something like Go in the general case.


> "can we have speed, correctness, and expressiveness in one language?"

Didn't ocaml already answer that question? Since ocaml hasn't dominated, it seems something more is required... What has rust got beyond that?


> OCaml bytecode and native code programs can be written in a multithreaded style, with preemptive context switching. However, because the garbage collector of the INRIA OCaml system (which is the only currently available full implementation of the language) is not designed for concurrency, symmetric multiprocessing is unsupported.

--https://en.wikipedia.org/wiki/OCaml

Rust has memory-safe concurrency without a GC.


Threads and predictable runtime model. (No GC)


Rust does not have predictable allocations, till it would have custom allocators. Malloc is not better than GC.


You're moving goal posts so far I don't even understand what your point is. Malloc vs GC doesn't matter at all because you can decide to not use it if you don't want to in Rust, C, C++. The vast majority of performance sensitive code avoids dynamic allocation of memory at all costs by either preallocating a large chunk of memory upfront and reusing it or by only using the stack. When no allocations are performed in a time critical section of code it is not affected by other threads making allocations. This is what a predictable runtime model is.

Programming languages like javascript or python always dynamically allocate every single object. When the GC does it's job it has to stop all threads and therefore will stop your time critical code even if you avoid allocating inside it. This is what is commonly understood as an unpredictable runtime model.

What does predictable allocations even mean? Allocation is always predictable, it will happen when you use "new" (Java), "Box::new"(Rust), malloc, etc. The unpredictable aspect is the stop the world pause caused by garbage collection. Your complaint regarding custom allocators doesn't make sense because arena allocators [0] and probably others are available in rust.

[0] https://doc.rust-lang.org/1.1.0/arena/index.html


>The unpredictable aspect is the stop the world pause caused by garbage collection.

As well as malloc pauses on deallocation. The only way of using your memory in realtime apps is preallocation, which often can be done in languages with GC too, it would be just very inconvenient.

At the moment custom allocation support in rust is a joke if you compare it with Ada or C++, and Box is not better than GC in this regard.

>Unstable

Besides it's very inconvenient to use. Does Box/Rc/Arc support this arena allocator, as C++'s smart_pointers do?


Threads are an implementation technique, not a user requirement (at least they shouldn't be).


C++ itself is not just overly complicated. However, in addition to that, C++ promotes object orientation. Design patterns add an additional layer of complexity for new grads to plow through.


A shallow learning curve and cute compiler messages are the least of your problems when doing C++-caliber software.

The 'small, easy language for ignorant developers' niche certainly exists, but it's already taken by Go.

Rust currently provides no benefit over (modern) C++ for the problems where using Rust or C++ makes sense. (Though perhaps Rust will make it easier for layman developers to learn Rust and then transition to C++.)


I... what? Rust is hardly targeting "small, easy language for ignorant developers," and putting it in that camp because it has nice error messages is unreasonable.

I'm even more perplexed by "Rust currently provides no benefit over (modern) C++."

* Rust's "pthreads and mutexes" wrappers prevent data races at compile time, and there's Rayon to compete with things like OpenMP.

* Rust's moves are destructive, guaranteed nothrow, and also checked at compile time.

* Rust's borrow checker is light years ahead of C++'s.

* Rust's type system lends itself to far simpler generic code, with trait-based generics and sum types instead of concepts and std::variant.

* Rust's iterators are much better than C++'s, to the point that Ranges is one of the most highly-anticipated additions to C++.

All of these are things C++ is actively trying to improve, so clearly at least the committee agrees they're worthwhile features.


Interesting! I don’t know how modern C++ deals with multi threading and shared memory etc.? Care to fill us in on the state of the art and how it’s as good as rust?


State of the art is pthreads and mutexes. The C++ and Rust wrappers for them are roughly equivalent.

Rust has some nice features for handling ownership semantics, but they are not significantly better than those in C++.

Meanwhile, Rust still lacks a normal exception handling story. Exception handling is absolutely necessary in 2018 for building real software systems.

(And even though Rust claims that errors are nicely dichotomized into "recoverable" and "not recoverable" camps, this is simply not true in the real world. There are obvious counterexamples that don't fit into this dichotomy.)


Haven't spent that much time with rust, but so far Result<> has sufficed for all my exception-needs; it's not clear to me what the practical difference is between exceptions and result<>, that would be relevant to implementing real software systems?

As I understand it, the primary usage of both is to report, and handle, errors. Rust splits it as panic! and Result<>, where panic! is naturally left for logic errors (ie states the program should never reach, regardless of circumstance; maintaining invariants), and Result<> is for everything else.

Exceptions do the same, but you can catch the broken-invariant case as well? I'm not sure how often you want to recover from such a state though.

Another aspect is retrieving the stack-trace, which iirc doesn’t exist in a normal result-type, but error-chain! magically handles it for my case (never looked into how, or at what cost)

Otherwise, the other major difference is that rust enforces that you explicitly handle all result types, making it part of the API contract, while most languages, with unchecked exceptions, leave it as a new runtime error to be found after updating your libraries. Java gives you checked exceptions, but in a much more syntax-unpleasant fashion (but thats always the case with java).

As far as I'm aware, Result<> seems to me a much cleaner solution than exceptions for the same use-case. A bit of concern for API updating, since the errors are part of the API so its more difficult, but at the same time, I'd rather update the library and fix the codebase, than update and wonder if a new Exception exists (or perhaps, always existed? Is there any way to find out the list of possible exceptions in C++, without reading the function, and all the code it depends on?).

The primary unpleasantness is that a single use of Result<> infects the entire callgraph until its handled, but thats true with exceptions as well. I'm not too happy about async/await for the same reason

Of course, part of the reason I'm interested in using rust as my hobby-language is because I'm absolutely sick of runtime errors and writing worthless tests in python, so maybe there's an appeal thats missing for me


> I'm not sure how often you want to recover from such a state though.

Pretty much always in real systems software.

Imagine a multithreaded server that handles HTTP requests. A catastrophic invariant failure when handling one requests shouldn't bring down the whole server.

Or imagine an application that calls into a money transaction routine. (This routine can itself call other routines, and so on for 12 stack frames deep.) A catastrophic failure in sending money shouldn't bring down the whole app, it should show a clean "money transfer failed, please try again" message.


When I'm talking about invariants, I mean something much more fundamental than a web-request failing. It's not a necessarily invalid state (and I'm not sure ever should be for any well-behaved program). It would be invalid if you've explicitly decided not to handle the scenario, but at least in Rust (and assuming the function properly returns Result<>), you can't forget to not handle it.

Essentially where you'd have asserts() in C. eg Your in-place sort function is meant to maintain a sorted list for all elements traversed so far: you add a panic check to guarantee this. It fails; the invariant is broken, and there's no recovering from such a state (your sort is not sorting! you're going to add a handler for this..?).

A web-request failing is a simple, normal, expected failure (hence the Result<> type). Adding 1+1 and getting 3 is a broken invariant, and there's no coming back from it. Again, you can (probably) catch it in Java since it throws exceptions on anything and everything... but why would you want to? If you take its to its conclusion, you're not trusting any aspect of the language anymore: you'll have to check every bit of code for arbitrary outcomes.

It seems to me similar to javascript allowing you to basically pass in anything to everything and get ...some... output, but its an extremely bug-prone methodology.

panic! is, afaik, intended for those situations where it should bring down the whole application (before you start adding $3 to person A, but subtracting $2 from person B); primarily to catch programmer errors, not execution errors. Errors that can be recovered from are Result<>, and the Result<> type forces you to handle all possible outcomes (which the caller might decide is a panic!). A failed web-request is most certainly a Result<> in this model, not a panic!.


That's why you would return a Result from all those and handle any failures that way. The Result type is meant to be used any time an operation could fail.


Do you use only the O'Reilly book? Or do some grads go and buy a few others?


We buy the book for them because we feel it's the best text out there, and they can get the 'Rust Book' for free on Rust's website, so that's two resources for them, plus being able to ask our already ramped up engineers questions.


The failures of Rust are the same failures of C++. Leaky abstractions making it impossible to separate representation details, making the abstraction consume a disproportionate mental load.

Given that Rust doesn't actually solve any of the actual problems C++ programmers have, there is no motivation to switch.


Actual problems like:

- sending dangling references to thread functions. Lambdas with automatic reference capture creating threads from inside functions that exit are terrible here.

- returning a pointer or reference to an invalidated iterator

- returning a pointer or reference to the contents of a temporary

Yes indeed, C++ programmers never actually have these problems, they are purely imaginary. /sarc


Yeah, I don't think there is a professional C++ developer who has any of these problems. It's called static analysis... welcome to a decade ago. Why on earth would an organisation move their codebase to Rust when they can just run Clang? Which they should be doing anyway.....


Unfortunately a lot of browser's CVEs tell a different story.

> Why on earth would an organisation move their codebase to Rust when they can just run Clang? Well, you can ask C++ professional at Mozilla.


In my experience, even modern C++ code and cutting-edge static analyzers still have a lot more holes than Rust when it comes to borrowing and lifetimes. Unsound code like this (which in Rust is the most basic form of lifetime error) still manages to slip past the CppCoreGuidelines static analyzer that Microsoft has been developing for years, which includes "lifetime checking":

    #include <iostream>
    #include <string>
    #include <string_view>

    int main() {
      std::string s = "Hellooooooooooooooo ";
      std::string_view sv = s + "World\n";
      std::cout << sv;
    }
C++ types simply don't contain the information needed to do Rust-style lifetime analysis. C++ static analyzers have to hard-code this knowledge themselves about every library type (will never be complete for every library in existence), use heuristics (will always have some false positives and false negatives), or rely on whole-program analysis of function bodies rather than signatures/types (runs into incomputability problems, and validity ends up depending on things the analyzer can't know, like which version of a dynamic librariy ends up linked at run time).


Rust is based on ADTs, typeclasses, and type parameters. C++s toolkit for abstraction is templates and OOP. They're completely different, and it sounds like you're just trolling anyway.


C++ has ADTs from C++17 and will have typeclasses from C++20. Templates with type traits are effectively a superclass of type parameters anyway.


C++'s ADTs are std::variant, which is horrific.

C++'s type classes are concepts, which are hardly more than syntactic sugar over SFINAE.

Neither can really compare to Rust's enums or traits.


Templates generate bad error messages because they are duck-typed. Rust is better at this.


I've enjoyed learning Rust, but I'm at the stage where I'm hitting constant stumbling blocks because of the slightly niche nature of what I'm doing.

It's the ugly side of Rust; when you're stuck with a series of problems that you can't solve (or take too long to solve), when there aren't enough people in the community to help you, and you end up being unproductive for a while.

Where I've seen small projects to their completion, Rust has been greatly rewarding to me. It's the projects that are bigger and more ambitious where I'm struggling.

> After reading the first 10 chapters of Programming Rust, I was able to push through the rest of the implementation. I still have open questions, and I’m not sure if the structure I used makes the most sense.

There's some chapters of TRPL and other resources that I've re-read a few times by now. Learning the language ends up being quite a lot of an academic exercise, but the benefit's that once a concept clicks, it paves way for many other concepts.

My only advice to less experienced programmers (whom you're not) learning Rust: Stay away from writing or rewriting time-critical applications in Rust if you can't tolerate being stuck on a problem or series thereof for weeks.


It depends how you approach learning Rust. If you expect learning curve as going from Java to C#, you are going to be disappointed. If you expect learning curve like going from Java to Haskell, it will be more in-line with expectations.

My point is that we very much align out expectations for the dominant paradigm and we got surprized when we have to actually "learn", i.e. internalize some different logic.

BTW, I started feel comfortable with Rust/Tokio/futures/etc. in less than a month. But I come from Scala/C++/logic and type theory background, that I guess is not so common.


Usually someone will help you out on irc or on the rust subreddit, but I think your point may still stand.


It depends, my biggest struggle right now is with the tokio/futures ecosystem, so I'm on gitter::tokio quite a bit, and have posted once on /r/rust.

With patience, I eventually solve many problems, but the lead-time is costly. Plus when I'm doing something wrong in my code, rustc could take over 5 minutes compiling, and then come back complaining. Even when I find someone willing to help me debug, the process takes a few hours, and I end up feeling bad for wasting someone's time.


I think the tokio/async ecosystem just isn't ready for prime time. Hopefully this (and compile times!) get much better.


The issue isn't exactly that it's not ready for prime time, but that it's not ergonomic at the moment. The biggest issue that you have to get used to is that pretty much everything has to be owned data, and no references passed around when constructing Future types. This can feel like it comes into conflict with the poll(&mut self) interface (in 0.1).

Also, I found truly understanding the fact that returning data from functions either must be sized or boxed, no references. Again, the &mut self can come into conflict here. But there are simple tricks for dealing with it, like using inner enums for iterating through a state machine of the future, and using Option where you can take() the value when ready.

You'll see these patterns if you look at the Future library and Tokio impls of many of the core types. So I encourage you to generate docs with `cargo doc` and then click the `src` link on any types you want to understand better. The thing I wish I had internalized more earlier (and have been cleaning up a lot lately), is that "Futures should do no work unless polled". This is easy to mess up and regret later as you might accidentally start a Timer or initiate a connection before polling the Future.

Anyway, hopefully people help out when you ask, though everyone's often busy :)


One of the challenges I'm having now is with some library that connects to a steaming pubsub server. I found a problem with the library, my use-case differs from what's being tested, and because I'm struggling to use the library the way the author suggests; I'm unable to convince them that being unable to Clone their data structure is causing a problem.

I unfortunately am not at the point of "X didn't work, so I wrote Y" as that's how we end up with competing libraries.


Sometimes there are good reasons for not cloning, such as underlying resources that can’t be cloned. But I agreed it can be ergonomically easier in many cases. If they truly don’t want it, and you really don’t want to fork, can rewrapping it in an Arc<T> or Arc<Mutex<T>> get you around the problem?


Wait, if I do (in any language)

  foo = createFuture(1)
  bar = createFuture(2)
  foo.poll()
  bar.poll()
I would expect them to start doing work before polled, otherwise there'd be no concurrency. Do I undsrstand you correctly about polling?


You didn’t say what you understood, but nothing would happen until poll is called in Rust. And calling poll would only result in one churn of the event loop. You don’t call poll yourself, you put the future onto an event loop and it calls poll for you.


While compile times can be slow, the rust system is checking so much for you, so that you can have a predictable @scale runtime. What was the issue with tokio? Plus, with async/await Futures coming in soon, already on nightly right, this should become good if not already? Rust went down the Kotlin route of not including coroutines/async/await initially and allowed Lib devs to build, but now have included as we all know. But anyways, keep at it, I have found Rust to be very helpful, using it at the startup I am at, and will keep using it deeper and in more complex scenarios.


Rust is checking a lot, but type checking is not the slow part! (I can usually run cargo check within a couple of seconds max). Rusts LLVM IR output, LLVM, and linking seem to be the main culprits. And I'm hopeful that these can be greatly improved :)


Oof, I got burned by the tokio/futures ecosystem too. It's definitely a frustrating experience. Thank god it was only a pet project with no deadline pressure, cause it's been 6months now and I'm still waiting for stabilization.


I spent two years of my professional career with Rust doing async web services and most of it with tokio/futurrs. First you finally get comfortable with Rust and then you do the learning again with futures... I did it. It paid off. Wrote some fast and stable services with it and it is not that hard when you get to the other side.

But for newcomers, be careful with references when using futures and be smart how you use the combinators. The errors can be tough and this is the only place in Rust ecosystem where they don't really help at all sometimes.


I eventually got something working, and it was stupid stupid fast, but it definitely took a lot longer to write than I would've liked.

Just waiting for the features and APIs to finalize and async/await for the ergonomics improvements. I believe in it's potential, but I'm in no hurry to use it again in it's current state.


Didn't mean though I think the current situation is that bad. What you get already is a type safe way to build async programs where the runtime is separated from the logic. I remember switching from a single threaded event loop into a work-stealing threadpool by just changing one line of code. It's very explicit and nice.


Which stabilization?


async/await is the big one :)


I guessed, it’s huge for sure :) since everything does work on stable, I wasn’t sure if there was something else I was missing, or if you meant the libraries, which still have some churn to go.

I can’t wait myself.


Great job in pushing through though. Where have you been posting for help, I am no ways an expert, and have been learning Rust, but all I have heard is the welcoming nature of the community, and would love to at-least try and help. Its a great language, but yes, a stabilizing and emerging ecosystem. But this is the way it will mature; implement tasks that push the language and hopefully come out with good solutions. The Go ecosystem evolved in this manner as-well, and others as well.


I have been learning Rust on and off this year. I have been writing mostly GO for the past few years, but am moving to coding almost primarily in Rust for any new project, and porting over some older ones. Microservices, Data Layer, etc... Honestly, while not perfect, its one of the most beautiful languages I have ever come across. Plus, I have not enjoyed coding in a language this much in a while.


How does your team (E.g., the people on the hook for reviewing/supporting/contributing to your project) feel about the change?

This is a big difference when moving from Go. A language that nobody calls beautiful, but is very easy for a team to contribute to and support (relative to other languages).


I don't think that's fair. I'm not entirely sure what beautiful means for a programming language, but I've seen many examples of Go programs which exhibited a beautiful simplicity. This project for example: https://github.com/inconshreveable/slt.


I think it’s different kinds of beauty. When I write Go, my good programs are “beautiful” for how simple they are; it’s relatively difficult to over-abstract. It’s the rugged practicality.

The other kind of beauty is a quest for an abstraction that makes everything conceptually simple—once you understand the abstraction. It’s more of a mathematical elegance thing, and it’s just gravy if it happens to solve a real world problem.


I didn’t mean to knock Go. It’s just that when I ask people what they love about it, nobody usually expresses a “feeling” they have when they use it.


Yes I agree. Beauty is highly subjective when it comes to programming languages. Its definitely an expression of a feeling from use and relative successes/failures.

I know people I highly respect that call C# with Linq & its lambda implementation very beautiful, and I can see why, but I have not a strong opinion one way or another on it.

I had a lot fun when initially learning Rust, and the way I have phased it in to the projects (work & home) that I have been doing has led to successes, which definitely increases my bias towards the fact rust is awesome =).


Like I said, we are using it for new code bases, and not moving all of our existing Go Code, thats doing fine. I agree that GO is very easy, I can get most any dev up and running and comfortable on Go in about a week. Honestly though, I can get a decent dev going on Rust in a week. Even with Go, if I was teaching a NodeJS dev, I would get them going on everything but goroutines & channels, and then ease them into it. With Rust, I feel to a Go dev, the syntax isnt too foreign. Plus, focus on understanding ownership & borrowing with real examples relevant to the team, then have them focus on core language features, and then branch out, how you would do with any language. We see a noticeable uptick in performance, and Rust has been well received. Yes Go's ecosystem now is well established, but when trying to do Location intelligence software back in 2014/2015 with Go was a pain from memory. I am not bashing GO, been a gopher for a while, but I do love Rust, and IMHO is not too complex. It just makes sense.


One more final point while I was thinking. I am a fan of both languages, Go & Rust. Go is in-fact still my recommended languages for teams, and until Rust hits a maturity level that wont change, but I am a big fan fo what rust is trying to become, I am using it for new code because of the problem fit, and I believe both ecosystems can co-exist. Go is also introducing some nice long awaited features (hopefully) in a decent way.


One more point here, I wouldnt have done it if I did not get full support & enthusiasm from my team. But I guess sometimes it helps when you dont have HUGE existing code bases to have to justify to port. =)


All good points thanks for the response.


Rust is one of those languages that I just can't see myself ever working with (I mostly do web dev), but it's a language I am really glad I learned and has made me a better overall developer.


I kinda felt similarly until I found one of my existing web services wasn't quite fast enough (currently serving around 1000req/s at peak). I could either go for a third rewrite in yet another framework hoping to increase performance by maybe 30%, or I could try something entirely new.

First attempt with rust more than doubled performance of the existing system on the same hardware. Now I feel a need to learn more.


What are you serving? Some of the Rust frameworks for backend should be able to do more than 1000req/s, but it depends what you're doing.


The system's peak _usage_ is 60kreq/min (avg 1k/s), the Python code it's written in can handle maybe 850/s per instance at 100% CPU.

Rust is fine, rust is managing almost 2k/s on the same hardware. And this is when I know practically nothing about Rust, I expect I'm likely able to do better given time.

It's acting as a simple filter and cache over JSON data on Postgres.


I’m shocked that Rust only gave you a 2X improvement over Python (I’ve rewritten a handful of Python services to Go and typically see 100-1000X improvement). What is the bottleneck? Was scaling horizontally an option?


I suspect the reason it's not faster is one of the following:

  1. backend DB at its query limit
  2. this is basically my first rust program and I've done something stupid
  3. ab/wrk aren't scaling properly either (I know, not likely, but worth considering) when I'm testing it
  4. bandwidth/IO limits on the AWS instance types I'm running this on
There are other possibilities too I guess. I was mostly doing this as a means to learn Rust though, I'd only go live with it once I had decent tests and everything else.


What web framework are you using?

Are you using a database? If so, which one? Are you using a cache like Redis?

I agree that a 2x speedup is a terribly low for a Python to Rust rewrite and shows that Python is unlikely to be the relevant bottleneck here.


actix/r2d2 on the Rust side (I haven't worked out bb8 yet), aiohttp/uvloop/asyncpg/gunicorn on the Python side (Postgres for the DB). This kinda _is_ the cache at present, it's a distillation of a lot of other data into a given form. Rust's async story re: databases still looks a little up-in-the-air right now from an outside perspective though, so I guess I'll wait and see how it pans out.

It's definitely a work in progress and I didn't expect this much interest in my offhand "I tried Rust even though I couldn't see myself using it for real, but..." comment.


> What web framework are you using?

I can't imagine the web framework is the bottleneck...


It might be because if it's a tokio-core based one OP might be blocking the event loop too much.


Interestingly, I was able to get an amazing speed improvement without going completely to Rust.

I didn't want to port APM code as well, so I kept node.js/express for routing. Very simple middleware that immediately passed the request and body buffer to Rust for handling. Rust returned a buffer back to express for sending the response.

It's easily able to hit 100k RPM on a single instance before hitting a CPU bottleneck in the Rust code (validating an RSA signature). It only needs to handle 90k RPM total.


Any reason you didn't scale up horizontally with more python instances?


We have seen production users choose to make this port to save on server costs. You can always scale horizontally, but it comes with a price tag.


Also complexity - managing an order of magnitude more instances is more hassle.


But "more hassle" by an order of magnitude that gradualy reduces when growing the number of instances.


But the cost keeps growing, especially when you need to go from 50 servers to 100


The OP only doubled their performance by rewriting in Rust though...


And depending on the amount of code, that's an awesome trade-off if OP can just have one instance instead of managing a cluster.

From what OP has said, there's probably a good change they can get more performance with some optimization.


You still need redundancy, so you’re operating multiple instances either way (or you’re playing fast and loose).


I have multiple instances to keep the latency down overall (and for security should we lose an availability zone or whatever else). But, as others have mentioned, instances cost, I'd like to be able to reduce that to the minimum if possible.


Yeah, if I was still doing primarily web applications, particularly version 1 apps where you don't know what the final product will actually be, I would probably still be using Rails for that. It's just insanely fast for creating those apps and once you've found the features that are hits that need to scale, you can pull those pieces out into services written in languages like Rust or Go. But since I mostly do lower level stuff now, Rust is looking very compelling.


you may want to have a look at Rocket https://rocket.rs/, you won't be disappointed


Rocket requires the nightly Rust compiler, which isn't something I find acceptable for production applications, and it's synchronous, so it's really slow. I have been rather disappointed by what I perceive as the author's unwillingness to work towards stable Rust. They have a GitHub issue where they track all of their dependencies on nightly, and kind of just say they aren't going to do anything about it -- it's up to the Rust core team to just make all the things stable that Rocket is using, or else it will stay on nightly forever.

Rocket's biggest feature is their flashy website, in my opinion. Their website is really nice looking and the self-assured marketing is convincing to readers.

Actix-Web seems like a more mature framework (I don't expect my application to randomly break), it's asynchronous (so it's really fast) and it works on stable Rust. Warp and Tower Web look like promising async frameworks, but they're not very mature yet. Rouille is a pretty stable option for a simple, synchronous web framework.


It's not that he's unwilling to make it run on stable, it's that he has to sacrifice ergonomics to make it run on stable. Despite it not being async, yet, Rocket is my go-to because it has the best ergonomics. Something like actix-web may be more performant, but it's ergonomics are poor in comparison.

Regardless, Rust is stabilizing procedural macros which just leaves the never type as the last stabilization required for Rocket to be able to run on stable Rust. Additionally, I believe their next release is targeting the rewrite to async. A lot of it has to do with Rust firming up its own story around async.


> It's not that he's unwilling to make it run on stable, it's that he has to sacrifice ergonomics to make it run on stable.

Two sides of the same coin. I clearly disagree about the amount of ergonomics that would have to be "sacrificed" in order to make the library usable in a production environment (on stable). So, it's simply an unwillingness to bring the library to stable, from my point of view.

Take Tower Web for example: https://medium.com/@carllerche/tower-web-0-3-async-await-and...

This has very similar ergonomics to Rocket in that it allows decorating handlers with their route, but it runs on Stable Rust. If you want to use `async fn`, that requires nightly for now since that's literally the nightly syntax for an async function, but the route decorators work on stable. As I previously mentioned, Tower Web is not mature, so I would not recommend it at this stage, but it shows what is possible.

I don't personally think that decorating handlers with routes is significantly more ergonomic than defining a table of contents somewhere else, like Actix does it. Defining routes is usually a very small part of your code that you do once and move on. Beyond that, what ergonomics are we talking about?

Actix can easily and automatically deserialize JSON into structs, for example: https://actix.rs/docs/extractors/#json


Is Rocket still on track to run on stable by the end of 2018, as per your comment here?

https://news.ycombinator.com/item?id=16543914

Anecdotally, I've been hearing claims that Rocket will run on stable "real soon now" for quite a while now. It just doesn't look like it's going to happen.


Looks like not quite: https://github.com/SergioBenitez/Rocket/issues/19

Never type can use a crate. The hygiene and error APIs aren’t going to be stable soon.

In theory it looks like rocket could use that package and accept worse error messages and build on stable. Sergio would have to weigh in on that, though, I could be wrong.


> which isn't something I find acceptable for production applications

For what it's worth, at least some of the largest rust adopters just pin to a nightly version, and don't have a ton of issues upgrading.


That was definitely true before Rust 1.15, but it becomes even less beneficial with each new stable release.

I work for one such prominent early adopter of Rust, and we were very happy to move to stable sometime back. Stable versions are widely used, so issues are much more likely to be noticed, and fixes are backported to the current stable release.

If you pick a random nightly version, you have much less support to begin with simply because fewer people use it, and you're on nightly because you're dependent on features that haven't been as thoroughly tested as those features that exist on stable, and which could disappear entirely in the next nightly. Each time you upgrade to a different nightly increases the risk of introducing some hard-to-find bug into production.

Some companies do use nightly Rust in production. You're completely correct. It's just not something that I would personally be willing to do unless I had absolutely no reasonable alternative.


> and it's synchronous, so it's really slow.

> it's asynchronous (so it's really fast)

Whether something is 'synchronous' or 'asynchronous' has absolutely no bearing on performance.


I don't understand the point you're trying to make. In networked stuff, the (a)synchronicity absolutely does make something fast or slow.

Suppose you have a synchronous web server with 4 threads, synchronous naturally means that each thread can only handle one request at a time. Each request can take dozens or hundreds of milliseconds to complete, just by being bottlenecked on latency. If it takes 100ms to complete each request, that server can only handle 40 requests per second.

If that server were asynchronous, each thread could handle thousands of simultaneous connections, making the performance literally thousands of times better at a minimum.

If you suggest spinning up an unlimited number of OS threads, that's quickly going to run into problems because most OSes can only handle a couple of thousand threads before you start running into OS limits that you have to adjust, knobs for which aren't always easy to find, and even then, each thread takes a significant amount of time to start and stop, as well as much larger amounts of RAM.

An alternative solution is green threading, which Go calls Goroutines, for example. In such a system, the asynchronous operations are handled by the underlying runtime and your code can treat them as synchronous and just spawn new "threads".

If you disagree, I would love to hear a more detailed response, because I can't see how your claim could be true.


All network I/O is inherently asynchronous of course, so the sync vs async debate is more about whether to use the blocking abstraction the kernel provides versus bringing your own or writing async code directly.

Using async I/O or a userland abstraction like green threads necessarily means you're moving the I/O scheduling work into userland. Sometimes this might be the right call, but it's effectively a bet that your userland scheduler can do a better job than the kernel's own scheduler.

This bet might pay off in highly specialised cases where your userland scheduler is well tuned to your workload, but the majority of userland schedulers (to name a few examples: the Go runtime, node.js's libuv) are also aimed at general purpose workloads and in many cases are far less mature than the kernel's scheduler.

There's been a massive amount of engineering work that's gone into the Linux kernel's various scheduling algorithms over the years. Pathological edge cases resulting in starvation or other performance issues have largely been identified and worked out. The various schedulers are also highly tuneable to the specifics of your workload if you need to do that.

These days OS threads are a totally viable option for building highly concurrent network services on Linux. Spawning hundreds of thousands of threads works fine and is fast enough for most applications. While threads will have 8MB of virtual address space reserved for their stack by default, this is just 'on paper' memory use - no pages are actually allocated until you use them.


> These days OS threads are a totally viable option for building highly concurrent network services on Linux. Spawning hundreds of thousands of threads works fine and is fast enough for most applications.

I don't agree. If you're at the point where you need to handle such large numbers of concurrent threads, my own experience and online benchmarks clearly show it is not fast enough. Why are none of the top performers on the TechEmpower benchmark using a thread per connection? The simplest answer is that that can't or they would, since it would be a waste of time to reimplement so much in userland.

More anecdotally, I have been unable to get my Fedora laptop to spawn more than a few tens of thousands of threads before the kernel tells everyone that "resource is temporarily unavailable" to any process that attempts to spawn a new thread or process until the offending process is stopped. I've googled the issue extensively, tweaked countless knobs, and come up empty handed. I'm certain the Linux kernel can spawn more threads than that, but my point still stands that it is nontrivial.

In theory, that's a great perspective you presented. However, the async interfaces into the kernel exist for very real reasons.

I would also challenge you (if you're bored) to write a C, C++, or Rust program that spawns 1 or 2 million threads that do nothing but sleep for a very long time, and write a similar program in Go. See how the two compare in how long it takes to launch all of the tasks, and see how much memory they use. Ideally, you would also use, say, Rust futures + tokio and spawn a million sleeping futures to compare there too, but futures and tokio aren't the most intuitive or well documented things yet, in my opinion.

I've done similar tests in the past, and OS threads are not a lightweight resource.


You don't need million threads to be really fast. You need enough threads for your load. If you need to handle 1000 requests per second with each request taking 10 ms in average, you need 100 threads. It's absolutely adequate number of threads for OS to manage. If you would write this code with async style, you won't achieve anything, because bottleneck would be with database or another service or disk I/O. Million threads is very rare case.


Can you please expand on how it made you a better developer?


It made more conscious about when I was modifying values stored in memory or creating copies those values.


I'm optimistic for the future of Rust. I currently program in Go for server side web stuff, but with the proposed changes to the Go language, the decision to choose Go over Rust becomes less compelling; Rust already has generics, a competent module system, better error handling, and ADTs. Go had a very narrow scope and very clear oversights, which are now bigger issues they are trying to shoehorn solutions into with the go v2 proposal.

I've been following rust for a while and have known it is not web ready, but early next year I think will be a different story.


What proposed changes to Go are you referring to?


It's web ready. It's very web ready.


Woah, I’m a big fan of rust, but saying it’s web ready is disingenuous. Rocket isn’t stable, most of the libraries rocket depends on aren’t stable either. Making http requests.. are there any stable http libraries yet? Last I checked Hyper was still on a 0 release with no h2 support.

Rust has conquered a lot, but it’s web service/API story is not complete yet. Go is ahead in this respect.


Check out actix-web: https://actix.rs

Does my proclamation still seem disingenuous to you? If so, why?


> with no h2 support

IIRC h2 support has been in Hyper for a few months.


IMO it's not really web ready until there's one web framework that has a clear majority of mindshare, like Rails for Ruby or Django for Python.


What's the point of this requirement? Python doesn't have "the one" either, does it mean its not web ready?


Yes but from a bird's eye view, rust code looks like perl. The readability is still a huge plus for go, even with the v2 proposals.


I love Rust, but in all honesty I wouldn't use it vs. Golang or C++17 for something that isn't a critical system (e.g a cryptography lib) and even then I'm not sure I wouldn't use something like OCaml instead.

The curve to productivity seem way too steep for the payoff.


Woah, woah, woah. First, Go and C++ are vastly different languages. Apples and oranges.

C++ is huge. It takes an incredible amount of effort to become a proficient C++ developer, and even then, C++ offers none of the amazing safety guarantees that Rust's borrow checker enforces. It's old language with sedimentary layers, including C backwards compatibility. Rust is no where near as complex, and Rust does 5x more to ensure you use Rust correctly. It has brought so many crucial advancements as well: immutable by default, typeclasses instead of OOP (thank god), real sum types, better unicode support, better concurrency primitives, and much much much better tooling and package management. No one in their right mind would be cracking out another C++ project if they took the time to learn Rust and C++.

Go isn't really in the same league as Rust, C++, or C. It's syntax is deceptively C like, and it has an equally poor type system, but it's performance is closer to Java, which is a few orders of magnitude slower than C++. Despite pushing outdated concepts like null and raw pointers on to the programmer, it has a runtime with a stop the world GC with no guarantees about object placement on the stack or heap. Go is also incredibly divisive, it's a step backwards that hardcodes a few useful container types, and gives you no facility to create your own. It has a hard coded method of concurrency (goroutines). While useful in it's simplicity, it lacks the generality one would expect of an industrial language, and these concerns are only now being accepted by the Go team in their 2.0 drafts. Many people believe that Go rose to popularity because of the authors and the company sponsoring it, not on its technical merits ,and Brad Fitzpatrick, one of the maintainers, even said the language brought nothing new to the table aside from better concurrency support in the Gotime podcast episode he attended.


> Many people believe that Go rose to popularity because of the authors and the company sponsoring it, not on its technical merits

I don't believe this to be the popular opinion. Originally Google's involvement dissuaded me, and indeed the very Googly bits have been the worst (context.Context), but the rest of it is markedly un-google-like. It's much more of a Bell Labs feel, with a focus on tool efficiency and stability.

> Brad Fitzpatrick, one of the maintainers, even said the language brought nothing new to the table aside from better concurrency support in the Gotime podcast episode he attended.

I think that was very much the intent. There were a lot of good ideas over the years (especially in Plan 9) and Go is really just a modern, polished revision of those ideas glued together.

Go is a _systems_ language at heart. It focuses on maintainability and literacy, and that's where it leads the pack in my eyes. It's possible to squeeze pretty phenomenal performance out of such a simple language. It's easy to drop into assembly for ultimate optimizations.

Perhaps generality is a mistake? I don't miss it. I've never found joy in debugging someone else's generalized metaprogramming.

Building software at serious scale has led me to appreciate the wisdom buried within Go. It's boring and I love it.

I've written a bit of Rust (and a lot of C++) which I find enjoyable enough, but they're tools I rarely find myself reaching for.


> There were a lot of good ideas over the years (especially in Plan 9) and Go is really just a modern, polished revision of those ideas glued together.

Plan 9 is an operating system. If you're referring to goroutines, CSP is completely unrelated to any of the work done at Bell Labs. That was Hoare. Go also kept a ton of terrible ideas, like nil, void (interface{}), and default mutability.

> Go is a _systems_ language at heart.

It really bothers me when people say this, because it's just untrue regurgitation from the Go team. It's not a systems language. It's a language that's pretty good for small web services. It has expensive interop (Solomon Hykes commented on this during one of his Gotime interviews) with C (even the Go team says cgo is not Go).

> It's easy to drop into assembly for ultimate optimizations.

You can only drop down into Plan 9 assembler, which is essentially useless. Write me an SGX lib without cgo in x86 and you can make that claim.


A lot of your claims about Go are false.

> It's a language that's pretty good for small web services.

I know projects in production running HUGE web services written in Go serving millions of reqs/s. If that's small for you then I don't know what large is. Look at techempower benchmarks[1] and additionally compare the source of actix-raw (Rust) to fasthttp (Go).

OS written in Go: In experiments comparing nearly identical system call, page fault, and context switch code paths written in Go and C, the Go version was 5% to 15% slower.

Read the paper[2]

1. https://www.techempower.com/benchmarks/#section=data-r16&hw=...

2. https://www.usenix.org/system/files/osdi18-cutler.pdf


People are doing OS research in Go, and Fuchsia core components like the TCP/IP stack are written in it, regardless of what the HN crowd thinks where Go should be used.

https://github.com/mit-pdos/biscuit

https://github.com/ycoroneos/G.E.R.T

Last version of Plan 9 was actually Inferno, which HNers keep forgetting about, which used Limbo for userspace code.

Limbo uses the channel syntax later adopted by Go.


People do os research in c#


And hopefully in the future even more so.

I was quite disappointed how WinDev managed to sink Longhorn and later WP 7.


+1 for Biscuit and Fuchsia


> but it's performance is closer to Java, which is a few orders of magnitude slower than C++

A few order of magnitude is an exaggeration. A more reasonable expectation is a 5x slowdown [1]. Depending on your task, a few orders of magnitude can be correct for JVM based languages; they can have very poor startup times (compared to c++) [2]. However, in startup time, go is not similar to Java.

[1]:https://benchmarksgame-team.pages.debian.net/benchmarksgame/... [2]:https://github.com/bdrung/startup-time


> JVM based languages; they can have very poor startup times (compared to c++) [2]

Hello world :-)

And is 54.55 ms perceptable?

(310.81 ms should be).


> And is 54.55 ms perceptable?

Its probably noticeable compared to instantaneously in terms of "feeling" different due to lag. However, it is definitely perceptible in the terminal based on my testing using `sleep`. For me (on my computer + monitor) down to 25ms is noticeable.

Also importantly, the hello world test shows 2 orders of magnitude simply, but the problem for JVM based languages gets worse for large projects (though not proportionally worse). Real java projects can take a second to launch whereas I haven't worked on a project large enough for that to be true in C++, Go or Rust.


"The basic advice regarding response times has been about the same for thirty years :

0.1 second is about the limit for having the user feel that the system is reacting instantaneously, meaning that no special feedback is necessary except to display the result."

https://www.nngroup.com/articles/response-times-3-important-...


Originally you asked "is 54.55 ms perceptable?", I say yes. I can tell the difference between 25 ms and 1 ms in my terminal.

That said, I don't think it is worth trying to reduce your startup time to the point where you can't tell the computer took time. Getting "the user [to] feel that the system is reacting instantaneously" is a different and more important goal.


> I can tell the difference between 25 ms and 1 ms

Maybe you are fooling yourself.


> Real java projects …

Can take much longer, and are engineered so that users don't experience a delay.

The users interact with a system that is already launched and up-to-speed. So much for Hello world!


I was just trying to come up with a real situation where there is a 2 order of magnitude difference.

Obviously in many situations you can mitigate the startup time. However, it does lock Java out of being a good replacement for git or other quick command line tools.


Not if jgit is already launched and sitting around waiting for commands.


> Go isn't really in the same league as Rust, C++, or C. It's syntax is deceptively C like, and it has an equally poor type system, but it's performance is closer to Java, which is a few orders of magnitude slower than C++. Despite pushing outdated concepts like null and raw pointers on to the programmer, it has a runtime with a stop the world GC with no guarantees about object placement on the stack or heap

Man, stating your opinions as fact is one thing, but every other claim you made above is empirically incorrect. Rust is a fantastic language on its own merits; no need to make stuff up about “the competition”.


> it's performance is closer to Java

Go vs Java https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

Go vs C++ https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

> pushing outdated concepts like null and raw pointers on to the programmer

I mean this is just a fact. Are you disputing nil and *?

> it has a runtime with a stop the world GC

https://blog.golang.org/ismmkeynote

"On the Y axis we have GC latency in milliseconds. On the X axis we have time. Each of the points is a stop the world pause time during that GC. "

> with no guarantees about object placement on the stack or heap

From the F.A.Q.

" How do I know whether a variable is allocated on the heap or the stack?

From a correctness standpoint, you don't need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language."

> but every other claim you made above is empirically incorrect.

Seems you're empirically incorrect.


The benchmarks game is just that: a game. Notably, Go programs are prohibited from doing certain optimizations that are permissible for C++ programs. The conventional wisdom is that Go and Java are within the same order of magnitude as C++ though still slower. I’d accept that they are a full order slower, but not multiple orders.

> Do you dispute nil and *

I dispute that Go’s pointer is a “raw pointer” in any meaningful sense of the word. In C++, raw pointers may be uninitialized, they may be cast from any int, they don’t imply any automatic cleanup of the pointee, and they are subject to pointer arithmetic—none of this is possible with Go pointers except via the “unsafe” package. So basically none of the criticism of raw pointers applies to Go pointers.

> Go has a stop the world GC

You are correct here, Go has a stw GC. It’s probably not suitable for RTOS, but its pauses are on the order of microseconds, so most of the conventional GC criticism doesn’t apply.

> Stack vs heap

The language doesn’t have semantics for stack vs heap allocation, but that doesn’t mean it’s hard to control where things are allocated. In particular, the compiler can spit out where its allocating and you can adjust accordingly. It’s far easier to do this in the hot path than to have to specify where every piece of memory is allocated across your program.

> seems like you’re empirically incorrect

Quite the opposite, actually. There’s nothing wrong with not knowing or being mistaken, but there’s no need for overt snarkiness.


> The benchmarks game is just that: a game.

The name "benchmarks game" signifies nothing more than the fact that programmers contribute programs that compete (but try to remain comparable) for fun not money.

It's what you make of it.

https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

> Go programs are prohibited from doing certain optimizations that are permissible for C++ programs

Which programs? Which "certain optimizations"?


That benchmarks game quote supports my point (not sure if you quoted it to contradict me or not?). As for prohibited optimizations, arena allocation is the one that comes to mind since it’s the standard way to avoid O(n) allocs.


> That benchmarks game quote supports my point…

As-long-as your point was not intended to be dismissive in any way.

> prohibited optimizations

Go programs are not prohibited from using arena allocation provided by a generally available library — that is what the C++ programs do.

Unfortunately there doesn't seem to be a generally available Go library that provides arena allocation. Of course, Go does provide GC.


It is dismissive of the idea that the game can tell you meaningful things about a programming language’s average or percentile performance or even its peak performance.

> Go programs are not prohibited...

Right, and this is why the Go benchmarks for allocations aren’t very meaningful. Using arenas (or other kinds of preallocation) is a common optimization in Go even if Go doesn’t have a library for it.

I’m sure you’re well aware of all of this since you evidently contributed to these benchmarks, but for other readers, here’s a good thread about why these benchmarks aren’t meaningful.


Where did you get the idea that 10 tiny tiny programs could tell you about a programming language’s average performance?

Who in this discussion has made any such a claim?

You repeatedly put up a straw man.


Im not sure why you’re confused. ilovecaching made claims about the relative performance of programming languages based on the benchmark game.


ilovecaching responded to your claim that — [Go's] performance is closer to Java — by posting links to pages on the benchmarks game website.

ilovecaching pointed to the performance of specific Go and Java programs

Now you have put up a straw man — "a programming language’s average or percentile performance or even its peak performance."


> … it's performance is closer to Java …

You seem to be quoting yourself out-of-context ;-)

In full, you wrote — "… but it's performance is closer to Java, which is a few orders of magnitude slower than C++" — and that is not shown by those measurements.


>First, Go and C++ are vastly different languages.

Yes, the point isn't to say that they are similar. Quite the contrary in fact, they are different enough that they compliment well. If I have to do latency sensitive systems work I would use C++17. It's good enough, has useful constructs, and all-in-all, rather easy to write.

It's nice to have stronger static safety but they usually displace the cost somewhere else. AFAIK, Rust becomes extremely touchy when you start inter-operating with abstractions the borrow-checker is not omniscient about. Wrapping code in unsafe{} everywhere feels clunky. That's not my biggest peeve though. Programming complex systems is an iterative process for me. I prototype, go back, throw it away, rewrite, until requirements are met and so on. I don't feel like I would be productive doing that in Rust. I don't care for safety for as long as the software prototype is complete enough. In that phase of development, what I care about is a compromise between velocity, performance, and safety.

The only thing I really miss in C++ is powerful type-system: GADTs and all. But again, if I find that I need those I would use a language that truly excels at that, OCaml.

For anything else, I found Golang to be a terrific fit.

It is easy to on-board new people and have them get productive and feel empowered enough to push change. The building blocks are easy and compose well.

Yes, I agree the lacks generics of generics can be frustrating, especially when software grows. On the other hand, it can get old really fast to debug templated software.

As for GC, it might not use fancy algorithms but from empirical experience, having worked with a wide-range of different applications with different workloads, I found that GC pauses are short and hardly ever an issue. I wouldn't use to write a RTOS but for most usage it's fine and a net positive in productivity and quality.

>Go rose to popularity because of the authors and the company sponsoring it, not on its technical merits

It rose to popularity because it fills a huge niche. My job is to build robust systems that do their job and deliver business value. It's easy to maintain Go code, it's easy to understand, and provides the right amount of static safety most of the time. I find Golang to be a humble and honest language, a productive C.

Rust is cool but not worth it for me.

>No one in their right mind would be cracking out another C++ project if they took the time to learn Rust and C++.

If I had a dollar every time I had read that (replace Rust by Haskell/Erlang/Lisp/Whatever language the cool hip kids use).


I think folks might find Sentry’s use of Rust interesting. Sentry is quite invested in Python on their backend, but needed additional performance mostly related to symbolication of crash reports. So they have a Rust symbolication library with Python bindings giving them the best of both worlds for their app.

https://github.com/getsentry/symbolic


Can anyone recommend exercises for learning a new language. For example, something like "implement a class with these methods", or implement a function that does this. Something that is realistic, should only take an hour or two to implement for a competent programmer, requires you to learn more complicated features of a language, yet I can finish before getting bored or frustrated?


Advent of Code[1] - A set of 50 tasks, released annually, with increasing difficulty. Each task is a short, Christmas related, funny story which makes it easier to follow and complete. You can track your progress so it'll give a sense of completion and satisfaction. The drawback may be that challenges are language agnostic so they aren't crafted for learning specific features of any language.

[1] https://adventofcode.com/2017/events (3 editions has been released so far)


For Rust I've seen people reference Rust Koans (https://github.com/crazymykl/rust-koans), but I haven't looked at that myself. I wanted a project that was sizeable enough to force me to use a good number of language features (but not all). I think the interpreter was a pretty good balance there, but it definitely took a time investment.


I'd also like to hear what others do to learn languages. I like to write a little RPN calculator. The program's interface might vary depending on the language: to learn browser JS, you might do a DOM-based UI; for Rust it might be a CLI; for Go or Erlang maybe a line-oriented network service.

Depending on the interface, this tends to exercise language and runtime features like: string handling and parsing, event handling, conditionals / pattern matching, etc. "Calculator" is also a big enough problem space that you can come back to it to try out more interesting language features (e.g. using Rust enums to model your calculator's operations).


I usually write data structures like Linked Lists when learning a new programming language.

This was a critical mistake for me when learning Rust and led to many, many stumbling blocks


Things like Cryptopals (https://cryptopals.com/) are good.

But surely it's going to depend somewhat on the language and what things are easy/hard to do in that language?


I think you can find koans for a lot of languages (mostly pre written tests, where you write code to make those tests pass. Some examples:

1. Kotlin Koans (https://play.kotlinlang.org/koans/overview) 2. Ruby koans (http://rubykoans.com/)



Peter Norvig has a repo of such problems / solutions (he solves them in Python, and calls them "pytudes" = "python" + "etudes", although they should be solvable in any language) https://github.com/norvig/pytudes

Rosetta code also has a great selection of problems / solutions in various languages: http://rosettacode.org/wiki/Category:Programming_Tasks


Rosalind is a good platform to learn a new language. Not the best to discover the most advanced features, but enough to ensure you know your structures and algorithms.

http://rosalind.info/


Maybe replace something you would write as a shell/perl/python script for automation with a rust binary.


Question: does "getting rusty" mean you're getting better or worse at Rust?


Worse. I think "getting oxidized" would mean getting better.


Yes.

More

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: