Arc subtypes

I know Rust prefers composition over inheritance, but not having inheritance makes it difficult to implement things like compilers (say, symbol table), because, besides having to make traits with is_x_subtype() (actually this is a good method, but I'm just listing this case as an example), you've to deal with using Rc<A>. I've ran into issues when using Rc with dyn types. If you see my posts at the accounts @Klaider/@Hydroper you see what I'm referring to.

Lately the last time I tried to implement a symbol table I faced a limitation on the language features in regards to Rc type conversion. I found that implementing a symbol table without inheritance was just noising the code.

Then why not just allow the Rust programmer to declare "subtypes" (reference types based on Arc and Weak) and allow inheritance in some way? No need to call them "classes" (as that may seem a confusing term when compared to struct). If possible a proposal could be made to allow inheritance in a way that fits into the language.

#[arc]
struct Symbol {
    m_cloud: SymbolCloud::Weak;
}

impl Symbol {
    fn str_value(&self) -> &str {
        ""
    }
}

#[arc]
struct StringConstant: Symbol;

impl StringConstant {
    #[override]
    fn str_value(&self) -> &str {
        "a"
    }
}

It must also be possible to use weak reference. In this case, something like A::Weak will do:

#[arc]
struct A {
    m_parent: A::Weak,
}

Instance-of asserting (reserve the method instance_of):

assert!(o.instance_of::<C>());

Covariant and contravariant conversions:

let u = o.upcast::<A>();
let d = o.downcast::<B>();

Type annotation:

let o: O = O::new(...);
// equivalent, but does not make sense because of the lifetime
let o: &O = o;

let o = o.clone(); // could work, but unnecessary

Can't you use a dyn Any trait object? (see here). Or better yet, mopa

With mopa (or with Any), your superclass is actually a trait object, which in OO terms is used quite like a abstract class (that is, a class with only virtual methods).

.. but actually, I think you should get more familiarized with Rust idioms before reaching to OO! In Rust, it's preferable to use an enum in most cases where you would use subtyping in OO languages.

4 Likes

And that's precisely what the Rust compiler uses internally for most of the types that would be a class hierarchy in a standard OOP compiler!

As much as anything in any compiler is "standard" anyway...

Is there a way to upcast_ref in mopa? Is there also a way to have multiple supertypes, like Sprite < InteractiveObject < DisplayObjectContainer < DisplayObject (out of compiler purpose, as I guess it can be useful for Flash Platform like display list)?

This is basically #![feature(trait_upcasting)].

If you want to polyfill this, you need to provide as_super methods on the subtrait.

This would be handled by traits having multiple supertraits, or since this is a single-inheritance chain, the supertrait having a supertrait. E.g.

trait DisplayObject {}
trait DisplayObjectContainer : DisplayObject {}
trait InteractiveObject : DisplayObjectContainer {}
trait Sprite : InteractiveObject {}

But this smells a lot like you're just trying to smash an OOP design into Rust instead of considering what design would be best for Rust. I suggest taking the actual problem you're trying to solve/model to the users forum to hash down to the desired solution.

In general, IRLO is the place to discuss for "how can the language/compiler change so this task is easier three years from now," and URLO is the place to discuss "how can I best solve this today." (And the Zulip is the place to discuss "how do I implement the change" or other chatter about actually working on the language/compiler.)

4 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.