Hacker News new | ask | show | jobs
by meisel 116 days ago
Why did Ladybird even attempt this with Swift, but (I presume) not with Rust? If they're going to go to the trouble of adding another language, does Rust not have a better history of C++ interop? Not to mention, Swift's GC doesn't seem great for the browser's performance.
12 comments

https://x.com/awesomekling/status/1822236888188498031 https://x.com/awesomekling/status/1822239138038382684 "In the end it came down to Swift vs Rust, and Swift is strictly better in OO support and C++ interop."
Did they consider using Nim? It has great C++ interop, OO and same ARC memory management as in Swift.
> In the end it came down to Swift vs Rust, and Swift is strictly better in OO support and C++ interop

Why not D?

Why not rust? It's popilar, in wide adoption, with wide support, without the baggage of C++. What'e the downside?
Well they already chose Swift over Rust because they said:

> Swift is strictly better in OO support and C++ interop

So I guess from their point of view that’s why not rust.

I don’t have a horse in the race.

I was genuinely interested in why they didn’t even consider D given they already ruled out rust for those particular reasons, for which it seems D would fulfill nicely.

It is not backward compatible, the library system is immature, and there is no variety of different compilers for the language.
> the library system is immature

Hoo boy, wait until you hear about the state of C++'s library "system"

> Swift is strictly better in OO support and C++ interop

Fascinating.

They've shown the idea it is better on C++ interop is wrong.

I don't know enough to say Rust has same OO support as Swift, but I'm pretty sure it does. (my guess as a former Swift dev: "protocol oriented programming" was a buzzy thing that would have sounded novel, but amounted to "use traits" in rust parlance)

EDIT: Happy to hear a reply re: why downvotes, -3 is a little wild, given current replies don't raise any issues.

Rust has straightforward support for every part of OOP other than implementation inheritance, and even implementation inheritance can be rephrased elegantly as the generic typestate pattern. (The two are effectively one and the same; if anything, generic typestate is likely more general.)
> Rust has straightforward support for every part of OOP other than implementation inheritance

Except the only thing that makes OOP OOP: Message passing.

Granted, Swift only just barely supports it, and only for the sake of interop with Objective-C. Still, Swift has better OO support because of it. Rust doesn't even try.

Not that OOP is much of a goal. There is likely good reason why Smalltalk, Objective-C, and Ruby are really the only OOP languages in existence (some esoteric language nobody has ever heard of notwithstanding).

I’m pretty sure when the Ladybird team said “Swift has strictly better OOP support”, they were not referring to ObjC style message passing, so it’s not even relevant.
I'm pretty sure your guessing is silly. I assume you are trying to be here in good faith, so make your case. Since it is not support for message passing, what else makes Swift have "strictly better OOP support"?
You just need to define a trait, then you can use dynamic dispatch.
You can, but then you don't get any of what OOP actually offers. Message passing isn't the same thing as dynamic dispatch. OOP is a very different paradigm.
I think we have seen enough since the best example of a Rust browser that is Servo, has taken them 14 years to reach v0.0.1.

So the approach of having a new language that requires a full rewrite (even with an LLM) is still a bad approach.

Fil-C likely can do the job without a massive rewrite and achieving safety for C and C++.

Job done.

EDIT: The authors of Ladybird have already dismissed using Rust, and with Servo progressing at a slow pace it clearly shows that Ladybird authors do not want something like that to happen to the project.

Until just a couple years ago, Servo had been a pure research project with no goal of ever releasing a full browser (and it was abandoned by Mozilla in 2020).

Igalia had five engineers working full time who turned that science project into v0.0.1 in less than two years.

> Fil-C likely can do the job without a massive rewrite and achieving safety for C and C++.

So long as you don't mind a 2-4x performance & memory usage cost.

Servo was essentially integrated into Firefox. It was not a browser in itself until it was put into a foundation on its own.
Only few isolated parts were integrated into Firefox, everything else was simply thrown away and abandoned, and IMO it was for a good reason.

I've been programming in Rust for 5 years and I could barely understand the code in their repo. Not because it was somehow advanced but because it didn't make any sense. It felt like that with every decision they could make, they always chose the hardest way.

On the other hand, I have never done any C++ (besides few tutorials) in my life and yet I found both Serenity/Ladybird and also WebKit to be very readable and understandable.

BTW: If anyone wants to reply that Rust is different then yes, of course it is - but that's the point, if there is a language that maps nicely to your problem domain, it's also very fast, and well-understood then why the hell you'd use a language that is well-known to NOT map to OOP?

