Announcing Rust 1.6
blog.rust-lang.org
blog.rust-lang.org
C11 (and C++11) defined a memory model and atomic operations for shared-state lock-free concurrency. But that model and the atomic operations aren't being used by Linux, because they didn't match up with the semantics of the operations that Linux uses. (See https://lwn.net/Articles/586838/ and http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p012...).
I'm curious what Rust says about this. Does Rust have a memory model like C11/C++11? I'm curious whether Rust (and C11/C++11 for that matter) will evolve to have primitives like what the Linux kernel currently defines and uses.
https://github.com/rust-lang/rfcs/issues/1447 is a good thread if you care about this topic.
As part of defining the Rust semantics they will certainly tackle the question of the memory model. Dreyer and company have a track record of providing semantics and reasoning principles for weak memory models (like C11).
You might have to wait a while for a rigorous semantics though.
The Linux kernel is written in C, but uses lots of GCC-specific features and inline assembly to address things that aren't covered by the C standard. Among these, the Linux kernel has its own set of atomic types and memory barriers. It documents them here: https://www.kernel.org/doc/Documentation/memory-barriers.txt
So even if Linux is being compiled on a conforming C11 compiler (the Linux kernel is written in C, not C++), it uses its own atomic primitives instead of the ones provided by the language. Hope that helps.
As the HN crowd seems to have quite a lot of Rust supporters, would it be a good selling point in a job description ?
i.e if (it's just currently a personal hypothesis) a company were to consider to (re)write some part of its Rest-ish microservices and that Rust was the chosen language, and was looking for people to help on that, would it make a `interesting++` in your mind ? for real services used by real people by a not-so-startup company, in europe.
edit: I already deployed in production for my previous company some (with a very stricly limited scope) microservices in rust (with everyone approval) and it was quite a success, so I'm more and more thinking that rust is now enough developed to fit the market of language for microservices, as it's more or less "understand HTTP, read/write from redis/postgresql/mysql/memcache, do some transformation in between" and Rust now support these operations quite well
But honestly, even if I hadn't it's be a selling point to me because it tells me that you're a place that isn't stuck writing everything in a single language but are willing to try new things are willing to use what seems to be the right tool for the job.
Also, since you mentioned PostgreSQL, if you can make the db handle json the shuffling part should be really trivial. Give node.js + pg-promise a spin for comparison.
But then again, I haven't used Rust for anything serious, so am happy to be wrong.
http://stevehanov.ca/blog/index.php?id=95
It's a bit silly, but I do think that Rust could be a very good solution here. For one thing, in my experience it is much easier to write than C++, especially for something you'd feel comfortable pointing at users.
It would be cool to see some articles that are the reverse of "scale all the things," something like "sympathize with all the caches."
1. rust handle erros in a VERY expressive way, and I do want my services to log ANY errors, and to be sure to miss any (kind of like what go permits too , but Rust Errors are more flexible) , so with rust it's hard to forgot a case of error and finished with "errr my API did a 500 but i don't know why"
2. It's a (nearly) self contained binary with low memory overhead, I can have dozen of microservices like this on my workstation / CI environments without making the machine cries So I can deploy it on cloud provider X or workstation Y without needing to worry if it has the version of node / python / php I need
3. it creates very small docker image if you're using docker (so it beats node/python/php here)
4. if I want to make my services multi-threaded and have some internal cache for some reason I'm sure the compiler will not let me create concurrent access problem that I would otherwise only detect in production when it's too late (beats every other languages , including go , the go race detector of go is nice, but it's at runtime so not the same league)
5. no nil pointer exception things (beat other languages here too)
6. strong typing but flexible (no go, I don't want to cast everything in {}interface everytime i need to make things a bit more generic, though I know it's just a personnal opinion), because no I don't want my developer to either develop a "is_true" function , or worst to rely on type casting for if to work.
7. the compiler as my first set of test it's a whole category of things you don't need to write test for because it's already handled by the compiler.
8. highlevel when you needs, low level when you want, I know that the language is not my bottleneck (or then I've reached the point where I don't care because my system is performant enough) , but if I need to serialize my struct into a json, I can in some line of codes.
9. plenty other little things , like scoping variables, immutable by default , possibility to have your SQL request check at compile time if you use postgresql plugin, using first-class debuggers to do step by step if you need , interfacing with C libraries pretty easily
But, you could write embedded software, device drivers and even operating systems in Rust, that's the domain where Rust could and hopefully will dominate.
with all my love for haskell, this is an understatement...
Yes the runtime behavior is definitely less predictable with lazy evaluation, which is fine for web servers but terrible for systems programming.
This is the classic domain of scripting languages (PHP, Ruby, node, ...), where a huge ecosystem exactly for this kind of tasks exists. But yes, type safety and error handling is not the best there.
If a good type system and a good ecosytem is desired then F# or a JVM language (Scala with Play Framework, Kotlin, ...) could be used, which would from my perspective give a more productive setup for this task.
I don't want to say that Rust is not good, but (just like C++) I think it's best use cases are other applications then webservers, e.g. high performance audio and video processing or bare metal software.
Yes it would. People love to be trained on a new software stack at someone else's expense, especially if they're not having to take a seniority hit to go there.
What do you mean by `doesn't target backend app'?
I cross-compiled this stuff to run on Raspberry Pi, and the binaries are so small and performant!
Feel free to respond here or reach out (contact details in my profile, you can find me as reem on the mozilla irc network).
Because he doesn't like NULL pointers aka the worst mistake of CS?https://www.lucidchart.com/techblog/2015/08/31/the-worst-mis...
Because he doesn't want a package manager that always fetches HEAD?
I'm not saying Go is a poorly designed language where the answer to every decision is the easiest one for the implementors. I'm just saying there's a legitimate case to be made.
If anyone complains about having nil in Go, I usually assume they're either forced to work a really bad codebase or lack experience in Go.
I've worked on a Go codebase for ~2 years, and I'm pretty sure the only nil pointer dereference I've seen was due to a concurrency bug, where an object cache (implemented as an array, not sync.Pool) was not locked properly.
The problem with having nil is when you expect a value to be either a valid pointer or nil to indicate an error, and you forget to check for an error. In Go, in my experience, explicit error checking and multiple return values makes that a non-problem, however ugly some people consider it to be. If I see error assignments to _, that makes me raise my eyebrows.
> The problem with having nil is when you expect a value to be either a valid pointer or nil to indicate an error, and you forget to check for an error.
That's not the problem with null pointers. Null is used all over the place for non-error conditions. The problem is when an object legitimately might or might not be present, but the type doesn't encode that fact, so some code mistakenly assumes that the object is always present when it isn't.
Yes reworded slightly, types encode value invariants, nullable types can't encode one of their invariants.
This is the reason for the rule of always returning error type in Go, not a pointer to detailed struct error. That leads to an ugly code when a check for non-nil err is followed by a cast.
This isn't the case. We have web backend libraries (servers, database thingies, template engines, I/O, etc) and it's totally possible to work on backend stuff in Rust. Rust doesn't "not target" much, really. Most of what you do in Python/Go/Ruby is also something we want Rust to work for. There is a false dichotomy of "fast language or safe language" which Rust does away with -- it's not only for situations where you would usually use C++.
It feels odd that someone would question it nowadays.
I surely do hope Rust gets used for everything.
Almost every programming language can have a REPL, it is called an interpreter. Anyone with a CS background should know this.
Also Lisp is a compiled language since the early days.
That's the theory though. The practice is (was) that Lisp had an excellent REPL, and most languages didn't have one at all, or had a crappy one.
Some languages lend themselves to a REPL by making it much easier to program one. iPython is great, JS ones are decent. Go attempts at REPLs otoh are mostly BS. C++ REPLs (Cling) etc, are neither very handy nor very popular. Etc.
The truth is, some languages handle the REPL situation much better than others. And "scripting" languages are usually better than others at that.
And REPL is not really just an interpreter. You can have an interpreter without having a REPL, or without having the kind of full featured REPL we're talking about. Most BASICs run with an interpreter, but didn't have a REPL, for example.
I am pretty conformable with Lisp, which isn't a scripting language at all, offers both a very good REPL experience and has the option of compiling to native code, both at REPL and AOT.
Also BASICs not only had an interpreter, but they also had AOT compilers. Visual Basic had a REPL, it was called Interactive Window.
Scripting languages don't have AOT compilers to native code nor Lisp is a scripting language, so I don't get the point of the comment I was replying to.
Well, if by "almost" you meant "in practice few and far between", then we agree :-)
What I've seen is that languages with AOT rarely have good (or any) REPLs.
Now, LISP of course has AOT, but it also shared (and early on) many characteristics of scripting languages (GC, dynamic typing, etc).
So, maybe a better way to put it is Algol derived languages with AOT as a rule don't have a good REPL story.
That was because at the time, forking was expensive, threading was too hard, and memory leaked like a sieve. Rust addresses all of these problems, and does it nicely.
For other compiled languages, I don't think so.
more reasons:
On error handling, in Go most of libraries and even some part of the std lib, erros are constant string, which mean that for example you can only do
`err == foo.DUPLICATE_KEY_ERROR`
but you can't extract which key, or then you start to have to either use an external library to do some string masking/unmasking, which complicate quite things and add one more dependency, or just to say "screw it, i will just log 'duplicate key error" which is unoptimal
I really did try go, to the point I even proposed a fix in the std library for a long standing bug in the xml library https://go-review.googlesource.com/#/c/15684/ , but not all the reason stated above makes me consider go as "yes sure it's an improvement over php/python/c++" but rust is like an even bigger improvement
As I got more into this kind of language I found that the language tools gave me very strict isolation, which lowered the value of separating everything at the process level. So I've shifted towards a more monolithic style of architecture.
You can follow along, all slides and HW are on github.
They probably should have prepended the school name to their GitHub org, but that's just my 2 cents :)
Likewise, Rust is not finalized as a language yet. That means whoever has to maintain the original commenter's code is likely to be in for a rough time if and when they ever attempt to bump the Rust version.
It is just as finalized as any other language.
> if and when they ever attempt to bump the Rust version.
If the parent is using a stable release, like this 1.6 is, then bumping the version should be all they need to do. (Unless they're relying on a safety hole for some reason; we do fix those)
So it's easy to see where you get the impression that Rust is prone to breakages, but that doesn't happen anymore.
Incidentally, this isn't really a criticism, but it's precisely because I don't see Rust as finalized that it isn't. A language that's finalized but not specified is just poorly documented.
It's only unreasonable due to Rust's young age. At Rust's age, none of those languages had a specification either.
This fact is the major reason behind the whole undefined behavior story in C and its derived languages.
When the standard came to be, no vendor wanted to give up on the semantics that gave their compiler some kind of advantage.
So all those little issues were tucked into undefined bucket.
So, I'm not seeing your examples as relevant or a critique. Most were in use and changing [to their benefit] before any spec was created. Three of those very publicly, one privately. Another sucked partly thanks to formalizations with lots of money driving adoption. I think you should read Gabriel's Worse is Better essays... several rather than just the first... to see why pushing a partly done or evolving system is right approach for growth & accelerated improvements. Lipner at Microsoft, inventor of successful Security Development Lifecycle, incidentally thought the same thing.
Least Rust team is trying to fix problems and evolve in a robust way. That's quite rare for mainstream stuff that I've seen.
I might have been too hasty there. Your context and this quote makes much more sense. I say something similar to them myself. Yet, they've already entered a 1.0 mode where they're not breaking stuff with much of it documented in guides. That's not formal but pretty final on language itself. Standard libraries and other tooling are where most of their work is right now.
So, I don't feel it's an accurate statement but it's close if we're talking the language. I prefer to say the core language is pretty stable or something like that.
The reason why Rust was stabilized in advance of a standard is that stabilization had an immediate practical consequence: ceasing to break code. A standard, by contrast, would have virtually no practical use.
I actually find myself pining for the simplicity of #[test] in other languages. It makes the Write->Test->Write loop so much faster.
"Actually managed to sneak some Rust into production."
"...sneak some Rust..."
"...sneak..."
There's your answer on that one. ;) Others might be quite useful, though.
I Work in an aging framework for electronics testers written in a combination of C#/VB/LabVIEW its highly asychronous nature make debugging the system an issue.
I figured this and you possibly breaking the rules were the reasons for discretion. I also figured you were forced to use aging crap that motivated you to try alternatives. A painful, but common, thing in industry. Hence, me reminding the other commenter not to expect a source reference on it. ;)
"I Work in an aging framework for electronics testers written in a combination of C#/VB/LabVIEW its highly asychronous nature make debugging the system an issue."
I usually try to drop papers or articles at moments like these but have nothing relevant. There's only a few articles in my collection on asynchronous systems (outside I/O) because they're so hard to verify. I did find a few resources. Would have to know if the problem is communications, data, what before I could attempt suitable references for you.
You probably already do one of my base recommendations here: tracing flows and input validation on them. The equivalent of asserts on input and/or monitors with read access to global state comparing data/states against ranges or rules in a policy. Taint-methods are also helpful where you tag data in the datatype with details about where it's been and whats happened. That's more advanced and I'm not sure there's libraries available for those platforms. The other technique they can easily handle: I did it in VB long ago.
"Screw diamonds: legacy systems are forever."
That's friggin' great. Need to make a meme image out of that with some COBOL or RPG on it. :)
GRR isn't hard just time consuming. Yes its not fully verified
>I also figured you were forced to use aging crap that motivated you to try alternatives.
I'm actually a polygot programmer trying to pay the bills. Working in aging tester frameworks pays a lot more then web development. I like Rust b/c its basically C-With-A-Type-System. Its still very easy to reason about how the Cee-LangVM will handle your code.
But yes. Working in a code base from the 80's and switching to Rust is lovely.
:.:.:
The core purpose is exception logging. A lot of the exceptions will get mutated/modified before being reported. "Servo drive failed." is a lot less useful then "Servo communication fault 0x274077343" which I've memorized to tell me that a power surged knocked a comport off line.
https://news.ycombinator.com/item?id=10954970
"GRR isn't hard just time consuming. Yes its not fully verified"
I believe it now after pulling papers. I even know exactly how hard it is and what parts are decidable.
" Working in aging tester frameworks pays a lot more then web development."
Makes sense. It's why I advise against commodity jobs. The niche or unpopular stuff usually pays better. Not always, but usually.
"The core purpose is exception logging. A lot of the exceptions will get mutated/modified before being reported. "Servo drive failed." is a lot less useful then "Servo communication fault 0x274077343" which I've memorized to tell me that a power surged knocked a comport off line."
Hmm. That's more straight-forward than most async. Just detail-oriented work as you said. The taint idea of tracking exact sequence of mutations combined with design-by-contract tracks of function call contexts would certainly help that. How much I can't say as your combination of tech obscures it. Don't know enough Labview mainly. Microsoft has things like Spec# and verifiers for C# part with VB6 easy to ignore if you keep logic out of it.
So, you're in better shape than many doing multi-language, legacy work. At least as far as verification concerns.
Don't learn it. Its a terrible language, and a worse IDE. Yeah you'll learn over 6 figures with 2 years experience. But you'll waste a lot of time debugging issues with the runtime itself, also the langauge itself isn't consistent which can lead to extreme headaches/development lagging. But NI will compensate lost development time with free hardware so companies love it.
The tools for tracing/testing in Labview are annoying and kinda primitive. Hence why a separate callable logger is useful. Mainly in Labview all functions start out as heap allocated monands wrapped in a mutex. So basically every function has state initially. You then have to opt-out of this to get a pure function.
>Hmm. That's more straight-forward than most async
Well yes. We're not exactly concerned with verification of the asynchronous system. Just making sure everything happens in the right order, and each thread is actually doing what its commended to do.
At a certain level you can abuse asynchronous systems to make certain measurements easier. Just assume your input has a half-Gaussian input lag level, and suddenly a 200 sample moving average becomes sufficient for smoothing data not jumping though hoops of fire doing weird data synchronization.
WOW! I never even thought about that business angle to dealing with shoddy tech. Thanks for the warnings.
"Well yes. We're not exactly concerned with verification of the asynchronous system. Just making sure everything happens in the right order, and each thread is actually doing what its commended to do."
Glad you at least have an easy approach to dealing with that nonsense. :)
Well most companies don't supply hardware and software. Also NI's hardware is great, best in the business. Their software is complete poop.
So, good news, there's a number of techniques for various aspects of this at a range of mathematical abilities. Might be able to make an informal, knock-off of one or more for your use case. The bad news is that I found more papers than I wanted to thoroughly read. Not filtering them myself. If you want, I'll drop you a link to an archive or links to individual papers for you to skim at your own pace. If not, that's cool too as I needed them in my collection anyway for high-assurance, asynchronous systems. Especially given all the uptake on async in mainstream.
So, it was great you replied with those details regardless. Might have inspired a future, bullet-proof system in an unusual instance of the Butterfly Effect. ;)
That'd be nice :D
For those wondering, stable just meant the API defined for interactions with some libraries were subject to change. It wasn't like a problem with using the APIs, it was just the developer has to know that new releases might change how they worked or if they would even be available in the future.
For network stuff I used openssl[0] and std::TcpStream [1]
I didn't use a GUI. I plan on using piston.rs[2] to build games but there are Qt, GTK+ and even Cocoa integrations for rust.
[0] https://crates.io/crates/openssl/
In terms of networking, I threw together a working console IRC client in about 60 lines of Rust (using standard library threads and TcpStreams). And I'm very much a Rust beginner. And Rust forced me to consider error handling in a way I wouldn't have otherwise.
I should also say that the community is unusually supportive: I've asked some questions on the IRC channel and got really helpful replies (and haven't noticed any of the snark that comes with a lot of IRC channels).
irc client: Everyone's least favorite Gtk project. For whatever reason, at one time there were seven active projects to develop a Gtk irc client. Used to deride poor judgement in choosing projects or lack of knowledge about what's going on. Often used self-deprecatingly, as in "I know, I'll write an irc client."
Thanks for keeping the dream alive.
An IRC bot is a great way to learn a new programming language. You have to learn how to use threading or asynchronous operations to get multiple connections, you have to learn how to use TLS for secure connections, you have to learn how to manipulate strings, how to read configuration files. It's a super good project for learning.
I use Rust for web as REST API and I'm absolutely in love with this language. Maybe first steps were little bit steep, but it's worth it :)
// cargo run!
[dependencies.iron]
version = "0.2.*"
[dependencies.bodyparser]
git = "https://github.com/iron/body-parser.git"
[dependencies.redis]
git = "https://github.com/mitsuhiko/redis-rs.git"
[dependencies]
router = "*"
rustc-serialize = "*"
plugin = "*"
rand = "*"
toml = "*"
rust-crypto = "^0.2"
hyper = "*"
r2fa = "*"
urlencoded = "*"
regex = "*"
[dependencies.mysql]
default-features = false
features = ["socket"]
And soon here will be added "rusoto". [dependencies.redis] git = ...
is the same as [dependencies] redis = { git = ... }
This will let you have just one [dependencies] block, which is a bit nicer looking. I've been changing examples to use it instead of that older style; they're equivalent if you prefer it though.I'd also note that while theoretically restricting versions works, in practice having multiple versions of a single crate within a rust project often leads to build failures due to crate A having a public API that uses types from crate B, and crate C using both, but not getting the same version of B that A got. This leads to type errors at build time.
> I'd also note that while theoretically restricting versions works, in practice having multiple versions of a single crate within a rust project often leads to build failures due to crate A having a public API that uses types from crate B, and crate C using both, but not getting the same version of B that A got. This leads to type errors at build time.
This is a problem, yes, but focusing on it by itself is somewhat of a red-herring: if A doesn't restrict B's version there's no guarantee that A compiles against whatever version of B that happens to be chosen, i.e. you don't even get to the point where there could be problematic interactions.
In any case, there has been serious discussion about how cargo can solve the problem of crates exposing other crates in their API, and the current proposed solution is to make cargo more strict about allowing multiple versions of such crates. #2064 is the relevant issue.
For now.
Furthermore, you can use a no_std library with an application that uses std just fine. The use case not quite covered is "I want an application with no standard library at all, period."
What two specific items? By "lang item" here, do you mean roughly "symbol", or something else entirely?
The two lang items that are absolutely required but not defined in core are 'eh_personality' and 'panic_fmt'. Read more here: http://doc.rust-lang.org/nightly/book/no-stdlib.html
$ cargo new example --bin
$ cd example
$ cat > src/main.rs
#![no_std]
fn main() {}
^D
$ multirust run stable cargo run
Compiling example v0.1.0 (file:///home/steve/tmp/example)
error: language item required, but not found: `panic_fmt`
error: language item required, but not found: `eh_personality`
error: aborting due to 2 previous errors
Could not compile `example`.
In general a "lang item" is some portion of Rust that the language expects to be defined in some manner. They must all be defined for compiling to work. `libcore` defines many of these language items, but does not for these last two. `libstd` does.You can provide your own:
#[lang = "eh_personality"]
extern "C" fn eh_personality() {
}
#[lang = "panic_fmt"]
fn panic_fmt() -> ! {
loop {}
}
These are enough to get going, but actually using `#[lang]` requires a `#![feature]`, which requires nightly.You also end up needing #[start], which is also behind a feature gate. The documentation brson linked you to contains an example no_std executable.
That flag you refer to exists, it's #![feature].
I'm glad now libraries are at least supported, which is good enough for my purpose (linking done with gcc, no idea if that's still state of the art for rust-on-stm32 or what), but it had been an annoyance. But I believe procedural macros are still in the same boat.
Somewhat tangential, this is the kind of blind spot encouraged by the rustup.sh degeneracy.
EDIT: sorry, it seems I've mis-read you. I get it now. Unfortunately, we have a strong compatibility story, and so must take strong measures to enforce it. You can use the nightly released on the same night to get a build that's like a particular stable, but allows features.
Breakage from forwards-incompatibility isn't my problem, it's potentially having to tackle it every morning rather than in batch mode when there's a new release.
edit: If this compatibility story really dictates that releases can't contain beta features, even with a #![unstable_beta_features_1_6] directive, then a separate beta release would be nice. But now it looks like I'm asking for something additional.
I'm not looking to get the rats on my face and switch to butt-based development ala rustup/multirust/etc.
Oh, cloud-to-butt, will you ever stop delivering the fun? I hope not.
It sounds to me like the real issue here is that procedural macros aren't stable, not anything about the release process.
Wanting hard-to-stabilize features like procedural macros and no_std.
Using external dependencies that work with stable, but when used with unstable they expect you are updating nightly.
Not updating nightly due to a wacky idea that people should control tools and not vice-versa. The first time I open a project in a week is not the time I want it to fail compiling due to language/library changes.
Maybe my impression is caused by the previous rapid change of nightlies (renaming in libraries, etc), and using month-old snapshots wouldn't be too bad these days. But still after several major releases I'd hope the stable tarballs would have been suitable for general use.
Instead of removing not-yet-stable features, they should be put behind a feature gate. With the idea that anybody who explicitly opts-in to unstable features and then complains when they're not forward-compatible can simply be told to pound sand.
By complaining that when you update nightly you have to update your code that uses unstable features, you are in effect asking us to stabilize everything. Unstable means unstable.
> ith the idea that anybody who explicitly opts-in to unstable features and then complains when they're not forward-compatible can simply be told to pound sand.
This never works in practice. We'd have too many crates that depended on nightly features. There would be 10x the number of complaints here on HN if we did what you suggested and enabled unstable features on stable. The only option would be to de facto stabilize everything.
Again, it really sounds like your complaint is just that procedural macros aren't stable. I'm sorry they've taken longer than you wanted to finish, but we have lots of work on our plate.
This isn't it. I feel like, when using unstable, that I've had to update packages that would not have needed updating were I using stable (and still would have worked fine). Maybe I just got a bad impression and switched away from nightlies around the time wider-demanded features started to stabilize.
> Again, it really sounds like your complaint is just that procedural macros aren't stable.
No, this really isn't it. I fully expect that code using unstable features is going to require changes when I update. I think the root of my gripe comes about from intermediate versioning being punted to "just run nightlies", meaning that rather than being able to reference older versions of packages that work with my compiler version, I'm effectively forced to upgrade and create breakage in my code right then.
> I'm sorry they've taken longer than you wanted to finish, but we have lots of work on our plate.
Please take whatever time is required to get them "right". And thank you in general.
I believe I added a dependency that wouldn't compile with the snapshot I was running (10JUL2015?). So then I updated to a new snapshot (14AUG2015?), and a previous dependency would no longer compile (since it hadn't been updated). I think this could have been due to libc changes, which I guess were marked unstable (and this was the result of them being removed from the main rustc distribution?). I did some manual tweaking, and/or the problem fixed itself in a few days.
I next came back to rust a few months later, where after that experience, I went ahead and updated to the 1.4 release. I figured libraries should generally aim to keep working with numbered releases, regardless of the upgrade treadmill. I guess (in your framework) that's applying unstable expectations to numbered releases, which is what I've been doing this whole thread - I don't care that code will break at future point, but I do desire consistency in the meantime!
I was next surprised to find out that the syntax extensions for eg serde were used completely differently with the numbered releases because procedural macros were disabled (I hadn't yet touched my own projects that use procedural macros or libcore).
The snapshot story is probably better these days, given that libraries should be more stable. It has always been annoying feeling like my rust is continually "out of date" and dependencies could break and require me to update, involuntarily breaking my code. This has been a problem all along, and I had hoped it was over with numbered releases. Alas.
From my perspective the main source of pain is that rust eschews having traditional numbered unstable releases. Instead creating a harsh dichotomy between uber-stable releases and uber-changing snapshots. One can alleviate some of that pain only if they're willing to take the web 2.0 give-up-control-of-your-computing plunge and run eg rustup.sh, which of course helps the fundamental problem to persist. Granted, the problem will be moot as rust libraries become more stable and the stable distribution becomes more featureful. We're apparently just not there yet for my purposes.
If one is onboard with the butt model of constant updates, then of course my problem looks odd and self-imposed. But such assertions that one's own perspective is universal is a source of many of the world's problems.
No, I think the point is to just have a specific unstable that corresponds to a specific stable as closely as possibly, and designated as such., Conceivably crates that needed unstable features, but not bleeding edge, could require at least that unstable release, while others that really need bleeding edge features could use nightly. The issue here is that your release procedure treats unstable features differently than everything else, making any crate or code that wants to use any unstable feature resort to using a nightly of some sort. Admittedly, I can see reasons why this might be by design.
You might have good reasons why you think that won't work or be useful (I can think of a few, such as not wanting to promote people building on a specific implementation of an unstable feature). At a minimum, it is at least slightly more work to make sure this new item is released, depending on the release process.
P.S. The prevailing wisdom so far when wanting to use unstable features from a point release is to use a nightly form the same day, but the release policy seems to indicate that the nightly from that time is actually two release versions ahead of the stable that was released the same day:
> This process happens in parallel. So every six weeks, on the same day, nightly goes to beta, beta goes to stable. When 1.x is released, at the same time, 1.(x + 1)-beta is released, and the nightly becomes the first version of 1.(x + 2)-nightly.[1]
I'm a bit unclear on what the best thing to do would be if I wanted to use features from something that is as close as possible to a particular stable release.
Unfortunately, the crates.io system does not follow the same policy, and crates regularly require feature flags.
The problem was that the config is compiled into a dynamic library and gets passed the config struct. The old alloc method kind of died on me when the dynamic library was trying to alter that struct. So I had to enable jemalloc to keep it from crashing.
However a few key platforms have jemalloc disabled because it's buggy (deadlocks or worse). I think as of a few days ago it's pretty much universally off on windows.
Also whether jemalloc is used depends on how you build your thing -- dylibs use the system allocator (because they're subordinate), static libs (rlibs) inherit from the thing they're linked into, and executables use jemalloc (because they're in control).
https://crates.io/crates/rusoto/
Haven't tried it yet (backwaters don't usually look kindly on AWS :) ), but that looks like what you're talking about. There are a ton of libraries for Rust these days (relative to the amount of time since 1.0, at least).
Anyways, thanks for Rusoto. It's going to make a project I'm starting next month significantly simpler!
Here are some recent posts by Nick on his experiments and progress (in order of publication):
* http://www.ncameron.org/blog/macro-plans-syntax/
* http://www.ncameron.org/blog/procedural-macros-framework/
* http://www.ncameron.org/blog/libmacro/
Pretty much all of his recent blog posts are on the topic, so it's worth browsing through all of them if you're interested.
(For those not familiar: the libc crate went from 0.1 to 0.2. Many people were depending on libc="*". Cargo allows for multiple copies of a library with incompatible versions. But the releases were incompatible for a reason... it caused problems. This fix is one of the things we're doing to address it, there's more coming in the future.)
The Rust standard library feels so much more modern and easy to use than the STL. The documentation is fantastic, too.
C++ pointers, casting, OO, templates, and all the billion other language features feel like traversing down a rabbit hole. Rust is small enough to grok in a day. The syntax is incredibly expressive and a joy to use.
I would say it is far easier to learn how to write good systems code in Rust than C++, but saying you can grok it in a day is a bit optimistic. On the surface level, perhaps. But the semantics of the type system can take longer to internalise, depending on one's background.
Rust does have a lot of features, but for most programming often you don't have to dabble in the more advanced features, which is great. Whilst working on Servo I mostly stuck to the basic features which I was familiar with for a long time and only learned the complicated stuff after a few months out of interest.
One major difference is that Rust forces you to learn about ownership and borrowing up front. This is cognitive load you would have to take in any systemsy language at some point when learning about memory management, Rust just makes you learn it early.
Don't forget your & in your function declaration or you'll silently copy objects.
Don't forget to make your destructor virtual in your base class (don't forget to add it if the class wasn't originally going to be a base class!) or you get fun crashes on delete every once in a while.
Use "explicit" with your one-parameter constructors to avoid fun with automatic conversions.
std::string is practically useless
Use "." with classes/structs/references and "->" pointers (why am I the compiler?!)
Think you know what "a = b;" does? Think you know what the =,==,!=,<,>,^,,+,-,/,=,+=,-=,/=,^= operators do? Not unless you checked to see if someone override them!
Ever tried to read some code that uses templates?
If you declared Class(int x) and Class(char x) and then do Class('a'), it silently gets constructed with the integer version (or maybe it's with Class(const char x), can't remember, which should say something right there.)
Quick, what does "const int const x;" mean?
Quick, what does "int* a, b;" do, and is that what you expected?
Is it safe to do "a = b"? You don't know until you read through all the class hierarchies to see if the object has a pointer, and if so, if it has an assignment operator that works properly ("properly" being somewhat relative to the purpose of your object).
Fun times debugging stuff like
if (...)
statement1;
statement2;
Can you call a virtual function from a constructor? Which version of C++ are you using?I have a soft spot in my heart for C++, but boy is there a lot to remember, and the mistakes/typos can kill a good half-day, minimum. I'm excited for the day I have a project I can use Rust on, looking forward to something I don't have to be always on my guard with!
> Don't forget your & in your function declaration or you'll silently copy objects.
I think this still exists in Rust to a limited extent but it's mitigated:
* Rust uses move semantics by default, so unless the type was specifically marked as Copy[0] it will be moved into the function which should be noticeable
* references are actual types, `&Foo` can't be confused with `Foo` and (outside of method receivers) references are created explicitly, so the callsite knows whether it's passing a reference
> Don't forget to make your destructor virtual in your base class (don't forget to add it if the class wasn't originally going to be a base class!) or you get fun crashes on delete every once in a while.
Rust has almost no inheritance support, and the realms of static and dynamic dispatches are pretty well separated (trait objects are dynamic, the rest is mostly static) so that should not be an issue.
> Use "explicit" with your one-parameter constructors to avoid fun with automatic conversions.
Rust has very little implicit behaviour (auto-deref is the main one I think), and I don't think it has implicit/automatic conversions.
> std::string is practically useless
Without more information as to its failing, I can't say whether String (and &str) is more useful. IME it certainly is useable and useful.
> Use "." with classes/structs/references and "->" pointers (why am I the compiler?!)
Yup, this is done through auto-defer (of types implementing the relevant trait of course), though it does have a separate `::` for other context.
> Think you know what "a = b;" does? Think you know what the =,==,!=,<,>,^,,+,-,/,=,+=,-=,/=,^= operators do? Not unless you checked to see if someone override them!
Can't override assignment itself, you can override other operators[1] and there is an accepted RFC for overloading augmented assignments[2]. Though these overrides are trait-based which should limit the shenanigan space somewhat.
> Ever tried to read some code that uses templates?
Rust's generics are slightly simpler, but they're lacking features (no template specialisation currently) so… not sure.
> If you declared Class(int x) and Class(char x) and then do Class('a'), it silently gets constructed with the integer version (or maybe it's with Class(const char x), can't remember, which should say something right there.)
See item above, the very declaration doesn't exist in Rust, you'd need to have two separate factory functions.
> Quick, what does "const int const x;" mean?
Should be clearer in rust, type declarations are fairly regular.
> Quick, what does "int* a, b;" do, and is that what you expected?
I think that's equivalent to `int* a; int b`?
Type information is an optional postfix addendum in Rust, so the ambiguity doesn't exist, but if you want explicit types you don't get the convenience of shortened declaration. The closest to this code would be
let (a, b): (Box<u32>, u32)
which isn't much of a gain over let a: Box<u32>;
let b: u32;
if you're not unpacking an existing structure> Is it safe to do "a = b"? You don't know until you read through all the class hierarchies to see if the object has a pointer, and if so, if it has an assignment operator that works properly ("properly" being somewhat relative to the purpose of your object).
See above, assignment itself can't be overloaded (at least at the moment)
> Fun times debugging stuff like
I think the only places where braces are optional in Rust are non-ambiguous 1-expression lambdas (`|| {expr}` can be written as `|| expr`) and 1-expression match arms e.g.
match foo {
v1 => { expr1 },
v2 => { expr2 },
}
can be written match foo {
v1 => expr1,
v2 => expr2,
}
> Can you call a virtual function from a constructor?Rust doesn't have constructors so no. As for the intent, since Rust doesn't have constructors you can't have partially built values (unless you forcefully partially build them) so the answer should still be no.
[0] http://doc.rust-lang.org/std/marker/trait.Copy.html
> I've never done anything with Rust […] I expect they have done away with a whole lot of C++ complexity
and trying to show whether, where and how rust had done so on the various examples provided.
So, it allows you to have safety and control. I thought that is very neat.
I've got three questions for experts. One, what type of applications is Rust intended for?
Two, I like JS because I can code in the client, and server in one language. Will there ever be a web server framework for rust and an api that allows me to modify the dom?
Three, what are your predictions for the future of rust?
2. There are already several web frameworks, in various stages of earliness. See [1]. I don't think it will ever be a good idea to write Rust client-side though (even though I believe there is an emscripten backend for it, so it's possible).
3. I see a very bright future for Rust. It could use some ergonomic improvements (but it's miles ahead of C++ even now, mind you), but is otherwise a very well designed language that fits very snuggly in its niche. And it has some very strong backing from Mozilla. I expect it will slowly take over large amounts of territory from C++ and possibly from C, as these developers start to realize the benefits of Rusts safety guarantees. It's also quite unique in that its safety entices many higher-level (python, ruby, C# etc.) developers into trying system programming, which could be really transformative to the system programming scene. For example, one thing that has already come out of this is the cargo package manager, which is similar to npm, bundler etc. but (before cargo) had yet to find its way down to the lowly systems programmers. Many (former?) C++ developers actually tout it as one of the major benefits of Rust.
Do note that, for many things on the web, JavaScript is PLENTY fast. It's when you are doing crazy things like CAD in the browser, it'll be amazing.
I have several crates providing access to GPIO/SPI/I2C under Linux and would like to put together a roadmap for having the interface to these types of devices that is portable to various platforms and devices (e.g. Linux as well as Zinc, ...).
The native thread/connection model quickly shows its limits, and is very slow on virtualized environments.
mio is as low-level as libevent and just as painful to use.
mioco and coio are very nice but blow the stack after 50k coroutines.
But for web services? I think it is overkill. I think Go strikes a nice balance. I would love to be convinced otherwise though. So please tell me, what am I missing?
- no need to copy-paste code for generic algorithms
- proper dependencies management