Rust vs C++

From @dirvine’s recent twitter posts I gather that he’s slowly falling in love with Rust :wink:
If you find the time to comment, I’m curious to know where the advantages/disadvantages of Rust vs C++ lie in the context of SAFE. I’m not a programmer, so I’m wondering is it possible/would it
make sense to switch to Rust? can a transition even be made? is it possible to build Rust apps on top of the C++ core of SAFE?

6 Likes

It’s something we are looking very seriously at.

First things first, Rust is not launched, but Beta from next Monday Launch version 1.0 in May. So huge projects would suffer as the API is changing a lot.

So caveat aside (but not ignored, it is a big issue), I see the advantages as
1: No crashes because of code misuse (as long as you do not use unsafe {} )
2: No memory leaks
3: No data races (so you can thread this thing like mad, but better is has async task handling (crs pattern to). So lighting up your machines cores is no prob.
4: Cross platform (really much better than most)
5: Inbuilt version management, build system and test harness (with benchmarking to).
6: Package management system (no more I Cannot build XX, it becomes automatic)
7: Inbuilt generics and traits (c++ concepts and more)
8: Very strongly typed (near zero runtime)
9: Very fast
10 compiles into a c lib basically (easy integration)

Sounds great, well it is, I took last week to investigate and caveats aside took a bit of a dive in there (just popping into the office to keep up with all the design discussions for routing_v2 -> looks great BTW).

So I figured what are our hardest libs to write (self encryption and routing). So I transposed self encryption from c++ -> rust. It took 3 days. It is not fully complete but close and that is a test suite, CI setup, packaged and published lib ( https://github.com/dirvine/self_encryption https://crates.io/crates/self_encryption So again not much on the sleep front :smiley: ). I need to finalise the encrypt and close methods, but I am waiting till after Monday as I need a part of the API to settle in Rust.

So now I will transpose routing to see what it looks like from there.

I am doing this myself as a sideline just now as we are right in launch mode for testnet3 with routing_v2 and crux (which will be 100% c++11 code). I Cannot disturb the real devs here, or you folks would rightly lynch me :smile:

So next 10 days I will try and get routing and vaults up in rust to run alongside c++ and we will really have to consider this then, if it is all successful.

So saying that, we gain a lot from Rust, it’s a very modern safe and secure language, but with modules (think Ruby builder ++ ) so you can just type safe-farmer "1.0.0" into a cargo file (config thing) and you will have full access to the code. Or type ````safe_client “1.0.0”``` and you will have all that built and ready (in only a minute or so). So goodbye complex build systems as well. A real PITA we spend months working on.

Not only that but to build in this systems language you have simple access to not only our code like this but everyone’s. The apps so far in Rust are kernels, window managers, games (2d and 3d), GUI’s, crypto libs and much more. So think managed language done right with systems language performance. Build anything you want with it.

So the community using it range from php/python/ruby etc. as well as java/c#/f# and so on to functional programmers haskel etc. which is a surprise. What are these folks doing near pointers and the likes, these are dangerous tools, not for fast app dev, but the issue is. You cannot make segfault/race condition type mistakes in Rust, it wont compile (very strong type system). Savings on debug here are colossal. The target group for the language was c/c++ devs and they seem to really like it, the rest are a surprise and a really good one.

So all in all it has to be taken seriously, I think with all the advantages you are looking at productivity gains that will be very substantial (I think you are looking at 10X or more for c++ systems work) and apps that do not crash.

My take is that this will feature in SAFE, how much I am not 100% on yet, the testing continues, but I would not be personally surprised if we transpose over in testnet3 as it seems to good to miss. If somebody took our code and transposed it they would be in a much better position than us to take it forward and that to me says it all really. Also great for pods, we have found c++ at this level to off-putting for many to help out with and no surprises, it is extremely hard. We need strong safe and secure code to go along with our strong safe secure network and this may be an edge that just helps us along.

With routing_v2 for instance in vaults we have reduced the code by 98% in the last three weeks, so transposing over is not a showstopper for us as we have the resource as long as tenet3 is up and running as the app dev team will be working like maddies and the core team may have some space to do this.

So you can see my conundrum, but I think it’s a done deal really, unless testing shows us a big issue I think Rust will be a very welcome friend to us and remove almost 90% of our time we spend on build/data races/memory protection and more, all that 90% goes then into core algorithms and not silly code issues.

It also lowers the barrier for anyone getting into the core code (whilst increasing security - so it’s a bit mental) and to me that is also very compelling.

21 Likes

The advantages definitely seem considerable and the case to use it compelling…sounds like a no-brainer, bar the caveat.
Is the caveat/worry that you won’t be able to start the transposition until May using the V1, or, that app devs won’t be able to interact with the Maidsafe API until May? …anyway all sounds good :smile:

4 Likes

Both really, so I will track this closely and make a call very soon I think. Now if folk will listen? well that’s MaidSafe always a debate :wink:

3 Likes

And we need 2 sides to have a debate
I adopt a 10th man principle :wink:

1 Like

Would this not be better to do later on in the dev cycle? After v1 perhaps? :slight_smile:

Yes possibly, we need to keep abreast of it though. I think a lot depends on these tests I am doing really. Transposing over seems pretty easy then making use of the advantages is much easier. Interesting Mozilla re backing this and we like the Mozila folks we have encountered so far. They have high expectations :wink:

9 Likes

More awesome news.

What flow through benefits would this change have at the API/ App level. It sounds like economically you’d be silly not to develop in RUST at this level also?

1 Like

Yes I agree, in terms of our ports projects then Viv reckons the change is a change from c++ to c which is nice. For app devs then Rust gives them fantastic benefits as well. Its several hundred times faster than many languages with ease of use. The build system tests and the rest are a huge help for app devs, even if they only use it initially to speed up slower parts of their system, but it looks like it will reach much further than that.

For us c++ was the bet game in town for systems level solid programs but this changes all that in a way that has been described as c++ for the 21st century and I agree with that.

1 Like

I compiled some links for Rust explorers:

Github:

CI for your projects against Rust nightly build: http://www.rust-ci.org/projects/

Rust Rosetta - Code For Common Tasks: https://github.com/Hoverbear/rust-rosetta

Rust by example: http://rustbyexample.com/

Cargo build system: http://doc.crates.io/guide.html

I believe this is a plot by David to get me programming again.

8 Likes

You will see a huge difference if you do now, I thought c++11 was a new language, this is decades in advance now. Actually fun to code in. In terms of sharing code it’s a real breeze so lots of fun.

2 Likes

See. :wink:

3 Likes

Sounds reasonable. I just try to regularly remind myself that delivering something functional is much better than not delivering something which would have been perfect! :slight_smile:

2 Likes

Intro to the Rust programming language: http://youtu.be/agzf6ftEsLU

I’m highly skeptical at most of these claims by rust.

The “no memory leaks” is a slight mis-truth I’ve heard from Java developers frequently. I always point out that if the code was designed to hold data references for long periods of time (even indefinitely!), the fact that the memory is still tracked is only a minor improvement.

Additionally, I don’t think the claim of “no race conditions” is true either. Its a technical truth at the byte level that will trap lots of developers proudly thinking it solves all of their ordering problems between asyncronous events. One example that comes to mind is one I saw in drive about 2 months ago, the typed checking system of rust would’ve never caught it because it involved a race between remote network operations. The compiler would have to check what the requests were doing in vault, and know what ordering was required. I don’t think that can be caught at compile-time by rust, especially since its just doing rudimentary type checks. I see this ending in tons of developers promoting apps with no race conditions, like Java and no memory leaks. The result will be no crashes but plenty of incorrect behavior. Its more important to keep a programmer scared than thinking everything is safe (yeah thats sadly dark).

The no crashes claim is always interesting. If the app goes down due to out-of-bounds exception or null pointer exception, is there much difference? I suppose the one benefit is less potential security exploits through this invalid memory accesses. From a users perspective theres little gain though if they hit either case.

Despite these complaints, I was practically high-fiving a friend of mine after first digging into the rust specifications ~10 months ago. I do see certain improvements in language design (modules were also nice), but I’m not sure if it differentiates itself enough from C++ to matter. It will probably depend on how much the type-checking system actually benefits code.

1 Like

I was to, but frankly the last weeks digging has shown it to be pretty remarkable. The strong typing goes even beyond concepts and leaves almost zero runtime (their goal). What I find transposing our code is areas where it just won’t let us handle things the way we can in c++. The reference system which forces lifetime specifiers seems weird, but makes a lot of sense. Also the traits system is incredible really, tonight I compiled a draft for using dynamic dispatch in routing (to allow vault/client façade) and it’s very powerful. The whole cargo packaging / module system is very well done and makes code sharing simple and interestingly promotes separation of responsibility very well.

When you code up a few examples or port over some of you’re code you will see. It feels weird as enums are possibly more powerful than structs (variants/tagged union with implementations) and traits are really fantastic to really tie up the type system. All in all the speed and ability to use task passing threads is just really simple to use and construct very efficient code. So yes the claims seem to good to be true, but then again we fell for std::async as well so there is always a doubt. I have found it much simpler to code when you are forced to use types and much stronger types that we are used to in c++. It’s very compelling indeed.

2 Likes

None of these appear possible in Rust, it won’t compile. If we can create an example making this happen then I am sure they will really want to see it. Again sounds bizarre but it is true. Unless you do
unsafe { /* stuff here / }
Then it checks all bounds and does not allow dereferencing a pointer you don’t own (there is no RAII requirement either due to ownership model)

The option/enum features were very powerful, and I didn’t see any reason for a performance impact either. Very nice.

The traits system is nice, but can be done in C++ too. Might have less boilerplate in Rust, but I haven’t seen any additional functionality. Making it a visible part of the language does make the technique more well known.

Still a sleight of hand. If you want to lazy-load something I think you have to do an option with a single type or a pointer-to-a-type. Since the option can be empty, the possibility still exists where you expect something to be there but isn’t. This type does require a “visitor” of sorts, one of which must handle “none”, but how is that different than Java’s implicitly checked pointers? I don’t see how it is, they’ve re-classified null pointers into a different type. The one benefit is that most people just want pointers to pass ownership cheaply (and not lazy loading type things), so they did manage to “solve” the problem for the average use case. Still not a magic bullet though; an unexpected empty option is likely to result in program abortion.

For buffer - what if the size of a buffer and the index of the buffer was computed at runtime, as often is the case? I don’t see how it can check to values only known at runtime. Even if the size of the buffer was fixed, indexing into the buffer has to be checked at runtime - having both as fixed would be a huge constraint. This should still result in runtime errors (but unlike C++ the behavior is defined).

1 Like

True, but with C++ it’s possible to do nastier memory leaks and pointers pointing directly into memory. I like Java because it’s cleaner, safer and more easily portable than C++. For really hardcore stuff I guess C++ can result in better performance, although JIT compilers have gotten pretty good.

As for Rust, there are many more developers who have experience with C++. I myself am looking at JavaScript at the moment. :slight_smile: JS is messy compared with Java, but pretty interesting with how functions can be used and performance is surprisingly good despite being a script language.

I think this is where the match (switch type) is very cool, it forces exhaustive checks. So if you do an Io method or similar you must match all returns and this is again forced through the type system. So this may be a solved issue I Cannot see how you can drop a return type this way.

For buffers (well any static size type) there is a sized trait and if you cannot calculate that size at compile time then it will force a dynamically allocated buffer be used. There is a lot of very nice features at play here.

1 Like