Swift Experiments
Swift looks really good - strong-typed, the API makes sense, first-class support for native, and now you can develop in Linux as well. The disadvantage is that the produced binaries depend on Swift being installed, which means that you need to install Swift wherever you plan to run your binary. This blog shows how to install and develop Swift on Ubuntu 25.04 aarch64.
Installing stuff
To start with Ubuntu 25.04, simply install Swift via apt:
$ sudo apt install swiftlang binutils-gold
The best way to develop in Swift is to use an IDE. You have three options:
- Using Intellij IDEA with the Swift plugin. Works quite well but limited: e.g. the
autocompletion stops working in
extension{}
. Paid. - Using VSCode with the Swift plugin. Works better than IDEA’s plugin, but can be a PITA if you’re not familiar with VSCode.
- Using XCode (MacOS only). This offers the best experience but requires MacOS.
To install install IDEA, run the following command; IDEA community edition is enough:
$ sudo snap install intellij-idea-community
Afterwards install the Swift Support plugin by Joachim Ansong.
The plugin doesn’t support navigating to certain classes (e.g. you can’t navigate to Foundation classes like String), but you can navigate to classes from your dependencies and the autocompletion works quite well.
To use VSCode follow this tutorial.
If you’re on x86-64, you can install vscode via snap (sudo snap install code
);
on arm64 you’ll need to download the deb package
then install it via sudo dpkg -i
.
Getting Started
You can follow the Building a Command-line Tool tutorial to build and run a basic CLI app.
Running
Open the terminal in Intellij and run swift run
. You can also create a run configuration
in IDEA; a “Shell Script” works best:
- Execute:
Script text
- Script text:
swift run
Press Ctrl+F10
to run the app.
Troubleshooting
If you get this error while running swift build
or swift run
:
error: link command failed with exit code 1 (use -v to see invocation)
clang-15: error: invalid linker name in argument '-fuse-ld=gold'
Make sure binutils-gold
is installed on your machine.
Working with files
Reading a file is easy: main.swift
:
import Foundation
print(try String(contentsOfFile: "foo.txt"))
print(try FileManager.default.contentsOfDirectory(atPath: "/home"))
Kotlin Koans, Testing, Example project
See the Swift Experiments example app which demoes a Swift project which builds on Linux and MacOS, on Swift 5.10 and uses XCTest framework for tests.
About the language
Swift have several features which make it remarkably close to Kotlin:
multi-line strings, strings with interpolation, types (Int
, UInt
, etc),
optional types (Int?
).
The lack of GC is a bit of a bummer, but the reference counting hopefully makes
up for it, and reference counting makes more sense in embedded environments such as
phones, arm SOCs and Apple Watches.
I don’t get the exception mechanism: all the try
/try?
stuff, and that you need
to add throws
to all functions… Yes, stack unwinding is expensive but exceptions
are thrown sparingly in Kotlin program, so it’s an acceptable penalty. Also,
why fatalError()
when you can just bubble the exception out of main()
?
If I only use fatalError()
(no try/try?/throws
) and try!
(when calling something
that throws
), this prints the best stack trace on failure but won’t call defer{}
blocks.
On the other hand, using try
+throws
everywhere feels excessive and dumb.
Java exception mechanism and Kotlin’s use{}
is far superior.
guard
looks weird: I like Kotlin’s way of simply using the ?:
operator more:
val foo = "25".toIntOrNull() ?: return
more than Swift’s
guard let name = Int("25") else { return }
Also, when I’m implementing Sequence
, why can’t my struct simply implement Sequence<Foo>
but instead I have to type in typealias Element = Foo
within the struct body?
On the other hand, I quite love that a class can implement Strideable
and have automatic support for range iteration; Hashable
is also great idea
which forces the structure to be explicitly marked to be eligible for Set
or
Dictionary
.
Also, how cool is that I can implement sum()
on a list of all numeric types, just like this:
extension Collection where Element: AdditiveArithmetic {
func sum() -> Element {
reduce(Element.zero, +)
}
}
Conclusion
Do I like Swift much more than Go, C, C++, Objective-C, Rust? Hell fucking yes - simple to use, familiar and sensible language syntax. More than Dart? Yup - native binaries consume less memory (todo citation). More than Kotlin/Native? Now this is tough. At the moment, probably yes - Kotlin/Native file support is barebones, and Kotlin/Native binaries can’t be built on arm64. More than Kotlin/JVM? Nope - JVM is rock-solid and offers so much; but it’s unfit for really limited embedded (anything that has less than 128mb of memory).
Also, Swift makes me appreciate Java tooling much more: IDEA’s Java plugin is top-notch compared to Swift’s plugins; also navigating to Swift built-ins doesn’t reveal their sources for some reason. Compare to Java - you have full sources for everything, right from the beginning.