Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> I'm not a rust user but if it lets me use classes and templates, I'll switch over

Yer not switching any time soon then. Rust does have methods but not classes (QOM’s inheritance is specifically called as an issue in TFA) and it uses Haskell-style generics rather than C++-style templates.



I mean it has polymorphism via v-tables and composition via traits, that's enough object-orientation for me. Inheritance is a core principle of OOP but in practice most C++ class hierarchies are relatively flat (there are exceptions like Qt, which I think uses inheritance in a good way), in practice most of that can be mimicked with embedding and composition well enough to work. Not sure if you want to call that object-oriented but operating on polymorphous structures that encapsulate their data is pretty close to object orientation (the good parts of OOP, at least). And I'm not a big expert on Rust but I think you can do most of the things we do in C++ with templates using macros.


The one lagging thing that isn't easy with rust's generics is expressions, and that looks to be getting kicked down the road indefinitely. You can't have Foo<N> * Foo<M> -> Foo<N+M> or similar. That is a useful thing for statically sized math libraries and for performance oriented metaprogramming. The latter can be clumsily handled with macros, but not the former. It is also blocking portable simd from stabilizing, apparently now indefinitely. I still wouldn't pick any other language a new production product, but I find the stalling out on const generic expressions frustrating, as simd and static math libraries are things I use daily.


> You can't have Foo<N> * Foo<M> -> Foo<N+M> or similar.

You can though, unless I totally misunderstand your syntax

    use std::{marker::PhantomData, ops::{Add, Mul}};

    pub struct Foo<T> {
        _p: PhantomData<T>,
    }

    impl<N, M> Mul<Foo<M>> for Foo<N> 
    where
        N: Add<M>
    {
        type Output = Foo<<N as Add<M>>::Output>;
        fn mul(self, rhs: Foo<M>) -> Self::Output {
            todo!()
        }
    }


You misunderstood. N, M are supposed to be integers (const generics); in your example code you've made them types. Also, your `type Output = Foo<<N as Add<M>>::Output>;` just means "multiplication has the same return type as addition". But desired is that multiplying a Foo<4> with a Foo<3> results in a Foo<7>.

Rust decided that it's important to not have instantiation-time compiler errors, but this makes computation with const generics complicated: you're not allowed to write Foo<{N+M}> because N+M might overflow, even if it never actually overflows for the generic arguments used in the program.


aiui this isn't inherently limited by instantiation-time error messages and is available on nightly today with the generic_const_exprs feature. It's in the pipeline.


I believe this kind of stuff is being worked on.


Instantiation time errors unlock so much metaprogramming potential that Rust is going to be forced to allow them sooner or later.


I could go on and on about the limitations of min_const_generics, missing TAIT (type alias impl trait), unstable coroutines/generators, etc. but none of that stuff erases how much of a miracle Rust is as a language. The industry really needed this. It's practically the poster child of memory safety and security-critical industries are picking it up and Ferrocene is pushing it in safety-critical environments as well and it's just. Good. Please. Finally a serious contender against the terrible reign of C and C++.


> Inheritance is a core principle of OOP

Of Simula (& descendants) proto-OOP objects, not as it was envisioned by the one who coined the term.

http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...

> I didn't like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better.

> OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP.

Fun that this was mentioned too:

>> it uses Haskell-style generics

> polymorphism via v-tables and composition via traits, that's enough object-orientation for me

For which Alan Kay had this to say:

> My math background made me realize that each object could have several algebras associated with it, and there could be families of these, and that these would be very very useful. The term "polymorphism" was imposed much later (I think by Peter Wegner) and it isn't quite valid, since it really comes from the nomenclature of functions, and I wanted quite a bit more than functions. I made up a term "genericity" for dealing with generic behaviors in a quasi-algebraic form.

In a way it's fascinating to see how C++ has shaped (dare I say warped) the collective vision of how to do OOP.

For example, as a Rubyist, which was heavily influenced by Smalltalk, it is fascinating how hard it can be to explain how fundamentally different message vs call are, and what's the whole point of modules, mostly because the other viewpoint is so warped as to cognitively reject that it can be any different from the C++ model.


You can do it with macros, the problem is A) documentation B) macro abuse

It's so much harder to debug things when function calls are secretly macros, and if I didn't have the vscode cpp language server for goto definition, I'd be completely lost. I'd wager that only 5% of the #defines aren't auto generated by occasionally recursive macros. Maybe hyperbole. Makes it really hard to figure out how existing code works.


:( the QOM inheritance is where I've had my wrist bugs. Recently I merged from master (upgrading me from version 8.something to 9.2.?) and they dramatically changed the resets. I tried the new way and had segfaults in bad places that went away when I reordered code that shouldn't have ordering requirements. That was too scary so I switched to their legacy reset function and it was all fine again. All this blind casting of opaques makes me nervous.


The legacy reset way is fine, and yeah this is where being more strict and doing more stuff within the language should help.


I don't think he literally means templates and classes. Rust has equivalents that do the things you want templates and classes for (generics and structs/traits respectively).

I completely agree with his point about reimplementing C++ badly in C. GNOME does this too in their libraries. He will be much happier with Rust.


On the other hand it seems like gobject was good for gnome as it made it easier to bind GTK to other languages


Hmmm I think I actually really want classes. Something that combines data and methods together without more function pointers. Template vs generic I don't care about


Rust structs are in some ways similar to C++ classes. You can combine data and methods together with them without worrying about things like function pointers.


Rust structs do bind data and methods together.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: