It took a bit of time, but finally
fsync is available in
From a user perspective it’s a pretty simple iOS client for
syncthing. If you never heard about
syncthing and you ever needed a self-hosted Dropbox you should give
it a try. It’s very nice piece of software, it runs almost anywhere
(Linux, *BSDs, Windows). It’s open source and written in Go so if you
want to practice Go language – you’re welcome to
fsync works in mostly “read-only” mode, i.e. you can view
files, you can delete them, but there is no way to edit. This is gonna
From a technical perspective it’s probably one of the earliest iOS applications, which are partially written in Rust.
There is a lot of things to talk about and I hope to provide more technical details in the following posts, while this one covers using Rust as a language for mobile development from my experience.
How it started
syncthing user I was missing opportunity to access my
files from mobile and decided to write an iOS application.
Initially I’ve started writing core code in C, got a first working prototype and understood that I’m spending too much time dealing with managing memory, ownership and so on. I’ve checked available options:
C++ was dropped immediately – I haven’t written in it since university, it changed a lot… and I wouldn’t like to invest my time into it, even if gives more advantages in short-term.
While technically it was possible to use Objective-C, it’s not good
enough for low level stuff and there is a lot of low-level stuff in
Swift looked very promising, but it was so immature that even Apple “fanboys” were against choosing it for any serious code.
The problem I saw was that although there is an official Android
client, it’s basically re-packaged
syncthing. Which means it wasn’t
written with mobile in mind, where being memory/traffic/battery
friendly is crucial.
You get were I was heading – I’d be happy to have a cross-platform code written for mobile. And the only option in this case was Rust.
There were moments when I hated Rust – it was a hell of a ride to the API stability. Initially it didn’t feel like a big deal (“ohh, that’s just a couple of changes here and there”). But… Little strokes fell great oaks and a couple of times I was on the edge, considering to rewrite it again in C (or C++ – yep, it’s a huge monster, but it’s also a well known + stable monster).
One of the hidden problems caused by instability was a desire to keep breaking surface as small as possible. Practically it meant ignoring existing libraries and re-inventing half-baked versions just to have a control on when and how to update it.
It was a dark time and I’m glad it’s finally over.
While language and std lib are stable now, there is still a huge necessity in a better documentation. A lot of changes have happened with no announcements and no discussions so if you were always on GitHub, monitoring issues everyday – you’re probably fine. But if you weren’t because you had to write your own code – I bet a lot of that code is already “rusty” and cries for modernization.
What was bad
At some point I was very disappointed, but I have to admit it was caused mostly by wrong expectations and naive estimations.
- I didn’t expect it’ll take so long to stabilize.
- Rust can give you exceptionally granular control of memory allocations, but it’s a manual control. You’ll pay with a longer development cycle, you’ll pay wit much more complex code and less flexibility.
- Rust is slow to compile and that discourages a lot, especially if you’ve got a minute to hack on an old laptop and… Boom… Half of the time is wasted in wait for compiler. More than a minute for building ~7K LOC? Yeah, I know it’s an old laptop, but that’s hardly an excuse, considering Clang can handle much bigger codebase faster.
- Code-management tooling (navigation/refactoring) is immature. This should improve over time with language stability, but I can’t imagine how long it will take to get something like AppCode/CLion.
As you can see only last 2 reasons are related to the language itself and I hope that at least compilation time will be addressed in upcoming 1.1 or 1.2.
What was good
Before Rust I’ve been developing in higher level languages for quite a long time. As a result, there were a lot of things I didn’t even consider – they were hidden, the choice was already made for me. The first impression after using Rust was “ohh, there are so many things I have to decide on my own now!”.
For me personally it was a refreshing experience and also a reminder that there is no way to get performance if you don’t keep it as a primary goal all the time.
Probably more than the language itself I liked the direction it takes in encouraging good engineering practices – you get built-in testing/benchmarking support and a pretty decent documentation generator. Want to go further? Mix them – and you’ll get a bullet-proof documentation, which will fail your tests if you’ve forgot to update it after an API change.
And yet there is also Cargo for
getting repeatable builds out of various dependencies. Std lib was
significantly reduced on the way to 1.0 due to
cargo. What was not
necessary or was controversial was extracted out of tree to a separate
That gut feeling of rock-solid foundation becomes even stronger after
familiarizing with Rust’s development process. In short – there is a
bot, which runs tests on approved pull requests and merges into
master only on success. Sometimes it’s annoying, sometimes it’s
slow, but you’re sure that at any point of time nothing is broken2.
One of the most interesting questions is if there is a place for Rust in iOS development.
In most cases if you’re developing for iOS/OS X – you’d better use Objective-C and/or Swift. They provide much better integration with native frameworks and higher level to work on.
Still, Rust can shine when:
- you need a cross-platform code
- you target to have a very low footprint
- you can either isolate code enough or provide automatic bindings to/from “native” code
I’d say that the last one is the real bottleneck.
A lot of iOS/OS X frameworks have a pure C interface3, 4 and therefore can be used from Rust directly5. In general it’s easy enough to access Objective C objects either6, but it’s hard to exploit that without loosing portability. So… you can’t move things down to Rust7 – you have to provide smoother interaction between “core” and “UI” by other means.
When Dropbox started cross-platform C++ development, they had the same problem and they solved it8 in Djinni – an automatic binding/proxy generator which bridges native code with cross-platform code. If someone writes a generator for Rust – it can make a huge difference9.
Another way to workaround this problem is to have a pretty isolated
Rust core, which acts as a server and can be accessed through a
well-known protocol. It means there will be additional costs,
definitely higher than automatic data marshaling performed by
Djinni. Whether it is acceptable or not depends a lot of data flow
in the application.
As a conclusion – unfortunately for mobile cross-platform development Rust is pretty limited nowadays and works good only for specific use cases. A bright side though is that it’s a limitation which can be addressed by tools.
crate is a synonym for a package↩
unless you’re out of luck and provide by yourself support for a platform which hasn’t official buildbot.↩
CFFoundationfor example provides access to all native data structures.↩
with the only exception for platform-accelerated APIs.↩