notes-computer-programming-programmingLanguageDesign-prosAndCons-rust

" Go and Rust are not really competing. There may be some overlap in domain, but they occupy different niches and will likely appeal to different crowds. Go will appeal more to people who prefer its focus on conceptual simplicity and its "opinionated" nature (very much like Python). Rust will appeal more to people who prefer "functional" trimmings (algebraic datatypes, pattern matching, liberal use of higher-order functions, Scheme-style macros) as well as folks fed up with C++ who aren't willing to give up complete control over memory and performance characteristics. The fact that both languages are built around a similar concurrency model is just convergent evolution.

'

"

shanemhansen 117 days ago

link

Go actually provides what I believe to be zero cost abstractions that map straight to the c memory model, making it very easy to use for systems programming.

If you want a fixed size array of bytes, for for it. Zero overhead. If you want a slightly smarter list you can use a go slice, which is also pretty low overhead. I've personally verified that if I create a struct in go it takes up the exact same amount of memory as the same c structure.

As a concrete example, I recently built an interface to kernel crypto apis using pure go (no cgo). There's no magic to go data structures, you can define structs in go and pass pointers directly to syscalls (through the syscall package) and everything just works. Dealing with large arrays of binary data is similarly straightforward. So go does give you complete control over memory layout if you choose to use it.

The elephant in the room is that go does have garbage collection, and that ain't free. Practically you can minimize it's impact by managing your own memory. In fact that's what Brad Fitzpatrick is doing with his go based memcached implementation.

It all boils down to how you define systems programming. I guess if you mean is go suitable to write a kernel in, the answer is probably no, (but it would sure be fun to try). If systems programming requires having the complete ability to interact with the operating system and all syscalls + tight control over memory layout, then maybe go is the way to go.

https://github.com/shanemhansen/gocryptodev/

[edit]

with respect to python and garbage collection, did you know you can actually turn it off? If you have no cycles in your program you can turn off gc and let the ref counter clean up all your data, similar to Objective-C's ARC.

http://docs.python.org/library/gc.html


pcwalton 117 days ago

link

There is a lot more to zero-cost abstraction than memory layout. If you do manual memory management in Go, then you get no safety. It is also difficult to use the standard library with manual memory management. Furthermore, interfaces in Go are not zero-cost; you incur virtual dispatch whenever you use them.

The article is about doing safe manual memory management. That's something that's unique to Rust. "

"

Rust is not particularly object-oriented; idiomatic Rust code leans more toward the functional style as opposed to the OO style.

The language is designed to make it harder to write buggy code at the cost of some amount of language complexity. Whether this is an acceptable tradeoff will depend on your particular situation. "

---

" On the Rust side, algebraic data types, an AST macro system, saner tuples, non-nullable and immutability by default. I'm a bit skeptic about the different pointer types and how they will interact with meta-programming.

On the D side, many good things like unittest(), best-in-class overloading support, compile-time everything, etc.

http://laser.inf.ethz.ch/2012/slides/Alexandrescu/2-D%20course%20parts%201%20and%202.pdf

"

---

"

cmccabe 117 days ago

link

Rust has three different ways of allocating memory. And you can't pass things allocated one way to functions that expect something allocated the other way.

A Python replacement, this ain't. More like C++ on quaaludes.


pcwalton 117 days ago

link

No, Rust has two ways of allocating memory (on the task heap or on the exchange heap), and most functions take borrowed pointers, which accept both kinds of memory.

(Edit, re below reply: It depends how you define "allocation"; it's either two or three. I wasn't considering the stack as allocation, but you're right that Rust takes the traditional stack/heap distinction and expands it to stack/exchange heap/task heap. We should update the tutorial to make it clear that borrowed pointers work for the stack as well as both heaps.)

I agree that the language is not designed to be a Python replacement, however. No language is suitable for every task.


cmccabe 117 days ago

link

from http://dl.rust-lang.org/doc/tutorial.html

"7.3 What to be aware of

Rust has three "realms" in which objects can be allocated: the stack, the local heap, and the exchange heap. These realms have corresponding pointer types: the borrowed pointer (&T), the shared box (@T), and the unique box (~T). These three sigils will appear repeatedly as we explore the language. Learning the appropriate role of each is key to using Rust effectively."

It's 3 different types, not 2.


eevee 116 days ago

link

Rust statically prevents leaks and double-frees, warns about implicit copies of large structures, and has GC built in if I want to use it. It's certainly more familiar to a Python dev than C++. The whole trait system is even like a built-in and vastly simpler zope.interface. "

---

"

kibwen 117 days ago

link

I'm sure that Go has higher-order functions, I just mean that Rust encourages you to use higher-order functions all the time. For example: in Rust, `for` loops desugar to higher-order functions (it's very neat, actually). Furthermore, whereas in Go you spawn a goroutine with the `go` keyword, spawning a task in Rust is done by handing a function (usually a Ruby-esque closure) to the `task::spawn` library function. (Note also that "higher-order functions" are not the same as "first-class functions".)

