Mixin layers and cyclic dependencies

Don Clugston dac at nospam.com.au
Tue Sep 12 00:39:34 PDT 2006


Steve Horne wrote:
> I wrote the following as a quick test if an idea. The idea in itself
> worked out fine, but I hit a problem I wasn't expecting. The problem
> is that the code tries to set up a cyclic dependency through
> templates...
> 
> template t_ML_Init (alias FINAL, int p_Leaf_Max, int p_Branch_Max)
> {
>   alias FINAL  m_Final;
> 
>   const int m_Leaf_Max   = p_Leaf_Max;
>   const int m_Branch_Max = p_Branch_Max;
>   
>   struct c_Common_Head
>   {
>     int m_Size;
>     int m_Height;
>   }
> 
>   struct c_Leaf_Item
>   {
>   }
> 
>   struct c_Branch_Item
>   {
>     void*  m_Child;
>   }
> 
>   typedef m_Final.c_Leaf_Item  [m_Leaf_Max  ]  c_Leaf_Items;
>   typedef m_Final.c_Branch_Item[m_Branch_Max]  c_Branch_Items;
> 
>   struct c_Leaf
>   {
>     m_Final.c_Common_Head            m_Head;
>     m_Final.c_Leaf_Item[m_Leaf_Max]  m_Items;
>   }
> 
>   struct c_Branch
>   {
>     m_Final.c_Common_Head               m_Head;
>     m_Final.c_Branch_Item[m_Branch_Max] m_Items;
>   }
>   
>   int* Size (m_Final.c_Leaf* p)
>   {
>     return &((cast(c_Common_Head*) p).m_Size);
>   }
> 
>   int* Size (m_Final.c_Branch* p)
>   {
>     return &((cast(c_Common_Head*) p).m_Size);
>   }
> 
>   int* Height (m_Final.c_Leaf* p)
>   {
>     return &((cast(c_Common_Head*) p).m_Height);
>   }
> 
>   int* Height (m_Final.c_Branch* p)
>   {
>     return &((cast(c_Common_Head*) p).m_Height);
>   }
>   
>   c_Leaf_Items* Items (m_Final.c_Leaf* p)
>   {
>     return &((cast(c_Leaf*) p).m_Items);
>   }
> 
>   c_Branch_Items* Items (m_Final.c_Branch* p)
>   {
>     return &((cast(c_Branch*) p).m_Items);
>   }
> 
>   void** Child (m_Final.c_Branch_Item* p)
>   {
>     return &((cast(c_Branch_Item*) p).m_Child);
>   }
> }
> 
> template t_ML_Keys (alias PL, c_Key)
> {
>   mixin PL;
>   
>   struct c_Leaf_Item
>   {
>     PL.c_Leaf_Item  m_Previous;
>     c_Key           m_Key;
>   }
> 
>   struct c_Branch_Item
>   {
>     PL.c_Branch_Item  m_Previous;
>     c_Key             m_Key;
>   }
> 
>   c_Key* Key (m_Final.c_Leaf_Item* p)
>   {
>     return &((cast(c_Leaf_Item*) p).m_Key);
>   }
> 
>   c_Key* Key (m_Final.c_Branch_Item* p)
>   {
>     return &((cast(c_Branch_Item*) p).m_Key);
>   }
> }
> 
> template t_ML_Data (alias PL, c_Data)
> {
>   mixin PL;
>   
>   struct c_Leaf_Item
>   {
>     PL.c_Leaf_Item  m_Previous;
>     c_Data          m_Data;
>   }
> 
>   c_Data* Data (m_Final.c_Leaf_Item* p)
>   {
>     return &((cast(c_Leaf_Item*) p).m_Data);
>   }
> }
> 
> //  Shorthand form
> template t_ML_Keys_Data(alias PL, c_Key, c_Data)
> {
>   mixin t_ML_Keys!(t_ML_Data!(PL,c_Data),c_Key);
> }
> 
> void main (char[][] args)
> {
>   alias t_ML_Keys_Data!(t_ML_Init!(ti_Test, 4, 4),int,int) ti_Test;
> }
> 
> 
> I get the error "alias ti_Test recursive alias declaration" - clearly
> the cyclic dependency isn't liked.
> 
> I also tried to use the C++ form of mix-in layers, using an outer
> class as a container for definitions. That didn't work either. It
> didn't complain about the cyclic dependency, but it couldn't resolve
> it either. Kept complaining about definitions being missing from
> FINAL.
> 
> Funny how you can get used to an idea, and forget what the compiler is
> having to do to handle it. I've been just working on the assumption
> that I could do these things in D.
> 
> The cyclic dependency thing isn't a fundamental feature of mix-in
> layers, and I don't actually need it despite the concept-testing code
> above - there are other ways using 'static if' - but I just wanted to
> ask if this no-cyclic-dependencies rule is permanent or whether it
> might be changed in the future.

I don't see how it could ever work. An alias contains the fully 
qualified name, with type information. You're asking it for a name where 
part of the name is the full name; this results in an infinitely long 
recursive name. Somehow, you need to prevent the alias from becoming 
part of the type. Well, that's what I thought. But...

...there's hope, because in the example below I've managed to get the 
name of the variable 'shark' included in the type of 'shark'! It's not 
very stable, though -- it's not hard to ICE the compiler.

template frog(alias x)
{
     alias x frog;
}

template reptile(alias y)
{
     class fish {}
}

// But if you swap the order of these next two lines, it doesn't work!
reptile!(shark).fish turtle;
typedef typeof(frog!(turtle)) shark;

pragma(msg, shark.mangleof);



More information about the Digitalmars-d mailing list