Is it possible to declare a type alias inside a trait?
Asked Answered
N

2

6

Existing syntax allows us to write a default value for associated type:

trait Foo {
    type Bar = i32;
}

I want something like C++:

trait Foo {
    typedef int Bar;
}

This is not valid Rust code, but tries to show my intention:

trait Foo<T> {
    trait Trait = Into<T> + /* 10 other traits dependent on T */;
    
    fn foo(x: Type) -> Trait;
}
Neille answered 24/11, 2020 at 15:10 Comment(9)
What exactly do you mean by "I want something like C++"?Cran
And why do you want this? How would you use it?Unschooled
@Unschooled It's a very strange question for me. We have type aliases in Rust, why we shouldn't to want to use them inside a trait definition?Neille
That second snippet does not make much sense, even if pseudo-code. One can add multiple trait bounds to an associated type, but not treat that sum of constraints as a type in itself. Perhaps you are interested in this?Breskin
Your example usage doesn't make sense to me. You have a generic type T and then you try to treat it as a trait because you add other traits to it (+ Clone). Those two concepts aren't compatible.Unschooled
Creating a new trait inheriting from the previous ones would probably solve the real problem here.Indeterminable
"Is Rust a really C++ killer" for the last time, no. no and no, rust in my opinion is not at all a C++ killer. It's a clear replacement for C that all.Immensurable
why people downvote this question — I didn't downvote this question, but look at the amount of comments and edits that have been made in the short time since you posted it. The question was very unclear in it's original form. People presumably read it, saw it was unclear, downvoted, and moved on with their day. To avoid those types of downvotes, ensure that questions are abundantly clear from the beginning.Unschooled
Is Rust a _really_ C++ killer — why do you believe it is? Can you point to a Rust page that suggests that is its purpose? if even such trivial things are rocket science — oftentimes, things that we think are "trivial" aren't when additional constraints like memory safety or lack of undefined behavior are required.Unschooled
Q
3

While trait aliases are currently unstable, you can emulate them. To create an "alias", define a new empty trait and write a blanket implementation for all types that satisfy the traits you want the alias to match. For example:

trait Short<T>: Into<T> /* plus others */ {}
impl<T, U> Short<T> for U where U: Into<T> /* plus others */ {}

The new trait can be used the same way you'd use an alias:

trait Foo<T> {
    // Ret is bound by Into<T> and other bounds provided by Short
    type Ret: Short<T>;

    fn example(&self) -> Self::Ret;
}

struct X;

impl Foo<u32> for X {
    type Ret = u8;  // compiles because u8 is Into<u32>

    fn example(&self) -> u8 {
        0
    }
}
Quartana answered 24/11, 2020 at 16:47 Comment(0)
U
3

No, it is not possible to declare a type alias inside a trait as of Rust 1.48.

Instead, use the existing type alias functionality:

type FooBar = i32;

trait Foo {
    fn usage(&self, _: FooBar);
}

Your specific example may be solved by a combination of two unstable features:

#![feature(type_alias_impl_trait)]
#![feature(trait_alias)] // Stable alternative available in link below.

trait FooBar<T> = Into<T>; // And 10 other traits dependent on T

trait Foo<T> {
    type Ret: FooBar<T>;

    fn example(&self) -> Self::Ret;
}

impl Foo<i32> for i32 {
    type Ret = impl FooBar<i32>;

    fn example(&self) -> Self::Ret {
        42
    }
}

See also:

Unschooled answered 24/11, 2020 at 15:13 Comment(1)
Thank you very much. It's definitely not what I want, but I've got the idea. Rust way is a such curly way.Neille
Q
3

While trait aliases are currently unstable, you can emulate them. To create an "alias", define a new empty trait and write a blanket implementation for all types that satisfy the traits you want the alias to match. For example:

trait Short<T>: Into<T> /* plus others */ {}
impl<T, U> Short<T> for U where U: Into<T> /* plus others */ {}

The new trait can be used the same way you'd use an alias:

trait Foo<T> {
    // Ret is bound by Into<T> and other bounds provided by Short
    type Ret: Short<T>;

    fn example(&self) -> Self::Ret;
}

struct X;

impl Foo<u32> for X {
    type Ret = u8;  // compiles because u8 is Into<u32>

    fn example(&self) -> u8 {
        0
    }
}
Quartana answered 24/11, 2020 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.