News for hackers. Stuff that matters.
Re:Swift is a more convenient Rust by lukeh on Friday September 06, 2024 @06:01AM (#41464598)
I don’t know Rust, but I’m loving Swift for systems programming. Most recent project was an 802.1Q SRP implementation and I couldn’t imagine going back to C. Higher up the stack, I’ve also used it with a custom runner to build the business logic for an embedded Flutter app.

My only beef is that the binaries are quite large. I’m hoping the new Foundation will improve things, in the interim I’m trying to eliminate my Foundation dependencies.

Re:Swift is a more convenient Rust by neonsunset on Friday September 06, 2024 @06:22AM (#41464715)
You can get much smaller native binaries with .NET's NativeAOT nowadays: https://github.com/MichalStrehovsky/sizegame

Funnily enough, I'm using C# to solve quite a similar type of tasks. It's a really pleasant experience.

Re:Swift is a more convenient Rust by pjmlp on Friday September 06, 2024 @06:36AM (#41464799)
Native AOT needs to get better tooling ergonomics though, the whole publish process is a bit convoluted versus toolchains that have AOT compilation as their default.

Not counting having to learn about IL trimming, and the whole AOT compatible libraries.

Re:Swift is a more convenient Rust by neonsunset on Friday September 06, 2024 @06:57AM (#41464940)
What kind of issues did you have with the build process? (as in, if you had a specific case, it might be worth submitting an issue or updating documentation)

It's a very straightforward process - you pass a single flag, maybe specify optimization preference and instruction set target, and it gives you the binary upon 'dotnet publish'ing the project.

The process of static linking (if you care about this scenario), with other static dependencies written in C/C++/Rust is not too different from other toolchains - you specify `DirectPInvoke` and `NativeLibrary` properties in .csproj, and they are linked into the final product as a part of the build process. You may need to forward linker arguments[0] for the imports referenced by those however, but this is expected regardless of .NET.

I think it's fair to criticize the additional compatibility effort required for high-level user libraries that rely on un-analyzable reflection, reflection emit or assembly loading, but none of these features usually have any relevance in the domain of systems programming.

When you write a project from scratch, you never have to think about whether it's native compilation or "JIT+CIL assemblies sandwich" executable, or anything else. It just works.

For example https://github.com/codr7/sharpl - the author was pretty much learning C# on the go and it needed exactly 0 changes besides adding `PublishAot` property to make it output a native executable.

[0]: https://github.com/U8String/U8String/blob/main/Examples/Inte...

Re:Swift is a more convenient Rust by pjmlp on Friday September 06, 2024 @07:44AM (#41465241)
As you are well aware, I know .NET since it was "partners only beta software", so dealing with "dotnet publish" plus csproj configuration, is still way easier than something like NGEN.

However this is somehow cumbersome versus doing a plain "aot-lang-compiler source -o binary".

Which is the experience I think the team should strive on as goal, especially for newcomers.

More so when comparing IDE experience of something like Delphi or Swift to keep it in context (press build), versus Visual Studio (besides csproj, create publish properties file, followed by a solution publish, which is hardly documented still).

Re:Swift is a more convenient Rust by neonsunset on Friday September 06, 2024 @07:51AM (#41465297)
> However this is somehow cumbersome versus doing a plain "aot-lang-compiler source -o binary".

But...it works in this exact way?

  dotnet publish -o folder -p:PublishAot=true
Does not need -p argument either, as noted in the previous comment, if `PublishAot` is specified in .csproj, like with any AOT template (e.g. dotnet new console --aot or dotnet new webapiaot).

On Visual Studio, I have started to recommend to newcomers to avoid its publishing UI which is convoluted and is easy to get side-tracked with. CLI offers much cleaner UX. Not that it matters outside of Windows. But you don't need to create publish file either, just tick the boxes you care about in the modal window.

Edit: you can't be serious, no one in their sane mind would consider a single extra keyword to get the final product once you're done writing code a learning curve too steep, unless you're in a bad mood and want to make a bad faith argument. Consider what you make the comparison against - C and C++ with their CMake, Ninja, or even raw MSBuild, Swift is barely better too. Rust with Cargo is about the same amount of effort as .NET CLI. Cmon, Pjmlp.

Re:Swift is a more convenient Rust by pjmlp on Friday September 06, 2024 @07:57AM (#41465336)
Publish versus build, yet another step, another concept to learn.

CLI only isn't the answer, if you want better adoption.

Re:Swift is a more convenient Rust by Measter on Friday September 06, 2024 @09:24AM (#41465973)
How are build times for AOT these days? Last time I tried it (~2019) it was slower than Rust at building the same project.
Re:Swift is a more convenient Rust by neonsunset on Friday September 06, 2024 @10:30AM (#41466562)
If you refer to R2R, then it's more like pre-JIT - it embeds pre-JITed code into the executable that still very much uses JIT. It will also re-JIT R2Rd code if it's deemed hot enough and in need for further optimization.

This is an older mechanism that works differently to NativeAOT, it's also used by host-installed runtime to improve startup latency, and you can do your own R2R, either full or granular, to further improve this: https://learn.microsoft.com/en-us/dotnet/core/deploying/read... It can slow down the build quite a bit from what I've seen.

NativeAOT is different - when you use it, ILLink (which previously was the Mono Linker and now has evolved) trims all unreachable and links together all of the remaining CIL bytecode and metadata from the CIL assemblies that the application/library consists of. After that, ILC (IL AOT Compiler) compiles everything (and performs AOT-specific optimizations) into a single static bundle emitted as COFF or PE (or Mach-O?) file containing machine code. Then the toolchain invokes a host-provided linker which produces the final native executable or library, much like it happens with C, C++ or Rust. It even has the OS-specific symbol format, so you can feed it to the same tools that work with native code.

Technically speaking, .NET's compiler still retains the name "RyuJIT", but in practice it's not JIT-specific and ILC drives the same back-end as JIT compilation at runtime, but with different optimizations and options.

This is a new feature that was introduced in .NET 7, and has substantially improved further in 8 and upcoming 9. Completely different output aside, NAOT builds take less time than the ones that have R2R from my experience.

Your mileage may vary depending on how big the application is, how complex linking it requires and how much the native code to compile there is.

The main difference with Rust is that compilation time whether it's good or bad has much less relevance because for development you can use JIT (both debug and release, i.e. plain 'dotnet run') or even hot-reload which can recompile actively running code without restarting the application with 'dotnet watch' which works surprisingly well.

Re:Swift is a more convenient Rust by pjmlp on Friday September 06, 2024 @10:44AM (#41466696)
The last point is exactly the value of having compiler toolchains with JIT/AOT in the box, as standard toolchain, which only a few are around.

We get to enjoy both worlds, and picking the best deployment options as per scenario.

Rust development experience would be much better if they adopted a similar approach, which by the way, is common on other ML inspired languages.

Re:Swift is a more convenient Rust by ahlCVA on Friday September 06, 2024 @01:49PM (#41468244)
Fascinating that somebody is using Swift "in production" for that!

I work on small-ish embedded Linux systems and I've been looking for an alternative to C for a long time. Rust does not fit the bill, both because I don't enjoy the ergonomics of it (but I could get over that were it not for the other issues) and because the binaries are huge, so unless you go for a busybox-style multicall binary (and even then) you'll be wasting a lot of space. Both the standard size reduction techniques and splitting out things into shared objects (the ABI instability is not an issue on an embedded system which always gets compiled as a whole anyway) don't really move the needle compared to what you can achieve using plain C.

I've been meaning to give Swift a shot for applications like this. From what I've seen I had assumed that it would have less of a tendency to monomorphize everything (like Rust and C++ like to do when you use them idiomatically), leading to less binary size bloat.

You also mention binary size, but in relation to a library - is it that the absolute cost of including the library in the image is too high or is there a per-binary effect here as well?

Could you maybe share some of your experiences with Swift on embedded Linux in the context of that project? What is working well, what are the warts? What kind of distribution (like buildroot, Yocto, ...) are you using?

Sorry for the ton of questions, it's just something that has been on my bucket list for quite a while and it very exciting to hear that somebody is already doing this.

Re:Swift is a more convenient Rust by naman34 on Tuesday September 10, 2024 @07:12PM (#41506583)
Sadly, Swift also produces large binaries unless you use Embedded Swift which is still early.