I don’t really want to wade into the Rust vs other languages thing, but I would be curious for Elementary’s take on why Vala over Rust (gtk-rs seems to see widespread use and all).
Anyone know if they’ve noted it somewhere? Is it just the investment in Vala and their custom widget library that set the direction?
Elementary is heavily dependent on the GTK ecosystem, which has its own OOP system implemented in C (for example like GObject). It is really hard to map GTK's OOP semantics to Rust. People have tried things like https://github.com/gtk-rs/gtk3-rs, but it requires heavy macro usage and doesn't feel like ergonomic Rust. On the other hand Vala is directly built upon the GObject system on the first place, so it's more fitting for GTK-specific development.
Yeah, this is a problem in a couple modern languages. For some time I tried to make a binding for Nim and encountered the same problem.
How do you make it so you can call "Widget" methods on a "Button"? Without proper subclassing, you have to either create a lot of duplicate functions, or the user has to explicitly cast up. Nim has implicit converters, so I tried defining conversions from all types to their base classes (Button -> Widget). But this made compilation time insanely slow.
Modern languages make this about "favor composition over inheritance" and say it helps you avoid monstrous Java-esqe class hierarchies. But it is really about subtyping and the Liskov substitution principle. You have a heterogeneous list of different "Widgets", how easily can you treat them as one kind, even if they need different behavior in detail?
Nim had experimental support for generics co-/contravariance. So you could say a "IF Button struct is a subclass of Widget struct THEN a GObjectPointer[Button] can be used in all cases where a GObjectPointer[Widget] can be used" (covariance). This was a unique feature and would solve the problem without implementation inheritance, but unfortunately it didn't work properly and I think it has been removed.
Nim actually does support inheritance though, so you could have just used that with methods. Though I can understand if you wanted to avoid inheritance.
That's true. I think my problem was that I was trying to be to clever and trying to make something like SmartPtr[TButton] have the same inheritance like ptr TButton. If I would have "wrapped" everything in native Nim classes it would have been fine. OTOH, I think there is no equivalent to an interface in Nim, so that would not work in that case.
I'm not saying Nim is deficient, in fact it is one of the most expressive and productive languages I know. But there are subtle difference between object models in different languages that make GUI programming hard, and I think that is one reason many people don't use modern languages but stay on C++/C# or throw there hands up in the air and just use Electron...
Until barely a couple of years ago, nobody wrote GUI applications in Rust anyway.
GTK's OOP semantics have been mapped very successfully to, among other languages, C++, Python, Perl and Go. It's unfortunate perhaps that the Rust bindings do not feel idiomatic for Rust programmers, but that's hardly fatal or unexpected.
I think it's just that Rust doesn't have inheritance/subclassing as a feature. As a result you have to do all sorts of mental gymnastics with impls and macros to fit Rust interface on GTK, while with other languages subclassing just "works".
I also think this is why Rust has lagged heavily on the GUI development front. No matter how you claim component or ECS-based architectures are better and faster, sometimes the only thing you really need might be a good ol' inheritance-based scenegraph... You can definitely do UI with a component-based object model (ex. Unity game engine), but the whole process seems a bit more... convoluted.
We have moved as an industry from "subclassing works great for GUIs" to "let's use it for absolutely everything else" through to "subclassing is a terrible idea, what were we thinking of?", whereas the first of those ideas is actually still sound.
A counterpoint: Vala hasn't done a 1.0 release yet.
But still, back at that time (2014) there was far less research done on how Rust library authors can ergonomic bind to C/C++ libraries that have their own object system. Nowadays people have figured out some techniques and we can actually use GTK and Qt from Rust, albeit in an awkward manner (lots and lots of macros).
Vala had made up its mind for many years on what it looks like and feels like. Older Rust version had green threads and IIRC even a garbage collector, it was absolutely not the same language as Rust 1.0.
Anyone know if they’ve noted it somewhere? Is it just the investment in Vala and their custom widget library that set the direction?