Go does not have pattern matching, to my knowledge, though without algebraic datatypes I don't think it's really a big deal. "

---

" He never specifically said it's C++ nor Java. I think he's talking about C++. C++'s slow compile problem has to do with the repeated inclusion of header files for every source file, which can become a FileNum?^2 recompilation problem. Though pre-compiled header files and refactoring into pre-built libraries should reduce the compile time. Java simply does not have the slow compile problem due to its simple package/class per dir/file, where a compiled class won't be recompiled again. "

--

a gazillion times in the discussion https://news.ycombinator.com/item?id=6417319 , various people (or maybe one person over and over, i didn't check) claim that although Go isn't a good C++ replacement, Rust might be

--

upvote

derefr 23 hours ago

link

Sounds like D would be better-compared to Rust, then.

reply

upvote

pcwalton 23 hours ago

link

Rust has safe manual memory management, at the cost of a learning curve. In D you must use the garbage collector if you want memory safety, but it avoids all the complexity of lifetimes and uniqueness. This difference makes the two languages feel pretty different, even if at their core they're pretty similar.

reply

upvote

luikore 12 hours ago

link

D is more like C++ without macro and with GC plus some engineering features (unit test is a language feature? weird). Rust looks different and does different. For example, idiomatic foreach block in Rust is a syntax sugar of passing lambda, which is more friendly to parallelism. While in C++/D it is a syntax sugar of classic for-loop with iterator, which is more efficient in unparalleled environment.

reply

upvote

WalterBright? 11 hours ago

link

You might thing that unit test as a language feature is weird. But our experience with it is that minor-seeming weird feature has been an enormous success.

It has literally transformed writing D code, and for the better. There's another little feature, -cov, which will tell you which lines of code are covered by the unit tests.

It's hard to understate the improvement these engender.

reply

upvote

dbaupp 7 hours ago

link

> For example, idiomatic foreach block in Rust is a syntax sugar of passing lambda, which is more friendly to parallelism

This changed with the recent 0.8, `for` is now syntax sugar for using the Iterator trait, which optimises exactly like C++ (the vector iterator even vectorises when LLVM can do it).

Rust has actually moved to have iterators that are very similar to (a subset of) D's ranges.

reply

---

kibwen 5 hours ago

link

A selection of some of my favorite aspects of this release:

1. The (yet-ongoing) removal of managed pointers, leaving us with one fewer pointer type. Final tally of built-in pointer types: unique pointers, mutable references, and immutable references.

