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.

Written on May 20, 2025