return to table of content

Swift Static Linux SDK

palata
87 replies
1d21h

Additionally, a program built for a particular distribution, or even a particular major version of a particular distribution, would not necessarily run on any other distribution or in some cases even on a different major version of the same distribution.

Not sure I understand that. Is it something specific to Swift, or is it exactly what is expected from using shared libraries?

Say my Linux distribution distributes some Swift runtime, then the corresponding Swift packages should have been built for this runtime as well. Just like when my Linux distribution distributes a libc, the corresponding packages need to be built for this libc. Right?

Still, it's cool that Swift provides static linking. But like in any language, the best IMHO is when the Linux distribution can choose how it wants to distribute a package. I tend to like shared libraries, and already Rust seems to be interfering and imposing its preferences. I am happy if Swift doesn't.

e63f67dd-065b
74 replies
1d21h

It's just classic dependency issues. I'm not familiar with swift specifics, but probably a combination of ABI instability and just plain version incompatibility from one distro to the next with your target program.

My opinion is the opposite: I think the old paradigm of distros managing a giant set of system libraries is a bad one, and is how we ended up in the land of docker. Go and Rust made the right decisions here: vendor all the dependencies, and distros can't mess with them. Makes it easier for upstream and the distro.

Modern languages are not like C/C++: a single non-trivial rust program can easily depend on 100+ crates, and re-creating crates.io in your package manager is just a bad idea, even putting aside that there's probably major version incompatibilities the moment you go beyond a handful of programs. Look at the disaster that's python package management, that's not where you want to end up.

jiripospisil
29 replies
1d21h

Makes it easier for upstream and the distro.

Until there's a vulnerability in one of the dependencies and now you have to rebuild all of the packages which use it. Specifically for Rust, there's also the fact that most projects use a lock file and if your build process respects it, you now have to wait for the upstream to update it and release a new version (or update it yourself). And if your build process doesn't respect the lock file (or the project doesn't use it) and you just fetch the latest compatible dependencies at the time of build, you now have no idea if you're affected or not by the vulnerability because you don't have the exact resolved versions stored anywhere (https://github.com/rust-lang/rfcs/pull/2801).

josephg
27 replies
1d21h

Until there's a vulnerability in one of the dependencies and now you have to rebuild all of the packages which use it.

Packages get rebuilt all the time. This is fine.

As for the rest, it would be cool if binaries shipped with a manifest of some sort naming all the versions of their statically included dependencies. A SBoM of sorts. It would make this sort of vulnerability scanning much easier to do.

palata
24 replies
1d20h

It would make this sort of vulnerability scanning much easier to do.

Scanning, sure. Fixing... surely much harder than with shared libraries.

josephg
23 replies
1d20h

Only because the build tooling is less mature.

It should be pretty easy to programmatically update a lock file, run the tests, and rebuild a package. For rust crates that are compiled and packaged straight from git, you could probably automate that today.

palata
22 replies
1d19h

It should be pretty easy to programmatically update a lock file, run the tests, and rebuild a package.

You still fundamentally need to rebuild (or at least relink) and re-distribute all the packages, whereas with shared libraries... well you just update that one package.

kibwen
21 replies
1d17h

I hear the refrain "you'll have to rebuild your packages" a lot in these discussions, and I confess I don't see how this is a problem. Maybe it's a holdover from C and C++ veterans for whom figuring out how to build any given project is a Herculean effort, but for every other language with a first-class build system it's trivial.

amszmidt
16 replies
1d16h

Debian has about 59000 packages. Even rebuilding 1k of that is a significant pain on build infrastructure, specially in one go, if say a vulnerable library is found.

You also now get a huge set of users who will now download these 1k of updated packages. Not to mention the utter fun of trying to understand why your system just requires maybe 100 packages to be updated…

Compare to upgrading a single shared library.

eviks
7 replies
1d10h

Do you know whether someone has made an estimate based on the history of actual vulnerabilities of how much rebuilding would need to be done in a non-shared library approach?

amszmidt
6 replies
1d1h

Not to my knowledge. But consider something like crypto, libssl ... which is linked to almost everything, or libxz, zlib, etc. If there is a bug in a shared library, one can replace it with a interm one very easily, and the whole operating system will use it. One can even replace it with a different implementation assuming ABI compatibility, without having to do "much".

Enclaves like Go, Rust, Swift (things that insist on using direct sys calls, and eschewing system libraries) would need to implement their own versions, or use FFI, and then you're SOL anyway if you really insist to use static linking... And who knows what kind of bugs might crop up there that don't match whatever anything anyone else uses.

Shrug :-)

tracker1
3 replies
23h29m

For what it's worth, Rust uses libc by default in Linux.

On the other side, there are quite a few self-updating applications out there (browsers), and source control systems like Github will push notifications, and even pull requests for out of date dependencies. So pushing out a new version of a given application is pretty easy. If the application comes through Flathub or self-updates then it doesn't have to wait for the distro maintainers to get the update out.

palata
1 replies
21h8m

then it doesn't have to wait for the distro maintainers

No, but it has to wait for each developer of each binary individually. Instead of relying on a team of maintainer, you now rely on all the developers.

"Self-update" isn't something magical: someone has to do build the new version and ship it. With static linking you still have to build and ship for every. single. binary. With dynamic linking you just build and ship the one library that everybody depends on.

tracker1
0 replies
3h36m

Of course... and I'm not suggesting that every app in a linux distro should be as such. You can dynamically link with Rust, Go, etc. That said, for one of the 3-4 GUI apps that most people use, the distro process tends to leave people with relatively old versions missing critical bug fixes or features.

I tend to keep my host OS pretty bare, and most of my runtime apps in Flatpak and the stuff I'm working on in Docker.

amszmidt
0 replies
22h41m

That is a very, very tiny subset of things that are installed on any GNU or BSD system, and that need to get security fixes. Just recall the xz/sshd/system debacle, to patch your system all you needed was to replace libxz / libzma -- a DSO! This obviously ignores lots of other work -- but that work would have ballooned if standard practise was to statically link everything.

The amount of work spent finding usages of static linkage, and figuring out which version of libxz (or whatever it was called) just to be very sure that one wasn't using the compromised version was atrocious, no thanks.

cesarb
1 replies
23h1m

But consider something like crypto, libssl ... which is linked to almost everything, or libxz, zlib, etc.

AFAIK, the reason most Linux distributions have an allergic reaction to static linking is because of zlib. There was a vulnerability in zlib some time ago, and it required the distributions to find every single program which had its own copy of zlib (vendoring zlib used to be common back then), update these copies with the security fix (not necessarily trivial, since the vendored copy might be a customized variant of an older zlib release), and rebuild all these packages (which is a lot of "fun" when some of the packages are in a "failed to build from source" aka FTBFS state). The distributions learned their lesson back then.

amszmidt
0 replies
22h54m

