
Ask HN: Rust or Swift for system programming? - rustyrose
I&#x27;ve been looking at system programming languages. After years of web development with higher-level, dynamic, slow languages, I&#x27;d like to learn a language that is fast and suitable for system programming. Because let&#x27;s face it, you aren&#x27;t going to write a key-value database, web server, or the next docker in Ruby.<p>I considered C, C++, Go, Rust, D, and Swift. I liked Rust and Swift the most.<p>Rust is a bit nicer, I admit, but Swift feels more high-level. Taken in a vacuum, it&#x27;s 50-50 for me.<p>However, languages don&#x27;t live in a vacuum. Swift has the added benefit of opening up a whole world of possibilities in the Apple ecosystem, not to mention readily available jobs. Because of this, I&#x27;d be inclined to invest in Swift rather than Rust.<p>My question to you is, will I miss out? Are there classes of applications that are much better suited for Rust? And I mean in practical terms, not in a theoretical, both are Turing complete way.<p>Because of my impression of the languages, I mentally classify Rust as lower level than Swift, and as a result I, probably mistakenly, tend to think that maybe Swift is still too high level for system programming. But performance wise they appear to be equivalent.<p>I want to make sure I&#x27;m not overlooking something and dismissing Rust in favor of Swift too quickly.
======
JoshTriplett
Rust is _capable_ of lower-level programming than Swift; it's designed as a
systems programming language capable of doing anything C can. It doesn't have
a "runtime", and doesn't do any background processing like garbage collection,
but still has automatic memory management, a fairly unique property among
languages.

If you specifically want to write iOS and OSX apps, especially GUI apps, that
ecosystem and its libraries melds well with Swift. It's definitely more
appealing than Objective C. Swift's ecosystem seems primarily focused there,
even though Swift is capable of other uses.

If you want to write cross-platform applications, services, systems, or
libraries, try Rust.

------
joshavant
I've done a small amount of work for a Swift-based project that was packaged
as CLI program. FWIW, it was a really difficult project to develop for.

This mainly had to do with the fact that the project had to be built from a
hacky Rakefile, not Xcode. This was because Xcode would embed the Swift
runtime only into an .app or .ipa file (because projects need to be shipped
with the same Swift version used to build it, thanks to lack of ABI
stability). But, as a CLI tool, there was no .app bundle - only a single
executable. One downfall.

So, now that you're not using the Xcode IDE to build + run the project, you
can't use the debugging IDE tooling in Xcode, making the development process
that much harder. Another downfall.

I haven't checked if this has been fixed in recent builds (this all happened
back in January), but figure that these are the kind of issues you're going to
encounter, until the Swift language is a little more stable + proper tooling
evolves.

That said, it seems pretty clear the future is Swift, so it would be better to
start building experience with it sooner rather than later!

------
fsloth
Otherwise I would suggest C++ but from what I gather it's really hard to learn
to use it in a vacuum without triggering all sorts of footguns (i.e.
unnecessary pain - speaking as a person who has written C++ for a decade).
Rust's documentation looks really nice.

Look at this page:

[https://doc.rust-lang.org/std/collections/](https://doc.rust-
lang.org/std/collections/)

Not only does it explain what the data structures do, it also contains pretty
solid architectural guidelines on when it makes sense to use them.