The RUST ecosystem barely just started getting into shape on the GUI toolkits frontend... So perhaps save your criticisms for something that wasn't born out of the vacuum.
> Fil-C likely can do the job

> Job done.

Seems like you forgot a few stops in your train of thought, Speed Racer.

This comment needs another 'EDIT'.
They demonstrated that swift's c++ interop isn't good enough, but does it follow that rust's is better? Genuinely asking, as I don't have experience with that. I would imagine that if they rejected it for that reason originally they forsaw even more severe issues.
> Why did Ladybird even attempt this with Swift, but (I presume) not with Rust? I

Probably the same reason why Rust is problematic in game development. The borrow checker and idiomatic Rust do not go well together with things that demand cyclic dependencies/references. Obviously there are ways around it but they're not very ergonomic/productive.

Swift actually has excellent C++ interop [1] (compared to other languages, but, I guess, not good enough for Ladybird).

[1] https://www.swift.org/documentation/cxx-interop/

I actually looked into that recently (calling C++ from Swift), and I was surprised by the amount of limitations.

Said differently: the C++ interop did not support calling the C++ library I wanted to use, so I wrote a C wrapper.

Binding to C++ is an extremely difficult and complex problem for any language that is similarly rich and has lots of (seemingly) equivalent features. The number of subtle incompatibilities and edge cases becomes nearly endless. It's not surprising that some C++ code can't be bound properly.
Yeah, that's what I realised. But I just wanted to mention that this is not what I was expecting from "excellent" interop. I would say that C has excellent interop, in general.
I did this a long time ago as Swift calling Objective-C++ which can call C++ libs, in that case OpenCV. So it wasn't awful but did require making an ObjC++ wrapper, unless I did something wrong which is also possible.
Yes that makes sense. I would just rather make a C wrapper than an ObjC++ one, because then that C wrapper can be used with many other languages.
Andreas Kling said Rust lacks OO, which he says is useful for GUI coding.

He even made an attempt at creating his own language, Jakt, under SerenityOS, but perhaps felt that C++ (earlier with, now without Swift) were the pragmatic choice for Ladybird.

But wasn’t Rust designed specifically for being a language for developing a rendering engine / web browser?
Rust initially started as a hobby project of a person who happened to be a Mozilla employee and later got sponsored by the foundation however it was not a language that was specifically designed with browsers in mind.
The language's largest project before it hit 1.0 was Servo. The language wasn't designed for browsers, but it certainly was informed by them and their struggles with maintaining and developing Firefox.
a lot of early rust design was driven by Servo - an internal mozilla project, and firefox component prototypes
How could browsers not be on his mind when his job was to contribute to Firefox as a dev?
Do your hobbies revolve around the benefits for your employer? I don't mean it in a snarky way either, but given that Rust was initially written in OCaml, you could see how it could go like "I like programming, I like type systems but I want something procedural over functional so let me give it a go".
It can be described as a hobby project only in the sense that his employer would probably prefer that he spend all his time working on Firefox.

Tools to do X better are often designed by people who get paid a lot to do X and worry about losing their job if they are not good enough at X.

If he were to tell me that he didn't imagine Rust's helping with browser dev when he designed Rust, then I'd believe him, but the "circumstantial" evidence points strongly in the other direction.

> Rust designed specifically for being a language for developing a rendering engine

Rust was born at Mozilla, sort of. It was created by a Mozilla employee. The first "real" project to put it into action was Servo of which parts were adopted into Firefox. While Rust may not have been developed "specifically" to create a browser, it is a fair comment.

That said, Ladybird was started as part of the SerenityOS project. That entire project was built using C++. If the original goal of Serenity was to build an opeerating system, C++ would have felt like a reasonable choice at the time.

By the time Ladybird was looking for "better" languages than C++, Ladybird was already a large project and was making very heavy use of traditional OOP. Rust was evaluated but rejected because it did not support OOP well. Or, at least, it did not support integration into a large, C++ based, OOP project.

Perhaps, if Ladybird had first selected a languge to write a browser from scratch, they would have gone with Rust. We will never know,

We do know that Mozilla, despite being the de facto stewards of Rust at the time, and having a prototype web browser written in Rust (Servo), decided to drop both Rust and Servo. So, perhaps using Rust for browsers is not as open and shut as you imply.

I stand corrected, I was always under the impression that Rust was created specifically for Servo; TIL.
As someone who was on that team for a long time, we took that into consideration, but it was never specifically for that. There was some stuff the Servo team would have liked us to have implemented that we didn’t.
No. It was developed as a general purpose language.

