[Pre-RFC] object_oriented

While I agree with you this is not the point of a pre-RFC thread. I think we should stick to constructive criticism here.

5 Likes

I, too, think we should try to write more constructive responses, and I don’t think a statement of “this is not a good idea in any way” without any nuance really fits the discussion style for this forum, nor is it particularly convincing.

One major problem in this thread, which has been present before the latest responses, too, is the vague name “object oriented” for the whole idea. The term OO is so underspecified that even the Rust book, commenting on the status quo of the language has something to say about it

Many competing definitions describe what OOP is, and by some of these definitions Rust is object-oriented, but by others it is not.

This is part of the premise of a whole chapter in The Book. In some ways, Rust does share features with the paradigm(s) called “object oriented”, so a contrasting too general “OO is fundamentally wrong” might even imply “Rust is fundamentally wrong”? Probably not… and that’s not my point. Just, with something so vaguely delimited in its scope as “OO”, the simplistic “OOP bad” approach is not particularly convincing. At least one should define better what isn’t a good idea rather than quoting “OO”.

Now, going into more detail like that for criticism is tedious, as that requires addressing a broad topic (either way, regarding “OO”, or regarding the language feature in this topic). In fact, the original post of this thread probably already makes it a lot too broad to begin with, I’d say. While this “Pre-RFC” is more concrete in what it’s actually about, than just quoting the term “object oriented” it still does list a fairly long list of ideas/features, all of which only have in common that they would be found in some form in more typical OOP languages, but otherwise they could probably better be (prioritized and then) discussed separately and sequentially.

Or maybe it even is envisioned as one, fully integrated, unsplittable, super large feature, though to ship that one would clearly have to answer the question of why it has to be that way.

I think it would be quite fair to strongly criticize the feature / this “Pre-RFC” e.g. on those grounds; stating that it’ſ adding too much, or too much complexity; or on the grounds of any of the specific sub-features being listed; or perhaps also because it’s not really described in much detail at all. But I don’t think it leads anywhere useful to criticize the feature solely based on the name “object oriented” that was chosen.[1]


  1. I’m not saying “don’t criticize the name”, I’m saying “don’t criticize the feature entirely, just because of the name” ↩︎

9 Likes

Notice that most inheritance systems designed for bindings are very focused allowing, e.g. only to define immediate childclasses of a set of predefined classes. However I'd say that they still remain kind of cumbersome. Having put some preliminary thoughts into designing a general macro-based inheritance system, I'd say the following features would be extremly useful in such an endevor:

a) The ability to "use" fields of subtypes.

A child class can currently be modelled like this (afaik bindgen is also using such a structure to map C++ classes):

#[repr(C)]
struct Base {
    field1: i32,
    field2: usize
}

#[repr(C)]
struct Child {
    base: Base,
    field3: [u8; 12]
}

However this has the disadvantage that the base fields must then be accessed via child_instance.base.field1. In particular with multiple class levels, this becomes cumbersome and difficult to hide away in a macro. Ideally base fields would be mirrored in the Child-namespace, such that child_instance.field1 becomes an alias for child_instance.base.field1, unless name collision occurs.

Since a similar feature also exist in Go and this may be usefull in other contexts, has been proposed in this context in the past (don't know where right now), it would be the most likely one to get include IMO.

Similar forwarding for methods would also be helpful, but is more tricky, when it comes to self parameter transformation and can in principle be replicated manually using today's technology.

b) Fixed layout/backcasting Virtual methods rely on easy pointer casting a pointer to the base member transparently back to a pointer to the childclass instance. For repr(C) it is AFAIK guranteed that the whole struct and it's first member share the same address making such a casting trivial. This would need to be verified. However a more specific solution would be needed for multiple inheritance (not sure if one wants that) or when one wants to relace layout constrains.

c) Memory between macro calls. Macros do not allow to communicate information between each other. Such a communication would be needed to transfer base class information to child declarations. For single inheritance this can be resolved by each class generating a dedicated macro that must be used to declare children.

d) Self describing unsized types. If virtual methods are allowed, the question arises how to store boxed objects that may either be child or parent instances. Assuming each base class is attributed a trait (a hacky solution allready), trait objects may be used, but they would create some overhead in such a situation. Either one would have to call an as_base_ref() first, or all method calls would go through a big vtable. Ideally there exist something that can be used in this context.

IMO even inheritance-based layouts have a lot of nuances in how to implement them exactly and given that their main objective is in FFI applications, I don't think that having a specific one in core language would be that helpful.

2 Likes

Simply adding a DerefMany-like trait doesn't work for mutable access because it would borrow self.parent multiple times when called directly, so a new syntax would be needed for this:

decompose Car {
  Vehicle => self.parent,
  Drivable => self.drivable,
  RoadObject => self.parent.parent,
}

By picking the first valid match from the list there's no ambiguity when multiple structs contain members with same names (and this can be a warning).

Though that feels too magical and ambiguous, but inheritance usually is I guess. I also don't see any of the rust ecosystem actually benefiting from this besides it just making bindings nicer/easer to write.

1 Like

Rust is OO enough. Inheritance is a way of implicitly attaching methods, and Rust never recommends clever implicitness.

1 Like

This topic’s OP has decided they wanted to close this topic.