Also, Rust supports Windows (which is a high percentage of several markets),
whereas Swift apparently, only unofficially (not an expert here, please
correct me if I'm wrong).

I really would not pick a language that does not run effortlessly on all three
major home computing platforms at this day and age unless the constraints are
really well understood.

------
bjz_
Swift abstracts away lots of memory management concerns by defaulting to
thread-safe reference counting. Rust defaults to the stack and allows you to
choose between a wide range of memory management options, and even build your
own if necessary. Rust therefore gives you a great deal more room to move, and
is much more flexible as a systems programming language.

That said, Swift is a nice language, perhaps cleaner looking in syntax
(although I prefer expression-oriented languages), and integrates nicely with
the macOS/iOS ecosystems. I wouldn't say it's 'higher level' \- Rust's upper
bound on expressiveness is around the same - but it does hide away lots more
of the minutia of thinking about how you manage memory.

~~~
millstone
One way in which Swift is higher-level is in its support for dynamic
constructs. For example, Swift allows you to dynamically check protocol
conformance (e.g. in generics). I believe Rust does not allow this.

~~~
Manishearth
> Swift allows you to dynamically check protocol conformance (e.g. in
> generics)

Could you explain more? Do you mean that Swift lets you arbitrarily downcast
between protocol objects?

I think Rust lets you do this too to some degree with Any. We generally stick
to static bounds, though.

I'd love to see if swift does something extra, and if it would be possible to
add to Rust.

~~~
millstone
You can cast in any direction amongst protocol objects, concrete types, and
generic types. You can also dynamically inspect the type itself (without
needing an instance of it).

For example, say we wish to write a function that builds an array from an
arbitrary sequence. But as a fast path, if the sequence is already an array,
just return it:

    
    
        func makeArray<T:SequenceType>(from values:T) -> [T.Generator.Element] {
            if let alreadyAnArray = values as? [T.Generator.Element] {
                return alreadyAnArray
            } else {
                return Array(values)
            }
        }
    

or we can use a Golang-style technique to dispatch to a more specific
protocol. See for example how debug descriptions are generated by checking
conformance to a series of protocols in turn [1]:
[https://github.com/apple/swift/blob/1e2d192b61c9003d8b8a8593...](https://github.com/apple/swift/blob/1e2d192b61c9003d8b8a8593c2ef0fa6a524b8c0/stdlib/public/core/OutputStream.swift#L375)

My understanding is that this is more limited in Rust, though I'm not too
familiar with how Any works - please correct if I'm wrong.

~~~
Manishearth
With Any you can downcast to concrete types, but not to other trait objects.
There is no fundamental reason why this shouldn't be allowed AFAICT though, so
we might be able to add it. You can currently double-box things to do it, and
probably write a library that makes this easy, but it's much nicer to have the
language do it efficiently in cases like this.

I wasn't aware that you could do that in swift, that sounds quite powerful and
useful!

------
Jerry2
> _However, languages don 't live in a vacuum. Swift has the added benefit of
> opening up a whole world of possibilities in the Apple ecosystem, not to
> mention readily available jobs. Because of this, I'd be inclined to invest
> in Swift rather than Rust._

Rust & Swift are fairly similar but Swift has a much wider range of possible
applications. Swift is also moving very fast (that's to be expected since it's
backed by one of the most valuable companies on Earth).

This is the primary reason why I picked Swift over Rust for a project I'm
working on (I'm working on an open-source password key store for high-volume
services).

~~~
pcwalton
> Rust & Swift are fairly similar but Swift has a much wider range of possible
> applications.

Can you elaborate on this? The languages seem very different to me--Swift is
garbage collected (reference counting being a form of GC), for example.

~~~
Jerry2
> _Can you elaborate on this? The languages seem very different to me--Swift
> is garbage collected (reference counting being a form of GC), for example._

ARC is not garbage collection [0]. Swift doesn't have a separate processes
managing memory during the runtime. In Swift, compiler analyzes the code
during the static compilation pass and inserts release/retain code during the
_compile time_. See this SO answer for more info [1]. And you don't have to
use ARC if you don't want to [2].

GC in Java or Go or CLR, for example, is completely different. Obj-C 2.0 was
garbage collected but Apple hated it because of GC pauses and they vowed to
remove it and never use GC again. [3] Hence, they developed ARC.

[0]
[https://en.wikipedia.org/wiki/Automatic_Reference_Counting](https://en.wikipedia.org/wiki/Automatic_Reference_Counting)

[1] [http://stackoverflow.com/a/7894809](http://stackoverflow.com/a/7894809)

[2]
[https://developer.apple.com/library/ios/documentation/Swift/...](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-XID_88)

[3]
[https://en.wikipedia.org/wiki/Objective-C#Garbage_collection](https://en.wikipedia.org/wiki/Objective-C#Garbage_collection)

~~~
MichaelGG
ARC is a form of GC, but the definition doesn't matter. Why do you say this is
a wider range of applications? Swift's ARC no doubt slows it down and makes it
unsuitable for some applications, right?

~~~
winstonewert
Is Rust's borrow system also a form of garbage collection?

~~~
steveklabnik
It is not, unless you count some library types that add reference counting,
but those are rarely used. Ownership and borrowing are calculated at compile
time, not runtime.

~~~
winstonewert
Ownership and borrowing may be calculated at compile time, but they still
result in code being inserted to do things like deallocate objects at run
time. It doesn't seem a useful distinction to call one garbage collection and
the other not. Swift and Rust are far more similiar to each other in their
memory management scheme then either is to Java or Go or D.

~~~
pcwalton
> but they still result in code being inserted to do things like deallocate
> objects at run time.

We're not talking about whether the user manually calls free. Even C has
automatic memory management (via stack/activation records) by that definition!
The difference is whether the memory management is worked out statically, at
compile time, or runtime, via tracing and/or reference counting.

~~~
winstonewert
Actually, yes, I think a lot of people would define automatic memory
management as not having to manually call free.

C does manage some memory automatically. But it leaves a lot of memory
management up to the user, such that any non-trivial C program will manually
manage memory. That's different from Rust, Go, Java, or D in that most
programs in those languages will not need to do that.

------
pcwalton
Swift is GC'd and has a large runtime. (Reference counting is a form of
garbage collection.) Rust is manually memory managed and effectively has no
runtime.

The languages are very different.

~~~
millstone
Swift uses reference counting for reference types, but emphasizes value types.
Rust supports reference counting for certain types, but emphasizes value types
too.

Also observe that Rust's drop flag is a form of (1-bit) reference counting.

In this particular area, they are more similar than different.

~~~
Veedrac
Rust's drop flag is quite different because it's local. Most pointers are not
reference counted in Rust, whereas they are in Swift.

Similar perhaps, but not that similar.

~~~
millstone
Which pointers? Here's all the different pointers I know of in Rust, and their
equivalents in Swift:

Rc/Arc <-> class types

Raw pointers <-> UnsafePointer/UnsafeMutablePointer

References <-> inouts

Trait objects <-> Protocol objects

Box <-> indirect enum (arguably)

Did I miss any?

Of the core language features, protocol objects are the only case where Swift
uses reference counting and Rust does not.

~~~
pcwalton
Swift doesn't have the borrow checker, which means that in order to ensure
safety the expressiveness is _really_ limited unless you use RC. That's why
essentially all Swift code uses RC, and Rust code rarely does.

There's a big difference between technically having manual memory management
and having it actually widely used and practical.

~~~
millstone
Yes, RC is the primary way to safely manage lifetimes of reference types in
Swift. You can drop down to unsafe constructs to avoid RC overhead, and I
sometimes do that in hot loops.

Using unsafe to improve performance is not unfamiliar in Rust either, though
Rust gives you better tools for building safe abstractions around it.

Shared ownership is routine in UI programming - think event handlers, etc.
These are the apps most commonly written in Swift. Does Rust avoid needing
shared ownership for these types of apps? If so, how?

------
Strom
There is no single correct answer as it always depends on a huge amount of
variables, many of which are in constant flux. You yourself will almost always
have the most accurate information to make a decision what's best for you.
Spend a year with Rust and a year with Swift. Then you'll be at a far superior
position to choose which one of those to invest more years in, or to look for
a third language. Which one to choose first? It doesn't matter, flip a coin if
the decision is difficult.

Learning many languages/frameworks/styles will make you a better programmer
than just investing decades into some supposed unicorn. Peter Norvig has a
great post on this called Teach Yourself Programming in Ten Years. [1]

[1] [http://norvig.com/21-days.html](http://norvig.com/21-days.html)

------
chriskrycho
Shameless plug that is _directly_ related to the question: if you want a
fairly detailed look at the two side by side, I've been comparing them as I
work through learning both over the last 10 months.
[http://www.chriskrycho.com/rust-and-
swift.html](http://www.chriskrycho.com/rust-and-swift.html)

I think, because of the automatic reference counting, that your overall sense
is roughly right—Swift is a _little_ higher-level than Rust—but their overall
ability to write many kinds of applications will be similar (Apple platform
applications being the big exceptions for obvious reasons).

------
agmcleod
Swift would be a good choice for job viability if you wanted to move over to
iOS after exploring systems programming. In the systems world, C is probably
the best choice in terms of systems programming. Personally I really like
Rust, and more companies do seem to be picking it up. If your goal is really
to just learn something, and potentially make something. More so than any
other job prospects in the future, than I say choose what you like the most.

~~~
bjz_
> If your goal is really to just learn something, and potentially make
> something

Yeah - Rust will most likely make you think more differently about programming
than Swift will, and will give more scope in terms of systems programming. The
advantage of Swift is that it simplifies things more, but that comes at a
cost.

~~~
Manishearth
I will point out that for people used to languages like C++, Java, Python, JS,
Ruby, or Go, Swift and Rust are both pretty good choices here.

I mean, while Rust may make you think about ownership and memory management
when programming (I have found this useful in all languages), both languages
have a great type system and IMO learning to work with those is a far greater
learning experience. So while Rust may teach you more, it doesn't teach you
_much_ more.

On the other hand, if you come from Haskell or something, the type systems
aren't what you're looking for :)

------
notriddle
Swift _is_ more high-level. That's not an accident: Swift is designed to write
the front end of an interactive application, while Rust is designed to build
the back end thereof. But if you're coming from dynamic languages, Rust's
biggest talking-point advantage over Swift is how easy it is to integrate Rust
with other systems.

Rust doesn't have "special integration" like Swift does with Cocoa, but it
will talk to anything that will talk to C. Which is basically everything. It
will talk to Java's JNI (including Android NDK), it will talk to Ruby's MRI,
it will talk to CPython, it will talk to Node, and I can even integrate Rust
with Swift. [It's pretty much just a matter of converting the function
declarations and asking to have your project compiled into a C shared
library.]([https://doc.rust-lang.org/book/ffi.html](https://doc.rust-
lang.org/book/ffi.html)) ("rust-bindgen" and "rust-cheddar" automate this)

------
broodbucket
"you aren't going to write a key-value database, web server, or the next
docker..."

I don't consider any of those things to be "systems programming". Any language
with a GC is utterly unsuitable for systems programming. If what you're
actually looking for is somewhat performant application programming, then
languages like Swift and Go become an option again.

------
andrepd
C or C++. One thing is how you want the world to be, another very different is
how the world _is_. I want to live in a word where a nice language like rust
or nim is the best choice for systems programing. But sadly, in our world, in
2016, the best choice is for many many reasons to go with a tried and tested
tool like C or C++.

------
falcolas
If you want to write systems programs, I'd probably focus on the programs you
want to write first, and then pick out a language in which to write them -
based on the features required and the community support you can gain.

Sure, you may be capable of writing device drivers in Swift, but how much help
are you going to get while doing so? How much help will you need? Will it be
picked up and used by the community at large? Do any of those matter to you?

Base your language choice off the project, not vice-versa. Remember, Docker
was written in Go, zookeeper in Java, and Rails (a web server as well as a
framework) in Ruby.

------
shams93
It depends upon what you're interested in developing for. If you're a pure
linux developer swift is not as exciting as rust. Just the fact that you need
a bunch of Apple kit to fully enjoy it is a downer. WIth rust I can hack on my
$35 pi3 box without having to go buy an ipad.

------
MichaelGG
Does Swift force GC (via AutoRC)? That might lower its utility as a systems
language and should have a performance penalty that Rust does not.

~~~
millstone
Both Swift and Rust use reference counting in different ways.

Swift uses reference counting for all reference types (classes), but idiomatic
Swift encourages using value types over reference types when possible. The
chief reason to use a reference type is when you need shared ownership. Value
types are not reference counted, though they may contain RC'd fields.

Rust has reference counting implemented in a library (Rc and Arc), which is
what Rust programmers reach for when they need shared ownership. Rust also has
a 1-bit reference count called the drop flag, which is used to dynamically
determine when an object's destructor should run.

~~~
pcwalton
The drop flag is not a reference count. It is an implementation detail, and we
could eliminate it if we wanted to.

Swift's value types are less flexible than those of Rust because of the need
to maintain soundness in the presence of aliasing and mutation.

------
piotrjurkiewicz
Neither.

------
ebbv
I really like writing in Swift. To be honest I am strongly considering looking
for jobs writing in it even though I have a great job, just because I want to
write Swift.