I think you are conflating the development of Servo with the design and development of Rust.

Might not be the best choice for browser chrome, where an OOP paradigm for GUIs might make sense.
It will be interesting to see any further justification; I believe Rust was rejected previously because of the DOM hierarchy/OOP but not sure IIRC.

20240810 https://news.ycombinator.com/item?id=41208836 Ladybird browser to start using Swift language this fall

Here's Andreas Kling's general thoughts on Rust:

- Excellent for short-lived programs that transform input A to output B

- Clunky for long-lived programs that maintain large complex object graphs

- Really impressive ecosystem

- Toxic community

https://x.com/awesomekling/status/1822241531501162806

I think that's fair. Funny to have a language that makes it prohibitively difficult to use most of the core computer science constructs (lists, graphs etc.).
I so wholeheartedly agree. You are making a new web browser - akin to a new OS - and you want it open source for everybody but you choose swift not rust?
This experiment has shown that both are actually bad choices.
Oh? They tried rust?

Lots of people seem really committed to OOP. Rust is definitely a bad fit if you can't imagine writing code without classes and objects. I don't think this makes rust is a bad language for the problem. Its just, perhaps, makes rust a bad language for some programmers.

It doesn't seem uncommon for someone to generally like Rust but still want to use something OO for UI. I'm in that boat. Never liked OOP much, but it makes sense sometimes.
What OO features are you thinking of that Rust doesn't have?

Traits give you the ability to model typical GUI OO hierarchies, e.g.:

    trait Widget {
        fn layout(&mut self, constraints: Constraints);
        fn paint(&self, ctx: &mut PaintCtx);
        fn handle_event(&mut self, event: Event);
    }

    struct Button { ... }
    struct Label { ... }

    impl Widget for Button { ... }
    impl Widget for Label { ... }

    let mut widgets: Vec<Box<dyn Widget>> = Vec::new();
Implementation inheritance can be achieved with good old shared functions that take trait arguments, like this:

    fn paint_if_visible<W>(widget: &W, ctx: &mut PaintCtx)
    where
        W: HasBounds + HasVisibility,
    {
        if widget.is_visible() {
            ctx.paint_rect(widget.bounds());
        }
    }
You can also define default methods at the trait level.

This all ends up being much more precise, clear, and strongly typed than the typical OO inheritance model, while still following a similar overall structure.

You can see real world examples of this kind of thing in the various GUI toolkits for Rust, like Iced, gpui, egui, Dioxus, etc.

You can do OO this way if you really want in Rust, kinda like how you can do it in C, but it gets cumbersome. Especially because there's no GC.
Every "OO for UI" approach I've seen breaks most of the rules of object-oriented design.

GTK, Qt, DOM, WinUI 3, Swing, Jetpack Compose, and GWT (to name a few) all provide getters and setters or public properties for GUI state, violating the encapsulation principle [1]. The TextBox/EditBox/Entry control is the perfect example.

The impedance mismatch is that a GUI control is not an object [2]. And yet, all of the object-orient GUI examples listed implement their controls as objects. The objects are not being used for the strengths of OO, it's just an implementation detail for a procedural API. The reason these GUIs don't provide an API like shown in [1] is because it's an impractical design.

"How are you supposed to design an OO TextEdit GUI control if it can't provide a getter/setter for the text that it owns?" Exactly. You're not supposed to. OOP is not the right model for GUIs.

Ironically, SwiftUI doesn't have this problem because it uses the Elm Architecture [3] like React and iced.

[1]: https://www.infoworld.com/article/2163972/building-user-inte...

[2]: From [1], "All the rules in the rule-of-thumb list above essentially say the same thing — that the inner state of an object must be hidden. In fact, the last rule in the list (“All objects must provide their own UI”) really just follows from the others. If access to the inner state of an object is impossible, then the UI, which by necessity must access the state information, must be created by the object whose state is being displayed."

[3]: https://guide.elm-lang.org/architecture/

Right, in this context people are not taking such a strict definition of OO.
The ladybird developers tried Rust and Swift both and voted to adopt Swift.
Also I believe one of the core LadyBird devs was an ex Apple employee on WebKit which has been using Swift as well.
The Ladybird founder was one of the original KHTML devs and worked on Safari at Apple.
I’m not even sure he was at Apple when Swift came out. WebKit integration is very recent.
Swift doesn't use a garbage collector.
ARC is GC, Swift definitely uses GC.

It isn't a _tracing_ GC

I remember watching the project lead say something like “the developers just don’t enjoy rust”
Swift != GC