The aversion to static linkage predates that, back many years static linkage also had other issues that have been solved today (ALSR ..). Many of the very basic points that Ulrich Drepper made some odd 20 years back (https://akkadia.org/drepper/no_static_linking.html) still hold.

kibwen
6 replies
1d15h

The distro repositories are being continuously rebuilt, because packages are receiving continuous updates. In the meantime, as far as I'm concerned dynamic linking is itself a security failure, because if I run a binary I want to know exactly what code is being run, without having to worry about dynamic linking and loading nonsense inserting itself into my process.

amszmidt
4 replies
1d13h

They aren’t being rebuilt with that kind of frequency as you might think.

They get rebuilt when a change in the package is made, not when a change in a dependency is made — which is a huge difference.

There are plenty of packages that might not get an update for a long time (month, half year, … whatever their release cadence might be).

Dynamic linking makes it _easier_ to handle security, including checking if your program is linking to a broken library — static linking does not have the same means.

Statically linked programs don’t mean you know what is being run either, you can always dlopen() and all kind of shenanigans like Go and Rust do.

What is a security nightmare is statically linked binaries, you have no clue what they are linked against.

kibwen
3 replies
1d5h

I'm against dlopen as well. If something makes use of LD_LIBRARY_PATH, rest assured that I want it excised from my system. Reproducibly-built, fully-static binaries are what I want, ideally with an accessible SBOM embedded.

palata
2 replies
1d1h

So all your binaries are statically linked on your system? 100%?

kibwen
1 replies
14h11m

That's the dream. I want a system that's 100% source-available, 100% reproducible, and 100% statically-defined. Nix looks like the closest thing to that right now.

amszmidt
0 replies
13h27m

I don’t see how Nix is close to your dream, Nix is just like any other system and links things like any other system.. I.e. mostly avoids static linking.

Debian did the strongest push for reproducible builds, and is 100% source available.

comex
0 replies
1d14h

The distro repositories are being continuously rebuilt, because packages are receiving continuous updates.

At large timescales, yes. But not at timescales relevant for rapid security updates.

tracker1
0 replies
23h33m

Most USERS only run a handful of applications any given month. I think upgrading 1-2 applications is easier to reason with over even a hundred packages.

palata
2 replies
1d5h

It really sounds like you see it from the point of view of a developer who has never thought about how a Linux distribution works.

Yes, for you as a user it's simpler to link statically and not learn about anything else. But distros are a bit more elaborate than that.

josephg
1 replies
21h54m

It sounds like you see it from the point of view of a disto maintainer and never thought about how awful the experience is for software developers. I want to just depend on some specific, latest version of a library. I don’t want to have to go look at which version of that library exists in 18 different Linux distributions. I don’t want to deal with bug reports because Debian patched one of my dependencies or replaced the version I depend on with something newer or older.

I’m happy for someone to update the version of my dependency if it has security patches. But the rest? A total nightmare. I’ll take cargo / npm / swift / etc style versioning every day.

palata
0 replies
20h52m

I don’t want to have to go look at which version of that library exists in 18 different Linux distributions.

If you make open source software, the solution is simply that you should not distribute your software [1]. Let distro maintainers do it, and suddenly it's a lot easier for you.

If you make proprietary software, then it's not exactly the problem of the Linux distros anymore so sure, feel free to link statically. I personally think you should do a mix of both: libraries like openssl you want to link dynamically from the system. Now some obscure dependency you may have that breaks compatibility randomly and is generally not distributed by major distros, probably you want to link them statically. But you should know that you are then responsible for them and the security issues they may bring (i.e. you should monitor them and update them regularly).

[1]: https://drewdevault.com/2019/12/09/Developers-shouldnt-distr...

LtWorf
0 replies
1d13h

For distributions, it costs a lot of money they don't have to just be rebuilding stuff all the time.

For randomly downloaded binaries from the internet it means you will most likely keep using it with the vulnerabilities for years to come.

dolmen
0 replies
1d20h

As for the rest, it would be cool if binaries shipped with a manifest of some sort naming all the versions of their statically included dependencies. A SBoM of sorts. It would make this sort of vulnerability scanning much easier to do.

Go binaries have that. You can apply "go version -m" to any recent Go binary.

Also "govulncheck".

Examples:

    go version -m $(which go)
    go install golang.org/x/vuln/cmd/govulncheck@latest
    go version -m $(which govulncheck)
    govulncheck -mode=binary $(which govulncheck)
    for b in $(go env GOPATH)/bin/*; do govulncheck -mode=binary "$b"; done

LtWorf
0 replies
1d20h

Packages get rebuilt all the time. This is fine.

You forgot to link the image with the dog sitting in the fire.

palata
0 replies
1d21h

I totally agree. Static linking is essentially easier for people who don't want to care. But ignoring security does not mean it solves it, on the contrary.

Static linking comes with a lot of issues, just like dynamic linking is not perfect. I really think it depends on the use-case, and that's why I want to have the choice.

palata
12 replies
1d21h

As you say, a typical Rust program can easily depend on hundreds of crates that nobody really checks. That's a security issue.

The whole point of a distro is that someone distributes them, so you can choose which distro you want to trust.

What I don't like about Rust and Go is that they enforce their preference. I am fine if you want to link everything statically. I just don't want you to force me.

kibwen
6 replies
1d17h

> I just don't want you to force me.

Rust supports dynamic linking, and has since well before 1.0.

palata
2 replies
1d5h

In practice, it feels like everybody assumes that Rust is installed through Rustup and dependencies are statically linked from cargo. I have tried going the dynamic linking way, it's painful when it's not impossible.

umanwizard
1 replies
23h33m

Regardless of what "everybody assumes", you can in fact build rust binaries without using rustup or cargo. Distros do this. Yes, it's more painful for end users than just typing `cargo build`, but that's irrelevant to distro maintainers.

palata
0 replies
20h50m

Some software (e.g. IDEs) will call `rustup` for some reason (yep, it happened to me and I therefore couldn't use that software).

Yes, it's more painful for end users than just typing `cargo build`

Cargo is fine, I don't mind installing cargo. I just don't want my packages to be handled by my package manager. I don't want every project to ship their own custom package manager like rustup.

glandium
2 replies
16h2m

That's kind of a disingenuous take. Rust supports producing dynamically loadable libraries. It doesn't support dynamically linking arbitrary dependencies, which is what most people would understand from "Rust supports dynamic linking" in a discussion about static linking.

kibwen
1 replies
14h13m

> It doesn't support dynamically linking arbitrary dependencies

I don't understand why one would think this. You make it sound as though Rust only supports dynamic linking for glibc, but that's certainly not true.

glandium
0 replies
13h49m

The keyword is "arbitrary". Say you have dependencies on reqwest and clap, want to dynamically link against them? Not gonna happen. That's what people talk about most of the time for static vs. dynamic linking, at least in my circles.

newZWhoDis
3 replies
1d18h

More software should “enforce” their preferences, many decisions are objectively superior and this “anything goes” attitude has done nothing but hurt OSS/Linux adoption.

Everything about the shared lib model is stupid, and has contributed to poor Linux market share to date.

lmz
1 replies
1d4h

Dynamic linking seems to work fine for Windows or OSX. Maybe it's open source + dynamic linking that's the problem.

palata
0 replies
1d2h

Honestly a problem is that most developers just don't understand how it works. Docker / static linking solves a lack of understanding, mostly. That's why they are popular.

palata
0 replies
1d5h

I couldn't disagree more.

Everything about the shared lib model is stupid

I don't think we can discuss if that's you're stance. But also I don't think you understand the shared lib model if you think like that.

akira2501
0 replies
1d20h

You're not forced to with Go. CGO exists and requires dynamic linking.

LtWorf
9 replies
1d20h

the disaster that's python package management, that's not where you want to end up

The one where the only sane option is using distribution packages or conda and ignoring anything that the python community comes up with?

j1elo
5 replies
1d19h

I had my Python and pip installed from distribution packages. One day I needed to build something from source, but it needed Meson...

Ok installed Meson also from my distro packages! But no, the project required a newer Meson version.

Ok let's install Meson with pip! But no, it turns out pip packages themselves can require a minimum pip version!! Go figure.

So I couldn't build that program without first pip-installing Meson, and I couldn't pip-install Meson without first pip-installing a more modern version of pip itself.

Guess how well it worked when I upgraded pip. Spoiler: not a smooth way to discover that Python packaging is a joke.

icedchai
4 replies
1d19h

Were you using a virtualenv? Or were you pip installing into your distro / system python, like a true savage?

j1elo
3 replies
1d19h

I just knew the basics. So I was just following commands from stack overflow or similar. Silly me, thinking that it would work logically like other languages do! Later I ended up learning about all that stuff with venvs and whatnot, not to mention it's not even a unified solution but there are multiple alternatives, adding to the confusion... All this, no doubt, is a consequence of how terrible the Python packaging story is. Rust, Go, Ruby, Node, and more, I had used without remotely similar hassles.

icedchai
2 replies
1d16h

You are right. It's not a good experience for new developers, especially given how long Python has been around.

j1elo
1 replies
1d8h

They are so close, though! I think one lesson Python took is that it's better, even mandatory, to use venv and install stuff in isolated containment.

This is exactly what Node/NPM does: "npm instal" creates a new dir, "./node_modules" and installs stuff there, and next "npm" commands will transparently refer to that subdir. This is, in effect, the same thing as a Python's venv! to the point that in my scripts I always name them "python_modules", to give other unfamiliar devs a clue of what it is.

If "pip install" just did this transparently, without introducing the whole concept of venvs to the user, it would be a huge step forward. I cannot imagine how it would suck if NPM didn't make its node_module dir, and instead it forced you to first learn all the idiosyncrasies of module isolation.

icedchai
0 replies
19h2m

Yeah, they should just define a new command line option (and perhaps a new command that defaults to this behavior, say vpip or vpython or something.) The virtualenvs take some getting use to. I've been using python for over 15 years so it's second nature.

icedchai
2 replies
1d19h

Have you tried "poetry"?

LtWorf
1 replies
1d19h

Yes. Having tried it led me to write that comment.

icedchai
0 replies
1d16h

I'm curious what problems you ran into with it?

OKThatWillDo
6 replies
1d20h

"vendor all the dependencies"

What does that mean?

PaulDavisThe1st
5 replies
1d16h

It means "add the source for your dependencies to your own codebase and build them with your build system".

OKThatWillDo
4 replies
19h27m

Thanks. Not an appropriate use of the noun "vendor," so I would never have guessed that.

OKThatWillDo
2 replies
15h41m

"Vendor" isn't the verb. The verb is "vend."

spacechild1
0 replies
8h48m

Did you read the link?

mkl
0 replies
13h32m

That's a different verb, with a different meaning.

umanwizard
5 replies
1d21h

Some distros do actually break out rust dependencies into separate packages (e.g. Guix does this). It's just that a lot of rust software isn't distributed primarily by distros.

jiripospisil
4 replies
1d21h

Fedora and Debian do this too. That's why it sometimes takes longer for a project to be packaged - you literally have to recursively package all of the dependencies first.

palata
1 replies
1d21h

Which is a feature, and not a bug: some of us want our distro maintainers to actually have a look at what they distribute.

prmoustache
0 replies
1d20h

Yes and it doesn't prevent anyone to build software separately, being written in rust or any other language.

NekkoDroid
1 replies
1d19h

Fedora and Debian do this too.

IIRC Arch does as well (or at least tries to).

jiripospisil
0 replies
1d9h

Arch does for quite a few ecosystems (Python, Ruby, Haskell, ...) but currently not for Rust.

PaulDavisThe1st
5 replies
1d16h

Modern languages are not like C/C++

I think there's a bit of a misconception here.

Ardour is written in C++ and depends on 80+ other libraries.

The dependency situation may be exacerbated by packaging culture that encourages the use of lots of relatively small dependencies, but it is by no means determined by language or even context.

palata
4 replies
1d5h

I started a small project both in C++ and Rust.

When in C++ I had 2 direct dependencies it resulted in 6 total dependencies (direct + transitive).

In Rust I had 5 direct dependencies (because some standard stuff is not in the standard lib) and it resulted in... 300 total dependencies.

but it is by no means determined by language or even context.

Not sure what you mean there. My feeling is that making it super easy to pull 50 transitive dependencies without realizing it does not help. If you have to manually handle every single dependency, first it forces you to look at them (that's a good thing), and second it encourages you to minimize them.

PaulDavisThe1st
3 replies
1d5h

My feeling is that making it super easy to pull 50 transitive dependencies without realizing it does not help

What is it that makes you think that C/C++ does not do this also?

[ EDIT: this also has something to do with the typical size and scope of C/C++ libraries ]

palata
2 replies
1d2h

What is it that makes you think that C/C++ does not do this also?

My experience. I haven't worked in a single C++ project that had hundreds of dependencies, but I encounter those regularly in Rust/npm.

PaulDavisThe1st
1 replies
1d1h

I would suggest that this caused more by ideas about the appropriate scope and scale of libraries in the 2020s than anything specifically connected to the language in use.

palata
0 replies
1d1h

I don't see that in Kotlin for instance.

lynndotpy
1 replies
1d21h

I feel the same. A huge part of the pleasure of Go and Rust are that I never run into dependency problems. I'm happy to pay the "Hello World is 4MB" tax.

LtWorf
0 replies
1d20h

And the "I now have to evaluate thousands of libraries instead of 10 well established framework" tax?

I've seen plenty of bad go libraries. For example their authors will be unaware of isatty() so they will output control codes when piped.

If you factor in the time to find a competently written library (and quite possibly write one yourself) it starts to be less convenient.

umanwizard
8 replies
1d21h

Dynamic linking works fine for software that is distributed by distros, but lots of software isn't.

palata
6 replies
1d21h

Sure. It's great to have the possibility to link statically.

My beef with the "static linking trend" is that many people (or languages, e.g. Rust) don't want to let me link dynamically, for some reason. Just let me choose!

tux3
5 replies
1d20h

But they do. They do let you choose.

Debian's build of rust packages are linked dynanically, for instance. It's a build setting, you can turn it on.

LtWorf
4 replies
1d20h

No, crates will be statically linked anyway in general.

kibwen
3 replies
1d17h

Rust supports dynamic linking, it's just not the default, so you need to configure a given crate to use it at build time.

LtWorf
2 replies
1d13h

Rust supports compiling each crate as a separate .so and then linking all of them?

That's not at all how debian packages written in rust are linked. So the person I replied to is incorrect.

I suspect you're incorrect as well and what you claim doesn't exist at all, but you're claiming a different thing.

umanwizard
1 replies
1d8h

Rust supports compiling each crate as a separate .so and then linking all of them?

Yes, by passing crate-type=dylib to the compiler.

whytevuhuni
0 replies
23h12m

Due to the lack of ABI stability, the resulting dynamic library is tied to the exact binary hash of the Rust compiler (which includes the dependencies rustc was built from).

Those dynamic libraries will also not remain ABI stable if their code changes (because Rust's semver specifically applies to the public API, but the public API is free to pass around structs with private fields, which may alter the layout drastically even for minor semver-compatible changes).

So this helps with some aspects (such as libraries being reused between binaries, reducing disk usage).

But it does not help with the issue most discussed in this thread: that of security updates (all libraries have to be rebuilt whenever rustc changes or a dependency changes, all programs (potentially the entire operating system) have to be redownloaded by all users, etc).

PaulDavisThe1st
0 replies
1d16h

For decades, Unix-y software has been distributed with dynamic linking made possible by the use of a startup script that also sets LD_LIBRARY_PATH (which means the dynamic linker will find the libs that come with the software in preference to system-provided ones.

manmal
1 replies
1d21h

A Swift program for a particular distribution will dynamically link some system libraries from the distro, and these libs might change on every distro update. They mention in the post that dynamic linking can cause versioning issues.

Say my Linux distribution distributes some Swift runtime

That runtime would need to be compatible with the Swift program. Nowadays that’s not a big issue due to ABI stability (https://www.swift.org/blog/abi-stability-and-apple/), but this would close the door on new features that need runtime support (need an OS update then, or the OS must come with multiple runtimes).

Longhanks
0 replies
22h28m

AFAIK they claim ABI stability only for Apple platforms, explicitly neither Linux, nor Windows. Has that changed?

mshockwave
0 replies
1d21h

Not sure I understand that. Is it something specific to Swift, or is it exactly what is expected from using shared libraries?

More of a shared library issue I believe.

Say my Linux distribution distributes some Swift runtime, then the corresponding Swift packages should have been built for this runtime as well. Just like when my Linux distribution distributes a libc, the corresponding packages need to be built for this libc. Right?

That's correct

jkelleyrtp
68 replies
1d21h

Swift 6 is amazing - I say this as a big Rust person. It seems like Swift is now its own entity outside the Apple bubble and has a few very interesting features:

- An "embedded" mode that turns off reflection for kilobyte-sized binaries

- An upcoming WASM target

- An LSP for VSCode

- Native C++ interop

- Typed "throws"

- Static linking on linux and the linux sdk

- Porting a number of "core foundation" / foundation primitives to nix platforms

- Distributed actors for concurrency that run on distant machines

- Data-race free by default

- non-copy RAII generic types

Watch the video on Swift 6: https://developer.apple.com/videos/play/wwdc2024/10136/.

IMO Swift 6 is a better Go and than Go, and a better Rust for app-dev type stuff, which seems to be what people want to use Rust for.

Swift has shipped stuff that Rust has been sitting on its hands over for years:

- Anonymous enums/structs in parameters/match statements

- Named function arguments

- A type of `Send` bound that allows Rcs to be sent between threads (not Arcs)

- Swift preview hotreloading

- autoclones (without GC)

Swift also took a bunch of goodies from Rust *[1]

- No garbage collector

- Traits via "protocol"

- ADT for Option/Result

- macros

- non-copy types enforcing RAII

I really really wish Rust had been keeping up with Swift's ergonomics because it's looking like Swift is going to catch up to Rust's cross-platform story much faster. Swift really could end up as the "do it all" language for frontend/backend/app dev.

[1] By "took" I mean if you like these things in Rust you'll see them in Swift

square_usual
15 replies
1d21h

Swift and Go are on polar ends of the language complexity spectrum. Someone who enjoys Go for what it is, i.e. a dead simple, straightforward language, would not see Swift as being "better".

jkelleyrtp
11 replies
1d21h

Some people want generics and ADTs in Go. If you're using go because it's

1) fast

2) expressive

3) concurrent

4) compiles natively

then I think Swift is the better of the two.

If you just want a very simple language, then sure, Go is there. But I don't think that's necessarily what makes Go, Go.

kbolino
6 replies
1d16h

Swift has its strengths against Go but it does not really beat Go at Go's own game.

Where are channels and select? Why is async code special? Why do protocols have to be explicitly adopted? Why are errors "thrown" instead of returned?

illusionyodel
5 replies
20h4m

The async question is actually really interesting - and gets at a few things Swift does very differently from some other languages.

Normal languages just sort of call functions on threads - and use locks when there is contention. You certainly can write the same sort of code in Swift - but that is not how async functions work.

The issue with locks is that waiting on a lock could be expensive - depending on the type of lock. And it also ties up the thread. If you have a thread pool you could end up with a lot of threads getting tied up in locks.

Async functions are suspendible. When they encounter a data hazard - the thread is released and allowed to go work on something else. When the conflict clears the function is picked back up and execution continues. Note: the way this is designed means that a _different_ thread may continue execution of the async function, and async functions should assume that they may change threads during execution. But this does prevent stalled threads just waiting on some condition. The compiler needs to extra notation to know your function has been designed around this sort of operation.

Basically: Async functions are not normal functions - they're allowed to be suspendible and may change threads mid execution - hence the extra notation. This improves both performance and safety.

kbolino
4 replies
19h8m

But that's the thing, we're comparing with Go, where all functions behave that way, and no async/await ceremony is required. Go has many weaknesses, but I don't think a language that treats async as unusual/special beats Go in that respect.

jkrejcha
1 replies
12h35m

This melding of the sync and the async is actually kinda interesting to me. I know that at least in lots of environments, the sync and async paths are effectively separate for things like I/O[1]. I wondered (and still do for some cases) how Go handles this.

For those curious I looked at Windows and Linux, but not much else.

Linux: no io_uring support. There's debate on even whether to use it as people are discussing security implications[2]. It looks like (from perusing this issue, but could be wrong) AIO wasn't used.

Windows: it looks like they're using IOCP everywhere. Seems sensible enough.

General case: there seems to be an open issue regarding this[3].

[1]: For example, Windows has IOCPs, Linux has io_uring, FreeBSD has kqueue, POSIX has... POSIX AIO, etc.

[2]: https://github.com/golang/go/issues/31908

[3]: https://github.com/golang/go/issues/6817

kbolino
0 replies
5h22m

Interesting. My understanding of how things get implemented is that all code runs essentially "async" by default, but the runtime scheduler can switch to running code synchronously when requested (runtime.LockOSThread) or necessary (e.g. "slow" calls to C via cgo).

I was not aware that file I/O isn't async on Linux. Even so, I'm pretty sure network I/O and channel operations (send/receive/select) are async via epoll. I'm not as sure about these, but I think time.Sleep and sync.Mutex.Lock suspend the goroutine as well.

developerDan
1 replies
14h11m

This is just a hunch but likely because of the application the two languages were originally designed for. Go is/was a purely backend lang (as I understand it) whereas Swift was built with the UI in mind which must be run on the main thread. So Swift has async/await for making clear boundaries between synchronous (aka UI) operations and asynchronous operations.

I’m am not well educated on the subject though so take that with a grain of salt.

kbolino
0 replies
5h26m

This is a good point. It's possible to use Go this way too, but it gets tricky. You can lock the main goroutine to its O/S thread with runtime.LockOSThread and then do the heavy lifting on other goroutines, sending messages back to the main goroutine typically using channels. Given Swift's lineage, this is probably more ergonomic there than in Go.

beanjuiceII
2 replies
1d20h

after using swift extensively i did not find it better of the two, in fact it is a complex keyword ridden language that seems bolted together at very many angles, each swift codebase i enter is like a new mystery to unfold because of its extremely rocky evolution

msie
0 replies
1d

Yes! Reading Swift code, even tutorial code, can be difficult.

Klonoar
0 replies
1d20h

One thing that bugs me to this day is reading Swift code without an IDE can be an exercise in “let me build up a mountain of context first”, due to the way enums and types can get shortened.

It’s nice to write but a pain to review. Meanwhile if I read Rust or Go, it’s more or less what you see is what you get.

I do agree in general that it’s frustrating that Rust hasn’t kept up with some of Swift’s pushes, but then again that’s the difference when you have the richest company in the world involved.

For context, I’ve written many apps in Swift, deployed a backend in Vapor, and worked with teams who use the language. I always thought I’d get over it but it just never fully clicked.

square_usual
0 replies
1d20h

I would say that yes, in fact, simplicity is characteristic of Go. That is clear from how the go team considers the impact of every new language feature, often choosing not to do things that would've been considered obvious in other languages. Many parts of the community still resent generics, and there is widespread backlash to the new iterators proposal. Most Go enthusiasts wouldn't be fans of Swift and vice versa.

arthur-st
2 replies
1d20h

I think it depends on the person. My anecdotal experience is that I'm using Go for hobby projects because with Python at my day job, I wanted a modern language with fancy-ish static typing. Additionally, I wanted it to be equally practical on Win/Mac/Linux, and to not run inside a VM.

The obvious first candidate was Rust, but the low-level features were unnecessary overhead. A "higher-level Rust" is literally Swift, but the portability is not there. The search basically ended here, so I went with Go as a consolation prize - I don't get a fancy type system to play with, but the development ergonomics, especially with the v2 modules system, are the best I've experienced yet.

manmal
1 replies
1d20h

Have you checked out the static linking option announced yesterday? Portability has increased a lot.

arthur-st
0 replies
1d11h

I have, and I am indeed very hopeful about the WWDC 2024-related Swift announcements. My comment was meant to illustrate my thinking circa a year or two ago.

christophilus
11 replies
1d21h

How’s the compilation speed?If it’s going to replace Go, that’s gotta be sub second for a medium sized project on my clunky old laptop.

coldtea
6 replies
1d21h

Why, would you care if it's a full second or even 5 seconds?

Go hyped their compilation speed a lot in its early years, but unless it's C++ templates level slugginess it's not like it's that big of deal.

plorkyeran
2 replies
1d18h

Swift compilation is slower than C++.

coldtea
1 replies
1d18h

C++ with heavy template use or C++ as glorified C-with-classes?

plorkyeran
0 replies
1d16h

C++ with heavy template use.

square_usual
1 replies
1d21h

Compiling fast has ripple effects throughout your workflow. Having your iteration time go from 1s to 5s is a massive difference: it can mean you break out of the flow state when you restart your server to test your code.

manmal
0 replies
1d20h

As someone dealing with Swift everyday (and, before that, faster langs like Elixir and Typescript), I can only agree. Sometimes my incremental builds take 20-30 seconds and it feels like a huge toll. Waiting on the CI (which is a weak machine) is up to 25 minutes until the test suite has passed - a large chunk of that being compilation time. Releases take 5-10 minutes.

I really like Swift, but I’d highly appreciate faster compilation times.

iainmerrick
0 replies
1d19h

Once you use a language where compile times are essentially invisible, it’s hard to go back.

josephg
2 replies
1d21h

Assuming my experience with Swift 5 is still accurate, compilation speed is at least an order of magnitude slower than Go.

It’s a much more powerful language. In my opinion slower compilation is worth it for all of its great features. (Does Go even have parametric enums?). But its definitely a trade off.

christophilus
0 replies
19h52m

Ocaml makes me wonder if we really do need the trade off. It’s a fairly advanced language, and compiles super fast. I wonder why it’s such an outlier among advanced languages?

MBCook
0 replies
1d19h

That’s the one big loss from moving off Objective-C. Because the language was so stupidly simple to parse and didn’t have a lot of “we’ll figure that out for you from what you wrote” it could be compiled incredibly quick on today’s machines.

I know they’re working on improving it. I’m glad they are. But that speed is something I definitely miss.

jkelleyrtp
0 replies
1d21h

Supposedly faster in Swift 6 but I don't have any big swift projects to throw at it. It uses LLVM so it's not going to be as fast as Go's.

In Swift 6 they:

- Improved parallelism via compilation pipelining (ie top-level object files are referencing not-yet-compiled symbols but can still proceed while those compile in the background)

- Parallelized and pipelined debug symbol generation (lazy debug symbols)

vips7L
6 replies
1d20h

- No garbage collector

ARC is a GC, and a slower one than most traditional tracing GC's.

MBCook
3 replies
1d19h

Reference counting and garbage collection are different.

They’re both forms automatic memory management, but they work in very different ways.

vips7L
0 replies
1d16h

No they're not. Reference counting is a garbage collection algorithm. Its even described as such in most literature on garbage collection.

pcwalton
0 replies
1d16h

Automatic memory management is a synonym for garbage collection. Reference counting is a form of garbage collection.

kibwen
0 replies
1d16h

Reference counting and garbage collection are different, yes. But in terms of classifying "no garbage collection" under "things that Swift took from Rust", Swift's pervasive reference counting is much closer to classic tracing GC than it is to Rust's system of single ownership.

mannuch
1 replies
19h48m

First of all, traditional (tracing) GCs require more expensive runtimes and consume much more memory. ARCs are also much more predictable in their behavior and pave the way for greater compile time optimizations. ARC is key in providing Swift its ability to maintain its low memory footprint compared to, say, Java.

Second, yes, ARC is a GC method. But when the language says "no garbage collector", they just mean no traditional (tracing) GC runtime because, for better or worse, tracing GC is what people think of when they hear "garbage collector".

vips7L
0 replies
16h53m

traditional (tracing) GCs require more expensive runtimes and consume much more memory

Not really no. Look at go, D, nim, or any ahead of time compiled language.

ARC is key in providing Swift its ability to maintain its low memory footprint compared to, say, Java

Again not really. Java has other issues. Like lack of value types, conservative escape analysis, needing extra memory for profiling and the jit, and HotSpot’s GCs are focused on server applications and are designed not to release memory until they’re about to run out.

Even if this were true ARC trades memory for execution speed. I can’t find the exact paper right now but the ixy implementations showed that you end up spending an unhealthy amount of time just counting references when you stay in pure swift code. I think it was somewhere > 30%.

e63f67dd-065b
5 replies
1d21h

I'm primarily a C++ developer these days, and if the C++ interop is actually good then I'm very excited for the future. For app-dev type stuff it really does seem like it's better than Rust, and I can definitely see a world where we start migrating some code into Swift.

Edit: back from watching the video, and a few observations:

- Swift does not suffer from Rust's refusal to add things into the standard library. gasp regex support in stdlib? Async/await runtimes?

- Default testing framework is a godsend, especially when integrated into the build system

- Rust but better for everything that's not low-level systems development is the impression I get

jkelleyrtp
2 replies
1d21h

The default testing framework made my jaw drop a bit - I have a very hard time seeing Rust have the enthusiasm or momentum to implement something like that right now.

kibwen
0 replies
1d16h

But Rust has had a default testing framework since 1.0?

glhaynes
0 replies
1d20h

Why do you think they wouldn't? (I don't keep up with Rust+its community closely enough to know.)

glhaynes
0 replies
1d20h

I'm not a (direct) user of the C++ interop, but everything I've heard about it has been quite positive. A few hopefully relevant resources, first a couple of videos:

- "Introducing a Memory-Safe Successor Language in Large C++ Code Bases" (John McCall; CppNow 2023) https://www.youtube.com/watch?v=lgivCGdmFrw

- "Swift as C++ Successor in FoundationDB" (Konrad Malawski; Strange Loop 2023) https://www.youtube.com/watch?v=ZQc9-seU-5k

And then a series of blog posts by Doug Gregor:

- "Swift for C++ Practitioners" https://www.douggregor.net/posts/

And finally:

- "Mixing Swift and C++" (Swift.org) https://www.swift.org/documentation/cxx-interop/

MBCook
0 replies
1d19h

Apple is using it for some low-level stuff and they appear to be trying to improve that every year.

I think they want to be able to use a limited subset of it in their kernel. Actually I think they already are but I’m not positive.

Obviously it started as an application level language but I do think they’re trying to move it down the stack as well.

mdhb
4 replies
1d20h

You almost caught up to Dart.

- Built for embedded devices and already has RISC-V support

- Already has WASM was a compilation target

- Not just an LSP but amazing VSCode tooling

- Native C, C++, Java, Rust and JavaScript interop and a .NET bridge is in the works it seems.

- Typed "throws"

- Static linking (in development)

- Data-race free by default

Unique features to Swift:

- Distributed actors for concurrency that run on distant machines. (This is doable but not native to the language)

- non-copy RAII generic types (not actually sure what this is so I assume it’s not in Dart)

manmal
2 replies
1d20h

Isn’t “data-race free” in Dart achieved by just not really sharing mutable memory between isolates? Probably because the web version needs to map isolates to web workers, right?

manmal
0 replies
1d10h

Great writeup, and I love that the authors looked at a lot of other languages. The solution section on how to prevent races is a bit light still - I‘m curious how they will solve this.

I think there will need to be exceptions to a strict race-free model eto not take away from dart‘s current capabilities, and without forcing people into something like a borrow checker. Swift has `@unchecked Sendable` which lets you tell the compiler "I promise I'll take care myself to keep everything in there race-free".

What I‘ve been missing in Swift are tools that let me add safety _within_ such @unchecked Sendables. There's the Swift Atomics lib: https://www.swift.org/blog/swift-atomics/, but its quite limited in its capabilities. So for now, I find myself reaching for tools provided by the community, like pointfree's LockIsolated: https://github.com/pointfreeco/swift-concurrency-extras/blob....

almostgotcaught
0 replies
1d20h

- Native C, C++, Java, Rust and JavaScript interop

dart doesn't do C++ interop

cube2222
4 replies
1d21h

Agreed that Swift looks quite amazing. There’s some cool talks on how they’re trying to move FoundationDB to Swift and their approach.

I think the main problem, and this is a really big problem, is that based on a very shallow investigation I did a couple months back, the ecosystem for server-side stuff barely exists.

And in my opinion, the ecosystem is one of the deciding factors when picking a language.

jkelleyrtp
3 replies
1d20h

I have a slight inkling that Apple internally is using Swift for backend stuff somewhere, especially with all the ML stuff they just shipped. Word on the street is their datacenters are full of M-series chips. I could see those servers running Swift + distributed actors + mlx.

The move to make swift run on Linux could be part of that work - their sysadmins, devops, and backend folks probably use Vim/VSCode and deploy on Linux.

We might see the release of a very good backend framework by apple for Swift that works on Mac/Linux.

The new macros they added kinda bolt on serde into the language too - and the distributed actor stuff is basically RPC in the language.

manmal
0 replies
1d20h

Yes their “private cloud” runs on Swift, which supposedly increases security because they believe Swift has things nailed by now.

MBCook
0 replies
1d19h

Apple deploys a ton of their server stuff on Linux. Plus they appear to be doing all new code in Swift and moving old code over slowly.

They’re also using embedded Swift in the Secure Enclaves and other small processors due to its safety, though I think they have an extra layer of automated security checking that they use internally that doesn’t exist in the public builds.

But in short, yes. I believe they’re trying to use Swift for everything at this point and getting away from C/C++/whatever even for kernel work.

Klonoar
0 replies
1d19h

I believe it’s confirmed that they’re doing it with Swift, buried somewhere in the ML post IIRC.

wg0
2 replies
1d17h

IMO Swift 6 is a better Go and than Go, and a better Rust for app-dev type stuff, which seems to be what people want to use Rust for.

This is a great assessment. There are some shortcomings in go that I wish weren't and I'm kind surprised that people having decades of language design experience under their belt ended up designing go.

I'm looking for a way to generate server stubs from OpenAPI specs. If that, I'm all set with Vapor+OpenAPI and would retire go for my container adventures.

wg0
0 replies
1d8h

You're right. This actually is first class Apple[0] and can't get any better than that whereas with Go, I am stuck with so many third party packages. They work well but kinda... not so elegant. Decent enough given what the language can offer.

[0] https://github.com/apple/swift-openapi-generator

heavyset_go
2 replies
1d20h

Given there is native C++ interop, is exporting a C ABI still a seemingly experimental/niche feature? Same question with interop between C and Swift.

Recently went with using Kotlin Native over Swift on macOS for this reason, the C ABI export and C interop were painless.

mannuch
0 replies
19h41m

Swift has had first-class C interop for a long time.

It is only C++ interop that is more experimental/in-progress.

MBCook
0 replies
1d19h

Swift has painless interop with Objective-C, which is just C plus small talk.

C should already be pretty easy, though I haven’t really used it myself. I only use the Objective-C stuff.

I know they’ve been working on C++ but don’t have any experience to comment. Someone else had a nice comment listing resources on that.

dagmx
2 replies
1d21h

As another huge rust fan myself, Swift 6 has really won me over.

I find myself reaching for Swift as the default for a lot of things rather than Rust, especially with the advent of C++ Interoperability and the new Swift embedded stack and ownership model.

The only thing I really need is a UI story on other platforms, but it’s an area Rust is lacking great solutions too. I suspect the C++ interop might eventually make Swift have great Qt bindings to compete with PySide as an accessible way to make multi platform UIs.

jclay
1 replies
1d18h

There’s a very minimal example using C++ interop in Qt’s test suite:

https://github.com/qt/qtdeclarative/tree/dev/tests/manual/he...

I’ve kicked around with the C++ interop a few times. Projects like Qt that use raw pointers extensively seem hard to expose. Ended up having to wrap Qt classes to model as a value type which was straight forward but it’s not nearly as seamless as the Objective-C++ experience

dagmx
0 replies
1d16h

Ah, very cool. Thanks for the link and write up

coldtea
2 replies
1d21h

Swift also took a bunch of goodies from Rust - No garbage collector - Traits via "protocol"

I'd say they took them from Apple's own Objective-C additions who had those for decades before Rust (ARC and protocols).

favorited
0 replies
1d20h

Yeah, Objective-C Protocols are so old that they influenced Interfaces in Java 1.0.

Klonoar
0 replies
1d20h

This is correct.

KurtMueller
1 replies
1d20h

Algebraic data types are not a Rust invention and aren't exclusive to that language.

MBCook
0 replies
1d19h

I don’t think they were trying to claim that, just that it was a feature that was in Rust that they liked and wanted to keep using.

Just like Rust didn’t invent not using garbage collection.

stux
0 replies
1d19h

Anonymous enums/structs in parameters

Can you share an example of this? It sounds really interesting but I couldn’t find any references. Do you mean the parameter “packs” features?

pcwalton
0 replies
1d16h

Swift has a garbage collector. Reference counting is a form of garbage collection.

lll-o-lll
0 replies
1d19h

No garbage collector

No tracing gc. Ref counting is the other kind of garbage collector.

Vt71fcAqt7
25 replies
1d21h

Genuine question: is there any reason to use Swift without iOS/SwiftUI? (Outside of devs who are primarily Swift developers that want to use something they already know for a small project or similar.)

righthand
9 replies
1d21h

Not really no, there are far better languages with better cross platform support.

josephg
4 replies
1d20h

Which languages do you think are both better and have better cross platform support?

boffinAudio
2 replies
1d7h

Lua, I would say. Far easier to get it everywhere, and a very nice language, also.

josephg
1 replies
1d4h

Lua is nice, but it’s a bit of a weird comparison for Swift. Swift is compiled and lua is interpreted. Swift is statically typed. Swift uses ref counting to Lua’s runtime GC. And Swift has non nullable types by default, classes, enums, ADTs, match expressions and so on.

Lua is nice. But it’s chalk and cheese comparing the languages. I can’t think of many cases where you’re trying to decide between lua and Swift.

boffinAudio
0 replies
10h53m

In this case, the question is whether to use Swift for a backend server on a Linux machine, or something else. That's the environment. I'd prefer Lua, simply because its a very proven language for that application.

Sure, Swift has sexy features that make it appealing to developers. But the ecosystem for server infrastructure on Lua is formidable.

Tainnor
0 replies
9h24m

Kotlin

petereddy
1 replies
1d20h

There are definitely languages with better cross platform support. But far better languages? I think Swift is a pretty good language and I like to know what you think is far better than it.

pzo
0 replies
1d15h

maybe not far better as a language but on the same league but with far better cross-platform ecosystem that would be kotlin (native) or java (this days). You have great ecosystem for e.g. backend (Spring Boot) and modern java is also looking better every year.

criddell
1 replies
1d20h

Out of curiosity, which language works best for you and your use case?

righthand
0 replies
1d3h

CPP

Mandelmus
7 replies
1d21h

It's a beautiful language that's a joy to write. It's safe and ergonomic, and has an extremely powerful type system. I'd say those are good reasons to use Swift.

oddevan
6 replies
1d20h

I'm really interested in exploring it for building web app backends because of this. Being able to have a drag-and-drop distribution is even better.

dlachausse
5 replies
1d20h

I haven't used it yet, but I've heard really good things about Vapor as far as server side Swift goes...

https://vapor.codes

OKThatWillDo
4 replies
1d19h

Thanks. What is a "protocol server?"

potatolicious
3 replies
1d19h

Not a super-expert but I've used Vapor on some personal projects. Do you have a link to the mention for "protocol server"? I'm not familiar with the concept but might be able to help.

OKThatWillDo
1 replies
19h32m

That's right. I did a search but this term does not seem to have a trendy or thorough definition.

dlachausse
0 replies
4h49m

In this instance they're talking about implementing network protocols, such as HTTP, where one end is the client and the other end of the connection is the server.

It's confusing because the Swift language also has the concept of "protocols" which are basically the equivalent of Java and C#'s interfaces if you're familiar with those languages.

jimbobthrowawy
1 replies
1d18h

Has nobody made a polyfill for swiftUI on other platforms yet? Or is it too tied to apple OS-level APIs? The language itself is pretty nice, last I used it. Even if some of the method (argument?) names in most SDKs are absurdly long.

robertjpayne
0 replies
19h48m

You can implement the same syntax for a renderer on other platforms but all of SwiftUI is closed source. So the diffing engine etc… all would need to be re-created from the ground up.

SwiftUI, like react uses some language constructs to make it look really fancy but in reality it's really simple nested data structs.

The real hard part is what the "DOM" provides for React and likewise what UIKit/iOS is doing with those data structs.

e63f67dd-065b
1 replies
1d21h

The main reason is that Apple has effectively deprecated Objective-C for ios/macos development going forward. It's not going away for probably another decade+, but all documentation is now in Swift, new APIs are written with Swift in mind, etc.

Think of it this way: in 5-10 years, ObjC will be the python2 of Apple development.

hbn
0 replies
1d20h

The GP was asking specifically about non-Apple development

wg0
0 replies
1d17h

Haven't written Swift ever but it seems very elegant language. In that spot, only go stands but go although simple but has very ugly corners such as error handling and a weird type system.

So yes for me, I might switch to Swift which seems very elegant and readable compared to some other options.

airstrike
0 replies
1d21h

No language feels more pleasurable to write in. It's incredibly expressive and things are just dead simple 99% of the time

It's not perfect, but I hope it continues to flourish because it gets a lot right

Tainnor
0 replies
9h33m

I was maintaining a server-side app written in Swift from 2018 to 2020 and we ran into tons of issues at least back then. I haven't looked into all the improvements they did since, but you might want to check.

My coworker wrote down some of the major issues we were facing: https://forums.swift.org/t/issues-learned-4-years-with-serve...

Personally, I've been soured enough that I don't ever want to write any server-side code in Swift again. It just seemed that Swift pretended to be open-source and cross-platform and then Apple would just unilaterally push some changes just because they wanted them for iOS (e.g. function builders for SwiftUI) without waiting for community feedback. It's fine to be a dictator for your PL, but not when you're claiming to have "open governance". All the while support for Linux was routinely being neglected.

I would rather recommend Kotlin. It's similar enough to Swift and it comes with the advantage of having the whole JVM ecosystem which can probably do most things you'd ever want to do on a server.

autoexecbat
11 replies
1d21h

I guess this means it can compete with golang on ease of distribution. Pushes all the complexity away from the end user

e63f67dd-065b
10 replies
1d21h

Yeah, I'm really glad for the trend of statically linked binaries that came with Rust/Go. No more version incompatibilities, fights with downstream packagers, weird build configs, etc, just distribute the binary and that's it.

umanwizard
8 replies
1d21h

Rust binaries (at least on Linux) are not statically linked by default. They depend on libc.

MrDrMcCoy
3 replies
1d18h

I've had a 0% success rate compiling other people's Rust apps statically. I always end up with a shared binary or a failed build, even when building with musl.

kibwen
2 replies
1d17h

What problems did you have? As someone who's never in his life used musl before, I just now ran `rustup target add x86_64-unknown-linux-musl` and then built ripgrep with `cargo build --release --target=x86_64-unknown-linux-musl` and it worked without a problem. ldd confirms that it's statically linked. I'm surprised it was as painless as it was, I thought I'd have to install musl separately.

burntsushi
1 replies
1d6h

I just tried this myself and I did not have a painless experience. Hah. Without the `musl` Archlinux package installed, I get this:

      --- stderr
      configure: error: in `/home/andrew/rust/ripgrep/target/x86_64-unknown-linux-musl/release/build/jemalloc-sys-b7d053053989ba56/out/build':
      configure: error: C compiler cannot create executables
      See `config.log' for more details
      thread 'main' panicked at /home/andrew/.cargo/registry/src/index.crates.io-6f17d22bba15001f/jemalloc-sys-0.5.4+5.3.0-patched/build.rs:351:9:
      command did not execute successfully: cd "/home/andrew/rust/ripgrep/target/x86_64-unknown-linux-musl/release/build/jemalloc-sys-b7d053053989ba56/out/build" && CC="musl-gcc" CFLAGS="-O3 -ffunction-sections -fdata-sections -fPIC -gdwarf-4 -fno-omit-frame-pointer -m64 -static -Wall" CPPFLAGS="-O3 -ffunction-sections -fdata-sections -fPIC -gdwarf-4 -fno-omit-frame-pointer -m64 -static -Wall" LDFLAGS="-O3 -ffunction-sections -fdata-sections -fPIC -gdwarf-4 -fno-omit-frame-pointer -m64 -static -Wall" "sh" "/home/andrew/rust/ripgrep/target/x86_64-unknown-linux-musl/release/build/jemalloc-sys-b7d053053989ba56/out/build/configure" "--disable-cxx" "--enable-doc=no" "--enable-shared=no" "--with-jemalloc-prefix=_rjem_" "--with-private-namespace=_rjem_" "--host=x86_64-unknown-linux-musl" "--build=x86_64-unknown-linux-gnu" "--prefix=/home/andrew/rust/ripgrep/target/x86_64-unknown-linux-musl/release/build/jemalloc-sys-b7d053053989ba56/out"
      expected success, got: exit status: 77
Notice, in particular, that there is `CC=musl-gcc` in the error above. But:

    $ which musl-gcc
    musl-gcc not found
I think the spoiler here is the fact that ripgrep uses jemalloc when you build with musl on 64-bit: https://github.com/BurntSushi/ripgrep/blob/c9ebcbd8abe48c833...

If you comment out those lines and remove the `jemallocator` dependency from `Cargo.toml`, then the build succeeds.

I imagine you'll run into this same problem if you enable ripgrep's `pcre2` feature.

However, after installing the `musl` Archlinux package (which provides `musl-gcc`, among other things of course), then the above command builds just fine. Including with `jemallocator` or even with the `pcre2` feature enabled.

kibwen
0 replies
14h7m

Interesting, I must have had musl preinstalled from some other package. And I did notice that jemallocator started showing up when I compiled for musl, I figured you must have had a good reason. :P

freedomben
1 replies
1d17h

(not directed at parent specifically) Do you have to link againt musl? I have some C applications that I link into a static binary using the glibc-static package (in Fedora). Can the same be used with Rust?

umanwizard
0 replies
1d16h

Nothing stops you from linking against glibc statically from rust. It’s recommended to link against glibc dynamically, but that’s just as true for any language.

seabrookmx
0 replies
23h20m

Same with golang! You need the CGO_ENABLED=0 flag IIRC to make static binaries on Linux.

dzonga
9 replies
1d19h

Swift could've easily replaced python.

but the language got complex and is now a baby C++.

guestbest
2 replies
1d16h

Does swift still lack a built in package management system?

newdee
0 replies
1d9h

No, this came with Swift 3 back in 2016.

glhaynes
2 replies
1d14h

"Swift is too complex now" has seemed to have achieved meme status of late but I don't see it.

For the average developer, writing modern Swift is generally not any more difficult than it was several years ago (much more often it's easier), it's just that the language can do a lot more now. But you only need to learn those new parts if you're using them. If you're not writing low-level or special-purpose code, you don't need to learn about more recently added things like move-only types, the embedded subset, varadic generics, or macros, etc, etc. And if you are writing things that require those features, you often couldn't have even considered Swift for that purpose before they were added.

veidr
0 replies
1d2h

I'm rooting for Swift, but OMFS (S=Science btw, join my acronym club, it's free) the complexity has doubled? tripled? since I wrote the Swift SDK for my emlpoyer's API, in the Swift 3-4 era.

I think it is a lot more difficult now, because the scenario wrt the, uh FUCK, WHAT THE— CEASE ALL MOTOR FUNCT—

msie
0 replies
1d

"But you only need to learn those new parts if you're using them" - people only use a subset of C++.

azinman2
1 replies
1d19h

Those are pretty different languages. One you just run as a script with no compilation and no static typing, the other is fully compiled and linked into a binary. How could they replace each other?

And what’s the complexity now that even remotely approaches c++?

dagmx
0 replies
1d16h

Fwiw, you can use Swift in a very Python like way.

If you give a Swift file a shebang, it’ll execute as a standalone script.

I still don’t agree they’re necessarily as overlapped as the other person claims but there is a decent area where Swift is easy enough to replace Python tooling

pzo
0 replies
1d16h

I think it's too late which is sad since Swift is not a bad language even though I agree it got complex since the last 5 years.

Python is mostly used not because of its language features but for cross-platform ecosystem. This is hard and slow to build especially these days (comparing to 10 years ago) since there are many languages and winner takes all or most of the cake.

The only way is

1) to provide something really groundbreaking at the time (e.g. ruby on rails)

2) piggyback on other ecosystem by providing great interop (e.g. maybe mojo in the future)

3) slowly grind and hustle until something eventually catchup (e.g. maybe rust in the future)

The problem with apple is they are too much focused to wall garden you instead of build ecosystem. Their IBM partnership failed to make something like Rails or Spring Framework for backend. Tensorflow for Swift failed even though it was google project. They don't have cross platform support in their DNA. You don't even get Xcode on Windows or iPad - this is dealbreaker for many people.

I would bet more on kotlin (native) / java even though I'm iOS dev myself. Embedded is the exception that they still might win the game since the only competition there is pretty much: C, C++, Rust and sometimes python, js more as a glue.

w10-1
8 replies
1d20h

This static SDK is just one example of Swift's new support for user-definable platforms, timed to amplify support for embedded and WASM.

Along with the move to a non-Apple GitHub organisation, it represents real progress in extending swift to other platforms.

It would be interesting to see if this is used for the AI OS that they are inviting researchers to validate for security purposes.

hugodan
2 replies
1d20h

Wasm? Care to provide source for that?

walterbell
0 replies
15h18m

> It would be interesting to see if this is used for the AI OS that they are inviting researchers to validate for security purposes.

That would imply either:

1. Bare-metal Linux AI OS runs on Apple Silicon. Apple could contribute Apple Silicon firmware/hardware support to Asahi and mainline Linux.

2. Virtualized Linux AI OS runs on Apple Silicon Hypervisor. Apple could contribute mainline Linux guest support for Apple Hypervisor. They could also support Linux VMs on MacOS and iPadOS which run on Apple Hypervisor, for M2+ devices with hardware support for nested virtualization.

29athrowaway
8 replies
1d20h

Why should I use Swift instead of Rust?

manmal
3 replies
1d20h

The concurrency story is quite good now with Swift 6, and it’s arguably easier to handle than the borrow checker, but still very safe.

Sytten
2 replies
1d20h

The way I view it as a Rust experienced programmer: Its kinda like if everything in your program was Arc<dyn Trait> and we didnt have the mess that are the async executors. But I might be wrong. Love rust but god that sometimes I curse the choices that were made and how slow it evolves.

msk-lywenn
0 replies
21h59m

And supposedly, the compiler transforms the Arc in Rc or even removes it entirely if it can prove to be fine. I still did not check if there is a tool that tells you what was optimized and the reason why something wasn't.

manmal
0 replies
1d10h

I don't have a lot of experience with Rust, but that sounds about right.

singularity2001
2 replies
1d20h

Swift is elegant, beautiful and concise, whereas Rust is an ugly verbose sigil mess.

29athrowaway
1 replies
22h40m

Would it be fair to say that Rust is a better C++ and Swift is a better Objective-C?

helge5
0 replies
18h58m

No, both Rust and Swift can be seen as better C++'s. And both do not provide the Smalltalk like OO Objective-C has. Swift (only) on Apple platforms integrate w/ ObjC, but the core language is more like C++ and very little like Smalltalk.

rgreekguy
0 replies
1d14h

Because it is not Rust.

JackYoustra
6 replies
1d19h

Swift tooling has some really! Sharp! Edges!!! If you need something quick and easier than rust or have some reason to want to take your swift code and run it elsewhere I guess this is good but I don't see why you'd use it besides that.

rescripting
1 replies
1d19h

Could you elaborate?

JackYoustra
0 replies
1d14h

Yes! See my reply above

gh123man
1 replies
1d19h

I'd love to hear some specific examples. Ive built several iOS apps and a whole backend (on linux) with Swift and other than lack of OSS library support for some SaaS APIs, it's been quite nice.

Sure Swift itself has some sharp edges, but not any more (or worse) than many other popular languages.

JackYoustra
0 replies
1d14h

Sure! I love talking about this stuff :) here's a few:

- if you want to manager your Package.swift target, you mostly have to deal with .target enum (can't figure out how to paste the URL)

You can really only do a define or unsafeFlags, which leads to a couple issues...

1) There's only Debug and Release configurations! What if you want more? What if you want a nice flow where you emit and consume pgo data and re-ingest it?

2) What if you want to use a define for another language managed by SPM, such as metal?

3) What if you want to put in a portable path into a linker argument? SPM blocks use of build-time environment variables, so you can't do that either.

All of these things seem contrived, but I ran into all three of them at my current job (shameless NanoFlick plug). All of these can be handled by cmake or xcodebuild (although probably better to use rules_xcodeproj).

- Swift compiler feedback and performance in builders is absolutely atrocious, to the point where binary searching a view to find the actual source of a type error over ~30 second build times isn't very unusual!

- It's very overly conservative with build times, and because there's only module-level import, it's very easy to accidentally have a long dependency chain which makes building one file imply building many files, further tanking your build time. There are some forum posts I can dig up on this if you're curious more on this point.

- POD structs are default-Sendable at module-level visibility, but lose that if they're public, which means if you try modularizing your app into different small packages to restore some notion of compilation units to fight against the above two points, you end up having to go around and mark all of your different classes with default protocols (usually just Sendable) to reimplement!

- Not a huge deal, but no way to have macro_rules! like you can in rust: macros are kinda hard to use and have to be in another package.

This is just my thoughts on tooling, I have many more thoughts about the language itself that I'd be happy to share.

Honestly though it's much better with vscode. I do hope that it makes progress in the right direction, Swift has a lot of things going for it!

akdor1154
1 replies
1d17h

It does, but it's also a really, really nice language. I'm excited to see Apple work to file those edges down. (and i say this as someone who is a Golang and Linux fan and owns zero iThings)

JackYoustra
0 replies
1d14h

Completely. The language philosophy is much easier than rust imo

prophesi
3 replies
22h21m

What might a cross-platform GUI app look like with Swift? I'm assuming SwiftUI can't be used? Regardless, I'll definitely be reaching for Swift for one-off scripts. I've enjoyed the times I needed to use Swift for a React Native extension.

lukeh
1 replies
16h45m

There's not a consistent story but there are a bunch of options, principally divided into wrappers around existing libraries (SwiftGTK [1], Qlift [2], LVGLSwift [3]) and SwiftUI workalikes (Tokamak [4], SwiftCrossUI [5], AdwaitaSwit [6], there are others too).

After exploring most of these for my use case (something that needs to run on an "embedded" RPi CM4 as well as iOS), I wrote a Swift bridge/runner for Flutter [7] which is working well. That enables me to write the UI in Dart and the business logic in Swift. I looked at all the other options below (that's how I know about them, indeed [3] I wrote as part of my research), in the end I felt that none of them were at the time of investigating sufficiently mature to base a product around.

[1] https://github.com/rhx/SwiftGtk

[2] https://github.com/Longhanks/qlift

[3] https://github.com/PADL/LVGLSwift

[4] https://github.com/TokamakUI/Tokamak

[5] https://github.com/stackotter/swift-cross-ui

[6] https://github.com/AparokshaUI/adwaita-swift

[7] https://github.com/PADL/FlutterSwift

prophesi
0 replies
1h20m

Late to respond, but thank you for the in-depth response! Your research into the different options judged by your use-case is greatly appreciated.

easeout
0 replies
20h40m

In iOS 18, there is now a SwiftUICore framework that's separate from SwiftUI, which I imagine consumes it. I don't see the new one on the documentation site. If that becomes public in a year or so, maybe you'd be able to replace one of the two frameworks to implement your own view system atop the attribute graph and data flow bits.

1vuio0pswjnm7
3 replies
1d18h

This website is sending gzip _and_ ignoring the client Accept-Encoding header. Specifiying "identity" has no effect.

Ignoring the Accept-Encoding header is common but sending gzip compressed response body and _also_ ignoring the header, thereby making it impossible for the client to disable compression using Accept-Encoding: identity, is relatively rare.

Another example that comes to mind is www.amazon.com. However in that case one can disable compression by sending a Viewport-Width header.

cqqxo4zV46cp
0 replies
1d18h

There is, in reality, nothing unusual about that.

1vuio0pswjnm7
0 replies
1d15h

They have now fixed it after I submitted this comment. No longer sending gzip by default. Thanks for that. Someone tell Amazon they should do the same.

1vuio0pswjnm7
0 replies
15h26m

In addition to viewport-width www.amazon.com also requires a user-agent header in order to disable compression

anothername12
1 replies
1d20h

Can I make Gtk GUI with this like you can with cocoa on macOS?

zshrc
0 replies
1d20h

Crazy that they’re still offering CentOS 7 images. PLEASE DONT USE THEM

stephen_g
0 replies
1d14h

This is awesome, and I believe opens up what I and a bunch of people were wanting which is the ability to run Swift binaries in Alpine containers! I'd seen work on musl support going in but I didn't realise it would all be going so soon. Cross compilation is very nice too to not need your runtime platform to necessarily support the whole toolchain.

I'm really glad there's finally support for vanilla Debian and from what I've seen it looks like there are initial Swift packages finally being added in the Debian testing version, which will be nice. Debian is more and more my go-to for development VMs where Ubuntu used to be, so I'm excited for official support!

With all this and embedded, I'm really excited about Swift! I've done a lot of embedded in C and I'm super keen to try out Swift on my STM dev boards!

darthrupert
0 replies
12h58m

How good is the LSP? In another like-Rust-but-better language (Kotlin), that part is just abysmal.

cryptonector
0 replies
21h47m

Cons of static linking:

Not listed is that ASLR either doesn't work at all or you get just one object (the PIE's) randomized. For a memory safe language this may not be a con at all.

Also, when many executables can share common objects then there can be a reduction in I/O (reads) needed to load those the next time that one of those executables runs. In 2004 when the Solaris 10 (then a work in progress) unified process model delivered, and all system executables were dynamically linked, boot times went down by a lot.