Similar to @eterevsky, I thought that associated types could be used to encode existential types (abstract types), as attempted below.
However, the only way I can get rustc to accept this code is when I say exactly what these associated types are, and expose their identities in terms of concrete types (i.e., String
and u32
).
This is exactly what I wanted to avoid. In particular, the tuple pattern that works below doesn't generalize to the case where I have an array or a list.
In those cases, I guess I need to abstract the associated type with another trait?
Is that right?
Details:
The trait T
has associated type t
. I define two implementations for this trait, with different definitions of t
. Then, I try to create a pair where the first and second components of the pair look "the same". That is, I want that both just mention trait T
, and each leaves t abstract, via an implicit existential quantifier. However, that version of the code is rejected by rustc. It insists that I give the concrete identity of t
in both cases.
Questions:
Suppose, I want to create an array, list, or other generic structure with T
objects, not just pairs of T
objects. The pattern below is undesirable, since in these cases, I want the two pair components to have exactly the same type, including exactly the same associated types.
What's the canonical solution to this kind of problem?
In OCaml, I'd use first-class modules. I'm stuck since I can't find the corresponding pattern in Rust. Perhaps it requires a more involved use of trait objects?
// Traits can have associated types:
#![feature(collections)]
use std::fmt::Debug;
//use std::string;
trait T : Debug {
type t;
fn get (self:&Self) -> Self::t ;
fn foo (self:&Self, Self::t ) -> String ;
}
#[derive(Debug)]
pub enum Foo { Foo }
#[derive(Debug)]
pub enum Bar { Bar }
impl T for Foo {
type t = String;
fn get (self:&Self) -> String { String::from_str("foo") }
fn foo (self:&Self, s:Self::t) -> String { s }
}
impl T for Bar {
type t = u32;
fn get (self:&Self) -> u32 { 0 }
fn foo (self:&Self, _s:Self::t) -> String { String::from_str("bar") }
}
#[derive(Debug)]
struct Packed {
two : (Box<T<t=String>>,Box<T<t=u32>>)
}
pub fn main () {
let a = Packed { two : (Box::new(Foo::Foo),
Box::new(Bar::Bar)) } ;
println!("{:?}", a);
}