On 16/11/13 03:05, Gábor Lehel wrote:
Hello list,
I have some ideas about typey things and I'm going to write them down.
It will be long.
No kidding.
It would be nice if `Trait1 + Trait2` were itself a trait, legal in
the same positions as any trait. This is already partly true: in trait
bounds on type parameters and super-traits of traits. Where it's not
true is trait objects, e.g. `~(ToStr + Send)`. Having this could
remove the need for the current `~Trait:OtherTraits` special syntax.
I wonder whether lifetimes could also be interpreted as traits, with
the meaning: "[object of type implementing lifetime-trait] does not
outlive [the given lifetime]". This is an honest wondering: I'm not
sure if it makes sense. If it does make sense, it would fit in
perfectly with the fact that 'static is already a trait. Together with
the above, it might also allow a solution for capturing borrowed data
in a trait object: you could write `~(Trait + 'a)`.
How does this interact with vtables?
Note we can already get something similar with
trait Combine1And2: Trait1 + Trait2 {}
impl<T: Trait1 + Trait2> Combine1And2 for T {}
// use ~Combine1And2
which makes it clear how the vtables work, since Combine1And2 has its
own vtable explicitly constructed from the two traits. (I guess ~(Trait1
+ Trait2) would be most useful if one could cast down to ~Trait1 and
~Trait2.)
The next few are going to be about higher- (or just different-) kinded
generics. To avoid confusion, I'm going to use "built-in trait" to
mean things like `Freeze` and `Send`, and "kind" to mean what it does
everywhere else in the non-Rustic world.
I think the best available syntax for annotating the kinds of types
would be to borrow the same or similar syntax as used to declare them,
with either `type` or `struct` being the kind of "normal" non-generic
types (the only kind of type that current Rust lets you abstract
over). [I prefer `type`, because both structs and enums inhabit the
same kind.] This is kind of like how C++ does it. For example, the
kind of `Result` would be `type<type, type>`. Our `type` corresponds
to C++'s `typename` and Haskell's `*`, and `type<type, type>` to C++'s
`template<typename, typename> class` and Haskell's `* -> * -> *`. So,
for example, you could write the fully kind-annotated signature of an
identity function restricted to Result-shaped types (yeah, actually
doing this would be pointless!) as:
fn dumb_id<type<type, type> R, type A, type B>(x: R<A, B>) -> R<A, B>;
To explicitly annotate the kind of the Self-type of a trait, we could
borrow the `for` syntax used in `impl`s. Here's the fully
kind-annotated version of the `Functor` trait familiar from Haskell:
trait Functor for type<type> Self {
fn fmap<type A, type B>(a: &Self<A>, f: |&A| -> B) -> Self<B>;
}
(Obviously, explicitly annotating every kind would be tiresome, and
`Self` is a little redundant when nothing else could go there. I could
imagine `trait Functor for type<type>`, `trait Functor for Self`,
and/or `trait Functor` all being legal formulations of the above. I'll
get back to this later.)
Could this be:
fn dumb_id<R<type, type>, A, B>(x: R<A, B>) -> R<A, B>;
and
trait Functor<type> {
fn fmap<A, B>(a: &Self<A>, f: |&A| -> B) -> Self<B>;
}
Then something like A<type<type>, type> would correspond to A :: (* ->
*) -> * -> *. Speaking of which, could we just use *, `R<*, *>`,
`R<*<*>, *>`, `trait Functor<*>`? Although that looks a little cryptic
in the nested case.
Huon
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev