8 ms·
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 ha
by meisel 7mo 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.
- bergheim 7mo agoI 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?
- rvz 7mo agoThis experiment has shown that both are actually bad choices.
- josephg 7mo agoOh? 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.
- zadikian 7mo agoIt 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.
- antonvs 7mo agoWhat 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.
- zadikian 7mo agoYou 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.
- antonvs 7mo agoBut it's not "kinda how you can do it in C". Traits are a core feature of Rust, any non-trivial Rust program uses them. Traits alone give you polymorphism across disparate types, exactly as in OO - actually better than standard OO (without interfaces), because trait polymorphism works without requiring inheritance from a common ancestor. > Especially because there's no GC. This is the only real issue I can think of. However, for implementing something like a UI, automatic GC isn't really necessary because the lifetime of widgets etc. maps very well to the lexical/RAII model. Windows own widgets, etc. Again, see all the UI toolkits implemented in Rust.
- zadikian 7mo agoI know the Rust trait system has an answer to every OO concept. Another is that data field inheritance is replaced by composition. But these are more workarounds for the rarer cases you want to do OO in Rust, not the intended usual path, and doing OOP this way will get tedious. Otherwise, there'd be no difference and everyone would call Rust an OO language. Not so sure about not needing GC. Many times a problem seems easy without GC until you get into the weeds. Like why did ObjC feel the need to add ARC (not GC but similar goal)?
- antonvs 7mo ago> But these are more workarounds for the rarer cases you want to do OO in Rust, not the intended usual path, and doing OOP this way will get tedious. It sounds like you're speculating. But this doesn't match the reality of actual Rust code. For example, here's the complete, actual code for the `Widget` trait implementation for the `Button` struct in the egui framework: impl Widget for Button<'_> { fn ui(self, ui: &mut Ui) -> Response { self.atom_ui(ui).response } } (From: https://github.com/emilk/egui/blob/main/crates/egui/src/widgets/button.rs https://github.com/emilk/egui/blob/main/crates/egui/src/widg... , bottom of page.) This is OO code. It's just that it's trait-oriented, not class-oriented. But that's a good thing, not a drawback. Traits are more precise, more flexible, more type-safe, and don't conflate multiple unrelated concerns in a single feature the way class inheritance does. OO languages like Java support a very similar approach, via interfaces. You can find similar code in any Rust GUI library, and indeed in almost any non-trivial Rust program. > Otherwise, there'd be no difference and everyone would call Rust an OO language. Rust is not a class-based OO language. But the fact that one of its core features, traits, have "methods", and those methods have a first argument traditionally named `self` should be a clue. Trait-based OO is very much OO. Whether "Rust is an OO language" depends on how strictly you want to define "OO" to match the rather obsolete 1970s conception of it. This is why the first question I asked you was "What OO features are you thinking of that Rust doesn't have?" Because "OO" is a broad label that covers a wide range of different features. Rust doesn't have "classes", but classes are a 1970s-era mish-mash of a whole bunch of different concerns munged together into a single poorly-factored construct. Now, half a century later, that's well understood, and better solutions exist in the form of traits and interfaces, and related capabilities. > Like why did ObjC feel the need to add ARC (not GC but similar goal)? Same reason Rust includes `Rc` and `Arc`. A general-purpose language has to provide some solution to memory management based on reachability. Reference counting and tracing GC are common solutions to that. Rust's static memory management plus RC is plenty good enough for GUI applications.
- jason_oster 7mo agoEvery "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-interfaces-for-object-oriented-systems-part-1.html 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/ https://guide.elm-lang.org/architecture/
- zadikian 7mo agoRight, in this context people are not taking such a strict definition of OO.
- carefree-bob 7mo agoThe ladybird developers tried Rust and Swift both and voted to adopt Swift.
- mlinksva 7mo agohttps://x.com/awesomekling/status/1822236888188498031 https://x.com/awesomekling/status/1822236888188498031 https://x.com/awesomekling/status/1822239138038382684 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."
- refulgentis 7mo ago> 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.
- zozbot234 7mo agoRust 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.)
- rvz 7mo agoI 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.
- tvshtr 7mo ago
- lukeh 7mo agoSwift 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/ https://www.swift.org/documentation/cxx-interop/
- palata 7mo agoI 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.
- gmueckl 7mo agoBinding 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.
- palata 7mo agoYeah, 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.
- zadikian 7mo agoI 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.
- palata 7mo agoYes 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.
- password4321 7mo agoIt 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 https://news.ycombinator.com/item?id=41208836 Ladybird browser to start using Swift language this fall
- jll29 7mo agoAndreas 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.
- stingraycharles 7mo agoBut wasn’t Rust designed specifically for being a language for developing a rendering engine / web browser?
- greazy 7mo agoNo. It was developed as a general purpose language. I think you are conflating the development of Servo with the design and development of Rust.
- diath 7mo agoRust 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.
- hollerith 7mo agoHow could browsers not be on his mind when his job was to contribute to Firefox as a dev?
- diath 7mo agoDo 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".
- 7mo ago
- elcritch 7mo agoAlso I believe one of the core LadyBird devs was an ex Apple employee on WebKit which has been using Swift as well.
- diath 7mo ago> 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.
- gardaani 7mo agoHere'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 https://x.com/awesomekling/status/1822241531501162806
- alper 7mo agoI 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.).
- sparky4pro 7mo agoSwift != GC
- ozgrakkurt 7mo agoI remember watching the project lead say something like “the developers just don’t enjoy rust”
- generalpf 7mo agoSwift doesn't use a garbage collector.
- myko 7mo agoARC is GC, Swift definitely uses GC. It isn't a _tracing_ GC