Skip to content

"Notes on adding Constraint Kinds to Rust" #1

@Centril

Description

@Centril

Notes from @withoutboats
https://gist.github.com/withoutboats/8b0eb3012203244bcf3a4e1a4be8819c


Notes on adding Constraint Kinds to Rust

Background: Constraint Kinds

a trait can be thought of as a type operator generating a "constraint" - what in Rust would usually be called a bound. For example:

// Declares a new item `Foo` with kind `type -> constraint`
trait Foo { }

// T: Foo applies Foo to `T`, `(type -> constraint)(type) => constraint`
fn bar<T>() where T: Foo { }

Constraints are facts that have to hold true when the generic item is instantiated to a concrete item.

Haskell has an extension which lets you talk about constraints as a first class language feature. This gist is abound a natural way to extend Rust to support some way of talking about constraints, with the context of Rust's syntax (which is very different from Haskell).

Mainly we handle this by dealing with type -> constraint objects, rather than constraint objects directly.

Associated traits

trait Foo {
    trait Bar;
    fn baz<T: Self::Bar>(arg: T);
}

fn quux<T>() where T: Foo + <T as Foo>::Bar

An associated trait is an associated item of the kind type -> constraint. You can then use it as a bound elsewhere

Trait parameters

fn foo<T, trait Trait>() where T: Trait

You could also parameterize items by traits, having the kind type -> constraint, to use them in bounds

Meta traits

meta trait Monoid {
    const EMPTY: Self;
    fn append(lhs: Self, rhs: Self) -> Self;
    fn concat(elems: Vec<Self>) -> Self {
         elems.into_iter().fold(Self::EMPTY, Self::append)
    }
}

impl Monoid for Add + Zero {
    const EMPTY: Self = Zero::ZERO;
    fn append(lhs: Self, rhs: Self) -> Self {
        lhs + rhs
    }
}

fn noop<T, trait M>(arg: T) -> T where T: M, M: Monoid {
    T + <T as M>::EMPTY
}

// mappend::<Add + Zero> adds 2, whereas mappend::<Mul + One> doubles it
fn mappend2<trait M>(arg: i32) -> i32 where i32: M, M: Monoid {
     M::append(arg, 2)
}

The use of Self here is problematic, still need to figure out the syntax around that.

Note

We won't do this any time in the near future, its just interesting to think about.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions