Of course this leads (assuming we had a `Collection` trait) to the horrendously 
ugly `Numbers::<i32, ~[i32], f32, ~[f32]>(...)` if you wanted to be explicit. 
But hopefully your code would be such that Rust could infer the bounds. This 
will be alleviated in the future by associated items, but that will probably be 
post 1.0.

(I might be getting a little off-topic here)

~Brendan

On 7 Dec 2013, at 5:27 pm, Brendan Zabarauskas <bjz...@yahoo.com.au> wrote:

> I’m not sure I understand everything in your post, but this is how I’d write 
> you first C++ example:
> 
>    struct Numbers<IV, FV> {
>        priv iv: IV,    // priv so the struct can only be constructed in this 
> module
>        priv fv: FV,
>    }
> 
>    impl<I: Int, IV: Collection<I>, F: Float, FV: Collection<F>> Numbers<IV, 
> FV> {
>        pub fn new(iv: IV, fv: FV) -> Numbers<IV, FV> {
>            Numbers { iv: iv, fv: fv }
>        }
>    }
> 
> You can also write type aliases with type parameters, but I don’t think you 
> can enforce trait bounds on them afaik:
> 
>   type A<T> = (T, int);
> 
> 
> ~Brendan
> 
> 
> On 7 Dec 2013, at 5:10 pm, David Piepgrass <qwertie...@gmail.com> wrote:
> 
>> Rust newb here. I have theoretical questions.
>> 
>> Recently I noticed that Higher-Kinded Types (HKTs) have been mentioned on 
>> the mailing list a lot, but I had no idea what a HKT was, or what it might 
>> be good for. After reading about them a little, they reminded me of C++'s 
>> "template template parameters". In C++ you can almost write something like 
>> this:
>> 
>> template <template <typename> class collection>
>> struct Numbers {
>>   collection<int> integers;
>>   collection<float> floats;
>> };
>> 
>> So then you can write Numbers<vector> for a structure that contains 
>> vector<T> collections, and Numbers<list> for a structure that contains 
>> list<T> collections. EXCEPT that it doesn't actually work, because vector<T> 
>> has two template parameters (the second one, the allocator, is normally left 
>> at its default). Let's ignore that, though.
>> 
>> So that brings me to my first question: is this what "higher-kinded types" 
>> means? What is the difference, if any, between HKT and C++ "template 
>> templates"?
>> 
>> However, as a C++ developer I never actually used a "template template" 
>> parameter because I didn't know they existed for a long time. So instead I 
>> would have written this, which has the same end-result:
>> 
>> struct VectorTrait
>> {
>>    template<typename T>
>>    struct collection { typedef vector<T> type; };
>> };
>> struct ListTrait
>> {
>>    template<typename T>
>>    struct collection { typedef list<T> type; };
>> };
>> 
>> template<typename Traits>
>> struct Numbers
>> {
>>    Traits::collection<int>::type integers;
>>    Traits::collection<float>::type floats;
>> };
>> // Use Numbers<VectorTrait> for vector<T>, Numbers<ListTrait> for list<T>.
>> 
>> This is clunkier, but it would have been a bit simpler if C++ supported 
>> templatized typedefs:
>> 
>> struct VectorTrait
>> {
>>    template<typename T> typedef vector<T> collection;
>> };
>> struct ListTrait
>> {
>>    template<typename T> typedef vector<T> collection;
>> };
>> 
>> template<typename Traits>
>> struct Numbers
>> {
>>    Traits::collection<int> integers;
>>    Traits::collection<float> floats;
>> };
>> // Now write Numbers<VectorTrait> instead of Numbers<vector>,
>> //           Numbers<ListTrait> instead of Numbers<list>.
>> 
>> I have found that because of the existence of typedef, "template template" 
>> parameters are never actually necessary; so far, I've never seen a situation 
>> where the typedef-based solution wasn't almost as good. Also, I have found 
>> that "trait" types filled with typedefs seem to be a more general thing than 
>> "template template"; they allow you to do things that would be very 
>> difficult or impossible without them. For example you can use 
>> typedefs-in-a-struct to create circular references among types that don't 
>> "know" about each other:
>> 
>> // I call this a "Combo"; I don't know if the technique has a standard name
>> struct MyCombo {
>>    typedef ConcreteA<Traits> A;
>>    typedef ConcreteB<Traits> B;
>>    typedef ConcreteC<Traits> C;
>> };
>> template<typename Combo>
>> class ConcreteA { Combo::B* b; ... };
>> template<typename Combo>
>> class ConcreteB { Combo::C* c; ... };
>> template<typename Combo>
>> class ConcreteC { Combo::A* b; ... };
>> 
>> Here I've created a network of types (ConcreteA<MyCombo>, 
>> ConcreteB<MyCombo>, and ConcreteC<MyCombo>) that are linked together through 
>> the "Combo" type MyCombo, so the types can all use each other, but none of 
>> the types refer to each other directly. This design allows you to freely 
>> swap in different implementations of A, B, and C; it has similar advantages 
>> to "dependency injection" or "inversion of control" in languages like Java 
>> and C#, except that the linkages are all defined statically at compile-time, 
>> so no dynamic dispatch is required.
>> 
>> Without the ability to define "typedefs", this approach is not possible at 
>> all if there is a cyclic relationship. Also, if the combo declares more than 
>> three types, it becomes impractical to specify all those types on the 
>> classes directly as type parameters.
>> 
>> In C# I learned that this quickly becomes a major problem if you need to 
>> parameterize on more than one or two types. I tried to do "generic" math 
>> (which requires at least two type parameters due to the under-designed 
>> standard libraries) and I also implemented a GiST data structure (see 
>> http://en.wikipedia.org/wiki/GiST), and found out that the lack of any 
>> analog to C++ typedef makes both of those tasks very clumsy, while also 
>> making the code hard to read, because you end up with a rats' nest of type 
>> parameters (or if you omit (otherwise necessary) type parameters, you might 
>> use lots of casts instead.)
>> 
>> So I guess that leads me to two more questions.
>> 
>> 2. Does Rust have a "typedef" equivalent that can be used in this way?
>> 3. Does it make sense to just suggest "just use typedefs instead of 
>> Higher-Kinded Types"?
>> 
>> _______________________________________________
>> Rust-dev mailing list
>> Rust-dev@mozilla.org
>> https://mail.mozilla.org/listinfo/rust-dev
> 
> _______________________________________________
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev

_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to