# \[Pre-RFC\] object\_oriented

**URL:** <https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925>\
**Category:** language design\
**Created:** [November 26, 2023, 11:18am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925 "2023-11-26T11:18:03Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 26, 2023, 11:18am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/1 "2023-11-26T11:18:03Z")

</div>

- Feature Name: `object_oriented`
- Start Date: 2023-11-26
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary

Support for optional object-oriented classes under a crate `object_oriented`.

# Motivation

Class inheritance is commonly used in the following platforms:

- [W3C](https://www.w3.org) — Uses class inheritance for custom elements
- [AIR SDK](https://airsdk.dev) — Uses class inheritance for display objects

Using procedural macros does not solve the issue of class inheritance:

- it limits the programmer to specifying all super classes for every class declaration,
  - which allows the programmer to miss or mispell a super class in the sequence of super classes for every class declaration;

- it does not support virtual methods, `abstract` methods and `override` methods.

The `object_oriented` crate is been reserved for this RFC.

### Virtual methods

Virtual methods with support for dynamic dispatch are often required in an object-oriented model, and abstract methods allow for exhaustive implementations of subclasses.

### Protected methods

Protected methods are important.

### Flexibility

This proposal suggests a form of object-oriented programming for Rust that may be used to model classes based either on `Box`, `Rc`, or `Arc`.

# Guide-level explanation

Use the `object_oriented` crate to define object-oriented classes. To use this crate, use the following attribute in your crate:

```rust
#![object_oriented]

```

A class must have either `BoxedObject`, `UnsyncObject`, or `SyncObject` as the topmost super class.

The following program illustrates defining a class based on `Arc`:

```rust
use object_oriented::{class, sync::SyncObject};

class! {
    abstract struct C0: SyncObject {
        x: f64,
        y: f64 = 0.0,
    }
    impl {
        fn constructor(&mut self) {
            self.x = 0.0;
        }
        abstract fn f(&self);

        fn f1(&self) {}
    }
}

class! {
    struct C1: C0 {
    }
    impl {
        fn constructor(&mut self) {
            super();
        }

        override fn f(&self) {}

        override fn f1(&self) {
            super.f1();
        }
    }
}

let mut object = C1::new();
object.x = 10.0;

```

Object-oriented classes are recommended for particular cases, such as for nodes in interactive systems.

- Use `object_oriented::boxed::BoxedObject` as the topmost super class if the class is based on `Box`.
- Use `object_oriented::unsync::UnsyncObject` as the topmost super class if the class is based on `Rc`.
- Use `object_oriented::sync::SyncObject` as the topmost super class if the class is based on `Arc`.

## Protected methods

Protected methods are available through the `priv` reserved word:

```rust
class! {
    struct C1: SyncObject {}
    impl {
        priv abstract fn f(&self) {}
    }
}

```

Such methods are only accessible from within a class and its subclasses.

## Traits

A class C1 implements several traits:

- If not a `BoxedObject`, `impl Clone for C1` — Clones the reference
- `impl Hash for C1` — Hashes the reference
- `impl PartialEq for C1` — Reference comparison
- `impl Eq for C1`
- `impl AsRef<C1> for C1`
- For every super class _C0_, `impl AsRef<C0> for C1`
- If not a `BoxedObject`, for every super class _C0_, `impl From<C1> for C0`
- If not a `BoxedObject`, for every super class _C0_, `impl TryFrom<C0> for C1`

It does not implement `Deref`; instead, it introduces a new object-oriented name resolution to Rust, for use with `object_oriented`.

## Representation

Classes are reference types, internally boxed with either `Box`, `Rc`, or `Arc`.

## Weak references

You can work with weak references in the context of reference counting using `Weak` and `object.downgrade()`:

```rust
use object_oriented::sync::Weak;

let weak_reference: Weak<C1> = object.downgrade();

```

## Constructor parameters

The constructor accepts a common formal parameter list, including the `where` clause. It must always contain a `&self` or `&mut self` parameter.

The constructor subroutine and the special `new` method have the same parameter list, except that the `new` method excludes the first parameter (`self`).

# Reference-level explanation

## Syntax

- `class!`
  - Consists of a `struct` followed by an empty `impl`
  - `struct`
    - Consists of a name, super class (non optional), and fields
    - Fields may specify a default initializer; more details in the Object-oriented fields section

  - `impl`
    - Consists of optional constructor and methods in any order.

- A `super();` statement
  - Invokes the super constructor subroutine
  - `super();` is only allowed at the block of a constructor subroutine and the subroutine's execution must not terminate before `super()` executes (control flow check). It must appear if and only if the class has a super class not equals the topmost super class.

- A `super.method()` expression
  - This expression invokes a method defined by the super class.
  - This expression requires `self` in scope whose static type is a a class (`C`, `&C` or `&mut C`).

- Qualifiers inside `impl` block from `class!`: `abstract` and `override`
  - Visibility, `abstract` and `override` are allowed to be in any order

## Availability

The `object_oriented` crate is available to the programmer by using the following crate attribute:

```rust
#![object_oriented]

```

When the `object_oriented` attribute is used, consequently the programmer's crate depends on `std`, as `object_oriented` relies on `std::sync` for its `object_oriented::sync` module, and the crate name `object_oriented` is made available to the programmer's crate.

The `object_oriented` class is natively implemented in `rustc`.

The crate contains the following items:

- the memory-specific models:
  - `object_oriented::boxed::BoxedObject`,
  - `object_oriented::unsync::UnsyncObject`,
  - `object_oriented::unsync::Weak`,
  - `object_oriented::sync::SyncObject`,
  - `object_oriented::sync::Weak`;

- the `class!` macro;
- the `ClassError` struct (exception returned from `object.to::<T>()`).

The `Object` class defines the following methods:

- `object.is::<T>()` — Indicates whether an object is a class `T` or any subclass of `T`
- `object.to::<T>()` — Converts an object to a class `T`, returning `Result<T, ClassError>` (alternative to `.try_into()`)
- `object.downgrade()` — Downgrades a strong reference to a weak reference, returning `object_oriented::Weak::<T>`

## Representation

The structure of a class is put into either a `Box` (for `BoxedObject`s), a `Rc` (for `UnsyncObject`s), or an `Arc` (for `SyncObject`s).

## Class

A class is a struct attached with additional object-oriented class characteristics:

- An super class (`struct Subclass: SuperClass`)
  - `BoxedObject`, `UnsyncObject` and `SyncObject` are the only classes without a super class.

- `abstract` modifier
  - Indicates that the class privatizes its constructor; therefore, the user cannot call `C::new()`, but can call `super()` to invoke the class constructor.

- A constructor subroutine
  - The constructor subroutine is defined inside the `impl` block of the `class!` invokation, in the form `fn constructor(&mut self) {}`.
    - The first parameter can be either `self: &Self` or `self: &mut Self`

  - The constructor subroutine must contain a `super();` statement if it extends a class other than `Object`.

- A `new` static method is defined based on the constructor subroutine and the `abstract` modifier. This method creates the class object and invokes the constructor subroutines.

A class _C1_ implements all the following traits as already covered in the above explanation:

- If not a `BoxedObject`, `impl Clone for C1` — Clones the reference
- `impl Hash for C1` — Hashes the reference
- `impl PartialEq for C1` — Reference comparison
- `impl Eq for C1`
- `impl AsRef<C1> for C1`
- For every super class _C0_, `impl AsRef<C0> for C1`
- If not a `BoxedObject`, for every super class _C0_, `impl From<C1> for C0`
- If not a `BoxedObject`, for every super class _C0_, `impl TryFrom<C0> for C1`

## Object-oriented fields

- The name of class fields must not conflict with the fields of the super classes.
- Every class field may have a default initializer. The default initializer is not a constant; it is allowed to be a runtime evaluated expression.
- If a class field has no default initializer, it must be first assigned in the constructor subroutine.
- For `SyncObject`s, fields are represented by `RwLock<T>`.
  - Referencing a field returns is equivalent to `lock.read().unwrap()` or `lock.write().unwrap()`

- For `UnsyncObject`s, fields are represented by either `Cell` or `RefCell`.
  - `RefCell` is used for `String`, `Vec`, `Box`, and `Rc` fields.

## Object-oriented instance method

An object-oriented instance method is a struct's instance method with additional characteristics:

- If it does not override a method, it must not conflict with a method in any of the super classes.
- An `override` modifier
  - If present, must override a method in a super class, with the same method signature.

- An `abstract` modifier
  - If present, all subclasses of the enclosing class must override this method.
  - If present, the method definition must contain no body.

- A protected visibility (`priv`)
  - This visibility means that the method is only available for use within the `impl` block of a class and its subclasses

## Strictness

- In a constructor subroutine, `self` is only allowed after `super();`. It cannot be used inside the arguments to `super();`.
- Object-oriented fields must implement `Send + Sync`.

## Object-oriented name resolution

An object-oriented name resolution is used for handling accesses to fields and methods (`o.x`, `o.method()`) in a base whose type is an object-oriented class:

- If the name resolves to a method in any of the classes in the hierarchy and the method is object-oriented, and the base is not `super`:
  - On execution, the method conditionally delegates control to overriding methods in subclasses (dynamic dispatch)

## Weak\<T\>

The `Weak<T>` struct, either `sync` or `unsync`, only allows `T` to be a class.

## Summary of compiler changes

- Detect optional usage of the `object_oriented` crate
  - Parsing and verification of the `class!` declaration
  - Object-oriented field or method resolution
  - Object-oriented classes
  - Object-oriented methods
  - Object-oriented fields

# Drawbacks

This proposal cannot be used as a way to interface with existing object-oriented systems as it relies on the Rust standard library to represent the classes (`Box`, `Rc`, and `Arc`).

# Rationale and alternatives

The crate `object_oriented` suggested by this proposal is not possible to be implemented by the user without changes to the `rustc` compiler: it involves attaching semantics to structs, fields, and methods, as well as introducing a dynamic dispatch resolution for the member expression (`object.x`); it also introduces to the language a `super();` statement and a `super.method_name()` expression.

Inheritance is often seen as an anti-pattern in Rust; however, this proposal adds object-oriented classes as part of a crate in the package registry, to which a developer can depend on optionally. Furthermore, it leverages the existing future reserved words `abstract` and `override`.

This feature can facilitate the development of frameworks. It serves an alternative to the Entity-Ccmponent-System pattern, which demands fragmenting nodes into smaller pieces. Object-oriented inheritance and Entity-Component-System both have their positives and negatives. It is up to the programmer which pattern they work with. Entity-Component-System leads more to code fragmentation, while object-oriented inheritance leads more to unification.

There are related inheritance proposals, but they do not focus on frameworks, however.

# Prior art

Inheritance is already seen in some form when using the web APIs, but the most important part where they are used are for custom elements. The [`oop_inheritance`](https://lib.rs/crates/oop_inheritance) crate implements an unreliable form of inheritance lacking dynamic dispatch, `abstract` and conciseness as covered in the Motivation section.

[AIR SDK](https://airsdk.dev) uses inheritance for the `DisplayObject` class. AIR SDK is a technology originated from the legacy Flash Platform.

# Unresolved questions

N/A

# Future possibilities

N/A

---

<div class="post-metadata">

**Author:** ![simonbuchan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonbuchan/32/9390_2.png) [@simonbuchan](https://internals.rust-lang.org/u/simonbuchan)\
**Post date:** [November 27, 2023, 9:39am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/2 "2023-11-27T09:39:06Z")

</div>

I'm a bit confused: is this an RFC for a crate? What would be being added to Rust itself? Including it in rustup distributions?

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 10:04am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/3 "2023-11-27T10:04:51Z")

</div>

It is a RFC for a crate and native object-oriented mechanisms in `rustc` that cannot be done through a procedural macro.

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [November 27, 2023, 12:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/4 "2023-11-27T12:06:21Z")

</div>

I would find this easier to follow if you could split it into two:

1. The changes to the compiler, `std` etc needed to support the `object_oriented` crate. This is the bit that's important in the RFC, because these are the bits that affect everyone; you can, of course, reference the `object_oriented` crate as justification for some of these features.
2. A separate text describing how the `object_oriented` crate uses the new features to implement your class inheritance system.

Right now, I'm not completely clear on which bits are procmacros from the `object_oriented` crate, and which bits need compiler or `std` changes. And therefore, I don't feel able to comment helpfully; in particular, I don't think it's worth your time arguing over details that live in the `object_oriented` crate, because that's the bit that's trivial to swap for a different implementation.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 12:40pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/5 "2023-11-27T12:40:10Z")

</div>

It is impossible for an user to implement this crate even if the language provides macros such as `class_extends!` because it uses intrinsic parts of the language. I could add a summary of the changes to the compiler, though...

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [November 27, 2023, 1:13pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/6 "2023-11-27T13:13:45Z")

</div>

> [@hydroper1](#):
>
> The `object_oriented` crate is available at the package registry. It is implemented using native compiler facilities.

> [@hydroper1](#):
>
> It is impossible for an user to implement this crate even if the language provides macros such as `class_extends!` because it uses intrinsic parts of the language

These two statements conflict. If the crate is available at the package registry, using native compiler facilities, then I can implement a variation on the crate myself, also using native compiler facilities. If I can't implement it using native compiler facilities, but depend on a close tie between the compiler and the crate, then it needs to be akin to `core` or `std`, not a crate from the package registry (not least because I could be using incompatible versions from a private registry instead of [crates.io](http://crates.io)).

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 1:22pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/7 "2023-11-27T13:22:45Z")

</div>

Understood, maybe the crate can be made available through a feature?

```rust
#![feature(object_oriented)]

```

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [November 27, 2023, 1:35pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/8 "2023-11-27T13:35:41Z")

</div>

The question you need to answer in your RFC is _what does `#![feature(object_oriented)]` do?_ In order to make the crate with the API you described possible.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 1:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/9 "2023-11-27T13:39:10Z")

</div>

Clarified that now:

> [@hydroper1](#):
>
> When the `object_oriented` feature is enabled, consequently the programmer's crate depends on `std`, as `object_oriented` relies on `std::sync`.

I forgot to say it also makes `object_oriented` available, similiar to `std`...

* * *

I have changed the attribute to `#![object_oriented]` from `#![feature(object_oriented)]` for compliance with `#![no_std]`.

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [November 27, 2023, 2:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/10 "2023-11-27T14:07:03Z")

</div>

I have several questions:

1. Why do you require so many traits? C++ doesn't require `Clone`, `Hash`, `PartialEq` or `Eq` for a class, which implies that you're building something to fit a Python or JavaScript model. Remember that a user of this system can require more than the implementation.
2. Why do classes have to be reference counted? Other objects in Rust are not reference counted - for example, `String` is not reference counted, and you can require something to be reference counted by type signature (take `&Arc<Self>`, `Weak<Self>` or similar in receiver position) if desired.
3. Why are fields represented by `RwLock<T>`? If I have an outermost lock for a data structure, having to then lock and unlock individual fields is going to waste CPU time for an operation that will always succeed.
4. How do I provide parameters to a constructor? An example here would be useful, including passing some parameters (but not all) up to the superclass constructor.
5. Why can't I run other code before calling `super()`? I understand why I can't access `self` before then, but you've now blocked me from deriving parameters for the superclass constructor based on my own parameters, which is a useful trick in Python.

The general theme I'm seeing here is that you've got a decent core feature that has to be implemented in the compiler (`abstract`, `override`, `super`, virtual methods), and then a chunk of stuff that's only needed because you're trying to build something that's interoperable as-is with one specific existing OO implementation.

I would prefer to see a split into a minimal OO system that lives in the compiler, and then room for external crates to require more functionality if needed for interop (e.g. requiring that you have `Arc<Self` instead of a stack allocation of `Self` or `Box<Self>`, adding requirements for extra traits, locking of fields etc).

Additionally, I'd like to see some discussion of how this affects [GTK Core Rust bindings](https://gtk-rs.org/gtk-rs-core/) and similar pre-existing bindings to OO libraries; for example, I'd expect a core Rust OO feature to enable [`wrapper`](https://gtk-rs.org/gtk-rs-core/stable/0.18/docs/glib/macro.wrapper.html) to be built atop native inheritance instead of using macros.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 2:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/11 "2023-11-27T14:26:33Z")

</div>

> [@farnz](#):
>
> Why do you require so many traits? C++ doesn't require `Clone`, `Hash`, `PartialEq` or `Eq` for a class, which implies that you're building something to fit a Python or JavaScript model. Remember that a user of this system can require more than the implementation.

I needed to implement these in `oop_inheritance` due to the following use-cases:

- using `DisplayObject`s as keys in a `HashMap`;
- finding `DisplayObject`s by equality in a `Vec`.

As to `Clone` though, it is because `Copy` implies `Clone`, so there is not much that can be done if not implementing `Clone`.

These implementations could be avoided though if Rust allows using classes inside `Arc` and `Weak`, maybe.

> [@farnz](#):
>
> Why do classes have to be reference counted? Other objects in Rust are not reference counted - for example, `String` is not reference counted, and you can require something to be reference counted by type signature (take `&Arc<Self>`, `Weak<Self>` or similar in receiver position) if desired.

For my use-case reference counting was right because `DisplayObject`s can be children of other `DisplayObject`s and reference their parent back through a `Weak` reference.

I could effortlessly adapt using `Arc<C>` and `Weak<C>` if implicit super class covariance conversions occur:

```rust
// MyClassB: MyClassA
let object: Arc<MyClassB> = Arc::new(MyClassB);
let object: Arc<MyClassA> = object.clone();

```

> [@farnz](#):
>
> Why are fields represented by `RwLock<T>`? If I have an outermost lock for a data structure, having to then lock and unlock individual fields is going to waste CPU time for an operation that will always succeed.

It was due to them being possibly mutated through a `mut` borrow of the class. In `oop_inheritance` I have instead generated `get_` and `set_` methods, either dealing with a reference (`ref` fields) or non reference type. The proposal also implies that the field access operations use either `*value.write().unwrap() = v` or `*value.read().unwrap()`.

> [@farnz](#):
>
> How do I provide parameters to a constructor? An example here would be useful, including passing some parameters (but not all) up to the superclass constructor.

I did not show that in practice, but in my `oop_inheritance` you were able to do this. I have not fully clarified all the available syntax, so I thought most readers could deduce it was allowed to specify parameters in the formal punctuated parameter list (including the `where` clause).

> [@farnz](#):
>
> Why can't I run other code before calling `super()`? I understand why I can't access `self` before then, but you've now blocked me from deriving parameters for the superclass constructor based on my own parameters, which is a useful trick in Python.

In JavaScript, `super()` is only allowed at the top; in ActionScript 3, `super()` is allowed anywhere. Maybe it is viable to allow it anywhere and forbid `self` only later, but that might be complicated considering the control flow checking?

* * *

In case, `Arc` covariance can already be useful for borrows:

```rust
let o: &Arc<B> = o;
let o: &Arc<A> = o;

```

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 4:17pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/12 "2023-11-27T16:17:30Z")

</div>

> [@farnz](#):
>
> I would prefer to see a split into a minimal OO system that lives in the compiler, and then room for external crates to require more functionality if needed for interop (e.g. requiring that you have `Arc<Self` instead of a stack allocation of `Self` or `Box<Self>`, adding requirements for extra traits, locking of fields etc).

I was not able to find a more minimal design because objects require some form of memory management and it is really hard because having default field initializers is useful. I have decided to split the topmost super class though into `BoxedObject` (for `Box`), `UnsyncObject` (for `Rc`), and `SyncObject` (for `Arc`).

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [November 27, 2023, 4:47pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/13 "2023-11-27T16:47:28Z")

</div>

Look at how C++ does objects - there's no memory management required for C++ object, or for Rust trait objects (a different solution in the same design space).

I'm going to bow out for a bit, but my impression is that you've got a single exemplar of OO in mind (ActionScript), and you're trying to bring that specific model directly into Rust. I'd strongly recommend that you look at how C++ does objects, and how at least two different C OO systems work (say GObject and the Linux kernel), because they have very different assumptions underlying them to the ones that you're working from (they don't need dynamic memory management, although you can heap-allocate objects if you so choose, they don't need locking of fields, because they can delegate that to higher levels etc).

To make this RFC strong, you'll need to explain why your system has requirements that C++'s system, GObject and Linux kernel objects don't have, and what forces them into existence. You'd probably also gain from considering how this system behaves in contrast to trait objects (an existing Rust concept with inheritance); trait objects, for example, don't need runtime locking because you can use the existing system to ensure shared xor mutable.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 27, 2023, 5:50pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/14 "2023-11-27T17:50:48Z")

</div>

I never heard of GObject, hmm... it looks a bit unusual to me, I might come up with a new RFC then...

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [November 27, 2023, 6:25pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/15 "2023-11-27T18:25:55Z")

</div>

> [@hydroper1](#):
>
> I never heard of GObject, hmm... it looks a bit unusual to me

It's at the core of GTK and Gnome as a whole, so it's not exactly a niche implementation.

It's also worth pointing out that Rust not having class/struct inheritance was never an oversight, but a purposeful design choice based on the 2 decades of industry experience using OOP that preceded the language as a whole.

So the proposal needs to explain why this integration would justify reversing course on that point.

---

<div class="post-metadata">

**Author:** ![Noratrieb](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/noratrieb/32/12440_2.png) [@Noratrieb](https://internals.rust-lang.org/u/Noratrieb)\
**Post date:** [November 28, 2023, 6:10am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/16 "2023-11-28T06:10:23Z")

</div>

What specific problem is this solving? And are there other ways to solve this problem? The RFC doesn't talk about this.

---

<div class="post-metadata">

**Author:** ![hydroper1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hydroper1/32/12099_2.png) [@hydroper1](https://internals.rust-lang.org/u/hydroper1)\
**Post date:** [November 28, 2023, 11:57am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/17 "2023-11-28T11:57:30Z")

</div>

I decided that I will try sticking to ActionScript 3 and Adobe AIR instead of using Rust due to the lack of inheritance. I will be inactive here for a while maybe unless I touch my `as3_parser` project.

My problem though is that Rust is not flexible and expressive enough compared to Adobe AIR for the development of different things: in my case it is a certain game project that I am having to interrupt due to lack of a framework that matches my needs. The Bevy Engine uses a different pattern that I am not used to.

---

<div class="post-metadata">

**Author:** ![caellian](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/caellian/32/9680_2.png) [@caellian](https://internals.rust-lang.org/u/caellian)\
**Post date:** [November 29, 2023, 6:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/18 "2023-11-29T18:52:26Z")

</div>

You can get similar behavior to inheritance via composition by implementing `AsRef<InnterType>` for all "inherited" objects.

I do agree though that bindings to OO feel overly complicated in a lot of cases. Something like `web-sys` is too hard to do just right and could be greatly simplified if Rust provided better ergonomics for such crates. The problem is that it's a very tricky thing to get it right and having a Rust version of OO doesn't really tackle the bindings thing in a way that would work (i.e. can't copy entire browser state into WASM memory to make `web-sys` more ergonomic).

What you're proposing though is a general shift in Rust's paradigm which as others have pointed out requires very good rationale. I started developing in OO, and don't miss it even a little with Rust because there's very few concepts from OO that Rust can't mimic in some way. I think it boils down to experience, once you're more comfortable with a language you stop looking for "that other language's" features in it because you start to model you code in a way that suits it better.

With regards to game dev, I suggest you examine Bevy a bit more because it's basically what most game engines are steering towards (e.g. Unity DOTS). It's almost a reference implementation of all best practices for a general purpose game engine (and ECS), so much so that there's very few reasons to write one from scratch in Rust.

---

<div class="post-metadata">

**Author:** ![piegames](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/piegames/32/9140_2.png) [@piegames](https://internals.rust-lang.org/u/piegames)\
**Post date:** [November 30, 2023, 9:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/19 "2023-11-30T21:31:25Z")

</div>

I'm still unclear about which features Rust exactly lacks to build OO features as a library using macros. glib/gobject did this with plain C over twenty years ago, and the rust bindings show that this is totally possible to achieve in Rust as well. There are many more object based libraries in the ecosystem, like pyo3 (Python bindings, with the Python model), probably whatever the current state of Qt bindings is, some PDF manipulation libraries, etc.

I think that any proposal about object oriented Rust should:

- Explain which features currently cannot (easily) be implemented in Rust with macros
- Show that the language changes are minimal and agnostic of the OO model
  - Especially, it should cater to both systems with inner mutability and those who keep using the Rust borrow checker.

- Show that the language changes will improve the code of existing OO projects like gtk-rs and pyo3
- Be "zero-cost"

---

<div class="post-metadata">

**Author:** ![cathaysia](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cathaysia/32/10820_2.png) [@cathaysia](https://internals.rust-lang.org/u/cathaysia)\
**Post date:** [December 5, 2023, 10:51am UTC](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925/20 "2023-12-05T10:51:59Z")

</div>

this is not a good idea in any way.

[Next page](https://internals.rust-lang.org/t/pre-rfc-object-oriented/19925.md?page=2)