2. The dead code detection pass (https://github.com/mozilla/rust/pull/10477), contributed by a student of the University of Virginia's Rust-based systems programming class (http://rust-class.org/pages/using-rust-for-an-undergraduate-...).

3. The `Any` trait, giving us on-demand dynamic typing (https://github.com/mozilla/rust/pull/9967).

4. The clean abstraction of green threads and native threads out into their own libraries (https://mail.mozilla.org/pipermail/rust-dev/2013-December/00...) such that any library that makes use of the stdlib will work regardless of which strategy the user selects.

We're not quite in the home stretch yet, but there are very few hard blockers left on 1.0. Here's the list that I can think of:

1. Dynamically-sized types (http://smallcultfollowing.com/babysteps/blog/2014/01/05/dst-...)

2. The extension of rvalue lifetimes (http://smallcultfollowing.com/babysteps/blog/2014/01/09/rval...)

3. Struct single (note that's single) inheritance (http://smallcultfollowing.com/babysteps/blog/2013/10/24/sing...)

4. Niceties and sugar to support custom smart pointer types to complete the excision of managed pointers

As far as I know, the devs are still aiming for a 1.0 release in 2014. The 1.0 release will not necessarily mean that the language is done evolving or ready for production use, but it will mean that the developers will begin honoring language-level and library-level backwards compatibility. I would expect at least two more unstable point releases (i.e. 0.10 and 0.11) before a 1.0 release occurs.

--

vorg 18 minutes ago

link

> normalized to Unicode normalization form NFKC

I'm wondering why they chose NFKC (compatibility composed from) instead of NFC (canonically composed form).

`ª` would become `a`, losing its super type. `ᵤ` becomes `u`, losing its sub type? `Ⓐ` becomes `A`, losing its circle type. As for multi-codepoint mappings, `¼` would become three tokens `1⁄4`, where `⁄` (U+2044) doesn't map to `/` (U+002F).

--

http://www.rustforrubyists.com/

--

pcwalton 2 hours ago

link

I'd say concurrency support is a big one: Rust rules out data races at compile time, eliminating the need for race detectors, while ensuring that you still have the full array of options when it comes to shared memory, locks, and so on.

reply

--

steveklabnik 4 hours ago

link

I am primarily a Rubyist, but I'm head over heels for Rust. I'm pretty sure I've inculcated wycats with similar feels.

You might be interested in http://words.steveklabnik.com/rust-is-surprisingly-expressiv... , which is sort of about this.

reply

bascule 2 hours ago

link

Ditto for me, but I came from a largely C background prior to Ruby

reply

--

bjz_ 5 hours ago

link

As always, drop by irc.mozilla.org #rust if you'd like to chat or ask questions. We're a friendly bunch!

http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23ru...

reply

Dewie 4 hours ago

link

OT: Is Rust using operator overloading? Is user-defined operators a possibility in the future? I googled it and the most I could find was this:

http://www.reddit.com/r/rust/comments/1le6vu/i_wrote_a_proto...

reply

kibwen 4 hours ago

link

Operator overloading, yes. But we place some restrictions on which types you can overload in order to keep things sane (oversimplified explanation: you must have declared the types yourself in order to overload operators on them). We also discourage the wanton overloading of operators to mean completely random things, as you might have encountered in C++.

As for user-defined operators, if you mean something like Haskell's custom infix operators then no, I don't believe there are any plans for those.

reply

JoshTriplett? 4 hours ago

link

> As for user-defined operators, if you mean something like Haskell's custom infix operators then no, I don't believe there are any plans for those.

Do the Rust designers actively oppose having them, or just not have any concrete plans to add them?

reply

kibwen 3 hours ago

link

Merely lukewarm, I think. There are simply much higher priorities to focus on at the moment. Who knows what Rust 2.0 might hold!

reply

Dewie 4 hours ago

link

I think that Reddit thread was interesting. The syntax is taken from Haskell, but someone brought up ditching precedence and only associating in one direction, which I guess is simpler than operator overloading(?)

reply

steveklabnik 4 hours ago

link

You want to check out std::ops http://static.rust-lang.org/doc/master/std/ops/index.html

reply

---

http://words.steveklabnik.com/a-30-minute-introduction-to-rust

---

As someone who has written a fair bit of Go code, I also find myself keeping a close eye on Rust. The things that really appeal to me are the possibility of immutable (by default) types, thread-local memory (ie. owned pointers), no null pointers, and generics. These are all basically aspects of the type system that make concurrent programming safer and more predictable.

--

http://jaredly.github.io/2014/03/22/rust-vs-go/index.html

--

on apple swift vs rust:

We're not scared in the slightest. I'll reconsider when Swift has inline ASM, allocators, linear types, move semantics by default, region analysis, and a type system that guarantees freedom from data races (oh, and when the code is open-sourced, and targets both Linux and Windows as a first-class citizen).

Swift isn't intended to be a systems language: it's an application language. Anyone who's capable of choosing Swift as of today was just as capable of choosing Objective-C yesterday. And as the Rust developers themselves have discovered over the past two years, deciding to become a systems language doesn't happen overnight.

--

pornel 16 hours ago

link

I hope ideas will flow the other way too, and Rust adopts some sugar from Swift.

I find `if let concrete = optional` sooo much nicer than `match optional { (concrete) => , _ => {} }`.

Rust has solid semantics that covers more than Swift. OTOH Apple has put their UX magic into the language's syntax. Some syntax shortcuts, like `.ShortEnumWhenInContext?` are delightful.

The two combined will be the perfect language ;)

reply

andolanra 10 hours ago

link

You could always write this yourself with a macro:

    macro_rules! if_let {
      ($p:pat = $init:expr in $e:expr) => {
        { match $init { $p => $e,_  => {}, } }
      }
    }
    fn main() {
      let tup = (2, 3);
      if_let!{(2, x) = tup in println!("x={}", x)}; // prints x=3
      if_let!{(5, x) = tup in println!("x={}", x)}; // doesn't print
    }

It's slightly more heavyweight, but still not too bad.

reply

--

[–]glaebhoerl 1 point 4 hours ago

If you don't care about low-level control (or even if you do), you might care about other things.

For example, my criteria for "doesn't suck" are something like:

    Statically typed
    Type-safe
    Type inference
    ADTs
    Closures
    Generics
    Type classes, or something similar
    No implicit nulls

Suddenly the arena is not so crowded.

    The sacrifices necessary to wrest low-level control have severe costs in other areas

Do you have anything in mind here besides explicit reference types and clone()?

    permalink
    parent

[–]kibwen 1 point 4 hours ago

If those are your criteria, then Haskell and Ocaml have already beaten us to maturity. Nobody who is currently using either of those languages ought to have any interest in Rust.

    Do you have anything in mind here besides explicit reference types and clone()?

Explicit lifetime annotations, closures that are nowhere near as general as in a dynamic language, explicit macro invocations, no canonical "dictionary" type, and our bountiful cornucopia of attributes. Not to mention the syntax concessions made to appeal to C++ users, which are all but a requirement to compete in this space.

    permalink
    parent

--

[–]jfagercontributor 25 points 22 hours ago*

At a glance:

Similar:

    Swift's protocols look somewhat like Rust's traits, which both look like Haskell's typeclasses.
    Both use Option instead of null.
    A lot of sameish syntax choices (type annotations come after variable names, braces, no parens around conditionals).
    Statically typed with local type inference.
    Bounds-checked arithmetic and array access.
    No/few automatic coercions.
    Forced initialization.
    ADT's via enums.
    Pattern matching.
    Generics.

Different:

    Swift doesn't have a concurrency story (or at least hasn't told it yet), Rust does (tasks, no data races, channels).
    Swift looks like it just uses stack allocation and Arc for memory management; Rust gives you much more control.
    Swift semicolons are optional.
    Swift uses separate keywords for defining value and reference types (struct vs class).
    Rust has macros; the Swift book doesn't mention any metaprogramming features.
    Rust is open source and already works on a bunch of platforms, Swift looks like its going to be proprietary and only work on Mac and iOS.
    Swift will automatically get massive adoption, Rust will have to compete on its merits.
    There's some pretty impressive tooling available for Swift out-of-the-box.
    permalink
    parent

[–]eddybsupercontributor 4 points 14 hours ago

Can we please use ARC when talking about "automatic reference counting" and Arc only for our "atomic reference-counted smart pointer"? Preferably, we should spell out the one that is less relevant to Rust.

    permalink
    parent

--

pornel 20 hours ago

link

Rust has `unsafe` blocks in which you're allowed to do all nasty hacks you want.

Rust actually isn't that complicated. Don't get discouraged by comparisons to Haskell — it's still a C-family language where you can play with pointers and mutable state.

To me Rust still feels like a "small" language (similar size as Go or ObjC?, not even scratching complexity of C++). It's mostly just functions + structs + enums, but they're more flexible and can be combined to be more powerful than in C.

reply

thinkpad20 19 hours ago

link

I think comparisons to Haskell are not too far off the mark. Haskell is not that complicated of a language either. You can do all sorts of complicated things with it, but the language itself is relatively simple. It just has a lot of stuff that you're likely to have never seen before (extensive use of higher-order functions, higher-kinded types, etc), and its type system produces error messages that seem obscure from the outside. Similarly Rust can have some rather obscure error messages that you're probably not going to have seen before during compilation - lifetime specifiers, errors about using things in the wrong contexts, heck, even "Bare str is not a type (what?)"

I'm much more familiar with Haskell than Rust, but having played around with Rust I think they're on a par with each other in terms of difficulty, depending on your background.

reply

--

dbaupp 15 hours ago

link

> You can easily generate a segfault in Rust in 'unsafe' (or 'trusted') code; that might only restrict errors of that nature to code that uses unsafe blocks, but practically speaking that's pretty common; once you enter an FFI unsafe block, you lose all type safety; but you can totally do it without FFI too. Eg. using transmute().

Not directly addressing what you're saying, but, IME people are far too quick to use `unsafe` code. One needs to be quite careful about it as there's a pile of invariants that need to be upheld: http://doc.rust-lang.org/master/rust.html#behavior-considere...

> once you enter an FFI unsafe block, you lose all type safety

You don't lose all type safety, especially not if the FFI bindings you're using are written idiomatically (using the mut/const raw pointers correctly; wrapper structs for each C type, rather than just using *c_void, etc).

reply

http://doc.rust-lang.org/master/rust.html#behavior-considered-unsafe

--

http://doc.rust-lang.org/master/intro.html

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

--

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

	An Experimental New Type Inference Scheme for Rust

---

http://smallcultfollowing.com/babysteps/blog/2014/05/13/focusing-on-ownership/

---

Bartosz Milewski Says:

September 20, 2013 at 1:30 pm

I don’t know much about Rust, but I noticed one thing: Like Erlang, it supports only one model of concurrency: message passing. That’s very limiting. Haskell actually lets you share memory in a very controlled way, which makes the implementation of STM possible.

---

[–]DrBartosz? 3 points 10 months ago

I'm concerned that Rust, like Erlang, only supports message passing style of concurrency. Message passing is relatively easy to make safe, but is not general enough and often leads to spaghetti code.

    permalink
    parent

[–]Tekmo 3 points 10 months ago

So do you prefer STM or did you have something else in mind?

    permalink
    parent

[–]DrBartosz? 2 points 10 months ago

I was thinking more of data-driven parallelism where you split a large array (or graph) between multiple workers. But there are, in general, many paradigms for concurrency and parallelism, and a general purpose language should support them.

    permalink
    parent

[–]sstewartgallus 3 points 10 months ago*

I'm actively trying to work on the non-message passing style of concurrency actually (in extra::sync, and extra::arc.) It's still quite ugly but I feel that Rust's type system will allow me to make it really pretty. Here's a sample that I hope to get working in the future (obviously a shorthand will be offered over the full RAII style using closures but the full RAII style allows really powerful techniques.)

 {
     let read_lock = rwarc.read_lock();  // The lock is acquired
     let x = read_lock.get();            // A readable pointer to the value is borrowed
     println(fmt!("%s", *x));
     // Here the lock is automatically released
 }

If anyone wants to help though that'd be awesome although mostly what's blocking progress is the long build times. Hopefully the rustpkg work will help to solve that. (Obviously, there will be convenience methods for directly getting values but the read_lock stuff will allow upgrading of the read lock to a write lock, or vice-versa.)

So, no Rust will not prohibit shared state concurrency (it just hopes to make it safer.)

Also there is no reason you won't be able to pass unsafe pointers around, and write your own concurrency library.

    permalink
    parent

---

scythe 302 days ago

link

Well, there is also the difficulty that there has not been, save Ada, a serious and concerted effort to replace C and C++ for so many of the things that they are used for. Except for Ada, no other modern language is suitable for writing things like kernels, drivers, emulators, etc; except for Ada, basically all modern languages are dependent on garbage collection.

So if you want to complain about C, remember that the only serious alternative is and has been Ada, and ask yourself why you're not using Ada, why operating systems and window managers, mupen64plus and Wayland, et cetera don't use Ada, and the truth is: people like C more than Ada.

Ada is the anti-C++. It's the answer to every criticism. It's also basically unheard of outside of situations where people really, really need safety cf. airline industry. In fact most of the people who complain about C++ would never even consider Ada. The author of the article seems to be unaware it even exists, which says a lot.

The takeaway is that safety is overrated, consistency is overrated, reliability is overrated, because if we really cared about these things... we'd use Ada. And we don't, because "Ada is annoying!".

---

" Rust let i = box 1234i;

C++ int *i = new int;

Rust infers the correct type, allocates the correct amount of memory and sets it to the value you asked for. This means that it's impossible to allocate uninitialized memory: Rust does not have the concept of null. " -- http://doc.rust-lang.org/master/intro.html

---

" First, let's go over a simple concurrency example. Rust makes it easy to create "tasks", otherwise known as "threads". Typically, tasks do not share memory but instead communicate amongst each other with 'channels', like this:

fn main() { let numbers = vec![1i, 2i, 3i];

    let (tx, rx)  = channel();
    tx.send(numbers);
    spawn(proc() {
        let numbers = rx.recv();
        println!("{}", numbers[0]);
    })}

In this example, we create a boxed array of numbers. We then make a 'channel', Rust's primary means of passing messages between tasks. The channel function returns two different ends of the channel: a Sender and Receiver (commonly abbreviated tx and rx). The spawn function spins up a new task, given a heap allocated closure to run. As you can see in the code, we call tx.send() from the original task, passing in our boxed array, and we call rx.recv() (short for 'receive') inside of the new task: values given to the Sender via the send method come out the other end via the recv method on the Receiver.

Now here's the exciting part: because numbers is an owned type, when it is sent across the channel, it is actually moved, transferring ownership of numbers between tasks. This ownership transfer is very fast - in this case simply copying a pointer - while also ensuring that the original owning task cannot create data races by continuing to read or write to numbers in parallel with the new owner.

To prove that Rust performs the ownership transfer, try to modify the previous example to continue using the variable numbers "

---

steveklabnik 3 days ago

link

Rust does not have any garbage collection, to be clear. All your other features are correct though :)

(We have previously said "opt-in GC" but that was a lie. See https://news.ycombinator.com/item?id=8312327 for more.)

reply

JoshTriplett?