www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template with template?

reply "Chris" <wendlec tcd.ie> writes:
How can I instantiate Person with Trait, i.e. a template with a 
template?

struct Trait(T0, T1) {
   T0 name;
   T1 value;
   T1[T0] map;

   this(T0 name, T1 value) {
     this.name = name;
     this.value = value;
     map[name] = value;
   }
}

class Person(T) {
   T traits[];

   void addTrait(T trait) {
     traits ~= trait;
   }
}


void main()
{
   auto trait1 = Trait!(string, string)("Name", "John");
   auto trait2 = Trait!(string, int)("Age", 42);
   writefln(%s", trait1.map);
   writefln(%s", trait2.map);
   // above code compiles and works
}
Mar 20 2014
next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template with a 
 template?

 struct Trait(T0, T1) {
   T0 name;
   T1 value;
   T1[T0] map;

   this(T0 name, T1 value) {
     this.name = name;
     this.value = value;
     map[name] = value;
   }
 }

 class Person(T) {
   T traits[];

   void addTrait(T trait) {
     traits ~= trait;
   }
 }


 void main()
 {
   auto trait1 = Trait!(string, string)("Name", "John");
   auto trait2 = Trait!(string, int)("Age", 42);
   writefln(%s", trait1.map);
   writefln(%s", trait2.map);
   // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Mar 20 2014
parent reply "Chris" <wendlec tcd.ie> writes:
On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev 
wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template with 
 a template?

 struct Trait(T0, T1) {
  T0 name;
  T1 value;
  T1[T0] map;

  this(T0 name, T1 value) {
    this.name = name;
    this.value = value;
    map[name] = value;
  }
 }

 class Person(T) {
  T traits[];

  void addTrait(T trait) {
    traits ~= trait;
  }
 }


 void main()
 {
  auto trait1 = Trait!(string, string)("Name", "John");
  auto trait2 = Trait!(string, int)("Age", 42);
  writefln(%s", trait1.map);
  writefln(%s", trait2.map);
  // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Mar 20 2014
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev 
 wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template with 
 a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
   this.name = name;
   this.value = value;
   map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
   traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
Mar 20 2014
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
Or make trait a class, storing the interface and passing the 
trait to the new Person in the constructor.
Mar 20 2014
prev sibling parent reply "Chris" <wendlec tcd.ie> writes:
On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir Panteleev 
 wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template 
 with a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
  this.name = name;
  this.value = value;
  map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
  traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.
Mar 20 2014
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir 
 Panteleev wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template 
 with a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
 this.name = name;
 this.value = value;
 map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
 traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.
Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.
Mar 20 2014
parent reply "Chris" <wendlec tcd.ie> writes:
On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir 
 Panteleev wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template 
 with a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
 this.name = name;
 this.value = value;
 map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
 traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.
Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.
I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.
Mar 20 2014
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:

 I thought the array T[] traits could hold any _type_ the template Trait is
 instantiated into.
Different instantiations of a template could become totally unrelated types (heck, even things that are *not* types: function definitions, values, code blocks, ...). So there is now way for an array could hold them all, in general. At their core, templates are just parameterized code blocks, that become whatever strikes your fancy.
Mar 20 2014
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:
 I thought the array T[] traits could hold any _type_ the 
 template Trait is instantiated into. That's where I got it 
 wrong.
This is the best explanation for this restriction that I can think of: struct Person(T) { static if (is(T == int)) { int age; property int age() { return age; } property int age(int val) { return age = val; } property bool isMiddleAge() { return age >= 30 && age <= 50); } } else static if (is(T == string)) { string name; //Etc... } } Depending on what type T is, Person could have an age and associated methods, or a name and associated methods, but never both. If T is neither int nor string, it will completely empty. Therefore, Person!int MUST be a completely different type from Person!string or Person!float. It just doesn't make any sense otherwise.
Mar 20 2014
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir 
 Panteleev wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template 
 with a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
 this.name = name;
 this.value = value;
 map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
 traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.
Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.
I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.
Try this: import std.stdio; import std.variant; enum maxTraitSize = 64; struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; static assert(T0.sizeof + T1.sizeof + (T1[T0]).sizeof <= maxTraitSize); this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person { alias ElT = VariantN!maxTraitSize; ElT[] traits; void addTrait(T)(T trait) if(is(T == Trait!Q, Q...)) { traits ~= ElT(trait); } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln("%s", trait1.map); writefln("%s", trait2.map); auto p = new Person; p.addTrait(trait1); p.addTrait(trait2); writeln(p.traits); }
Mar 20 2014
parent reply "Chris" <wendlec tcd.ie> writes:
On Thursday, 20 March 2014 at 20:20:28 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin 
 wrote:
 On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir 
 Panteleev wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template 
 with a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
 this.name = name;
 this.value = value;
 map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
 traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.
Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.
I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.
Try this: import std.stdio; import std.variant; enum maxTraitSize = 64; struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; static assert(T0.sizeof + T1.sizeof + (T1[T0]).sizeof <= maxTraitSize); this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person { alias ElT = VariantN!maxTraitSize; ElT[] traits; void addTrait(T)(T trait) if(is(T == Trait!Q, Q...)) { traits ~= ElT(trait); } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln("%s", trait1.map); writefln("%s", trait2.map); auto p = new Person; p.addTrait(trait1); p.addTrait(trait2); writeln(p.traits); }
Thanks John, this does what I had in mind. I don't know, though, if I will use it for a real world application. I would have to test the behavior thoroughly first. The background is that I will have variable user input, i.e. users (non-programmers) define traits and rules. There is no way to foresee what names users will choose. That's why Trait stores arbitrary keys and values (and Meta's solution is not an option). I only thought it would be nice to have [string:int] straight away for numerical operations further down the road. I was also thinking about using std.variant. But I'm just starting out with this ...
Mar 21 2014
parent reply "Chris" <wendlec tcd.ie> writes:
On Friday, 21 March 2014 at 09:54:24 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 20:20:28 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 19:38:25 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 18:54:30 UTC, John Colvin wrote:
 On Thursday, 20 March 2014 at 18:39:32 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 17:49:52 UTC, John Colvin 
 wrote:
 On Thursday, 20 March 2014 at 16:40:50 UTC, Chris wrote:
 On Thursday, 20 March 2014 at 16:32:34 UTC, Vladimir 
 Panteleev wrote:
 On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a 
 template with a template?

 struct Trait(T0, T1) {
 T0 name;
 T1 value;
 T1[T0] map;

 this(T0 name, T1 value) {
 this.name = name;
 this.value = value;
 map[name] = value;
 }
 }

 class Person(T) {
 T traits[];

 void addTrait(T trait) {
 traits ~= trait;
 }
 }


 void main()
 {
 auto trait1 = Trait!(string, string)("Name", "John");
 auto trait2 = Trait!(string, int)("Age", 42);
 writefln(%s", trait1.map);
 writefln(%s", trait2.map);
 // above code compiles and works
 }
Person!(Trait!(string, string)) person; -- or -- alias MyTrait = Trait!(string, string); Person!MyTrait person; Note that this approach won't let you have traits with different parameters within the same Person type.
Yep, I've already tried this (sorry I should've mentioned it!). But I don't want this restriction.
Arrays are homogeneous. All the elements must be of the same type. Different instantiations of templates are different types. You could use an array of std.variant.Variant
The elements are all of type Trait. However, Type itself might be of different types. That's why it is not possible? I've come across this restriction before when using templates, which is a big disappointment because it restricts the "templatization" / generalization of data structures somewhat.
Trait is not a type. Trait is a template. An instantiation of the Trait template is a type. Arrays are contiguous, homogeneous data. This is fundamental to their design and their performance characteristics. Workarounds use at least one of the following: indirection, tagging* and padding. Variant uses tagging and padding. Interface/base-class arrays use indirection (and tagging, ultimately). *inline or external, or even compile-time. This is true in *every* programming language, just with different names.
I thought the array T[] traits could hold any _type_ the template Trait is instantiated into. That's where I got it wrong. I understand the practical aspects of this restriction (homogeneous data, performance and the work around involved etc.). However, this makes templates less universal and rather cumbersome to work with in certain circumstances. Take for example the Person class. If I want to do numerical operations with the age of the person, I will have to convert the age to an int (or whatever) later on instead of just doing it once at the beginning (when loading data). So everytime I access Trait.map["age"] I will have to convert it to a number before I can calculate anything. This, or I store it in a field of its own when instantiating Trait. Whatever workaround I choose it will make it less elegant and less simple. Maybe I expect(ed) to much of templates. Mea culpa.
Try this: import std.stdio; import std.variant; enum maxTraitSize = 64; struct Trait(T0, T1) { T0 name; T1 value; T1[T0] map; static assert(T0.sizeof + T1.sizeof + (T1[T0]).sizeof <= maxTraitSize); this(T0 name, T1 value) { this.name = name; this.value = value; map[name] = value; } } class Person { alias ElT = VariantN!maxTraitSize; ElT[] traits; void addTrait(T)(T trait) if(is(T == Trait!Q, Q...)) { traits ~= ElT(trait); } } void main() { auto trait1 = Trait!(string, string)("Name", "John"); auto trait2 = Trait!(string, int)("Age", 42); writefln("%s", trait1.map); writefln("%s", trait2.map); auto p = new Person; p.addTrait(trait1); p.addTrait(trait2); writeln(p.traits); }
Thanks John, this does what I had in mind. I don't know, though, if I will use it for a real world application. I would have to test the behavior thoroughly first. The background is that I will have variable user input, i.e. users (non-programmers) define traits and rules. There is no way to foresee what names users will choose. That's why Trait stores arbitrary keys and values (and Meta's solution is not an option). I only thought it would be nice to have [string:int] straight away for numerical operations further down the road. I was also thinking about using std.variant. But I'm just starting out with this ...
Btw, I was initially inspired by Objective-C's NSSet that can hold arbitrary objects.
Mar 21 2014
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Friday, 21 March 2014 at 09:56:49 UTC, Chris wrote:
 Btw, I was initially inspired by Objective-C's NSSet that can 
 hold arbitrary objects.
That's because Objective-C's objects are references. It would be equivalent to Adam Ruppe's suggestion of using classes/interfaces.
Mar 23 2014
parent "Chris" <wendlec tcd.ie> writes:
On Sunday, 23 March 2014 at 12:37:34 UTC, Marc Schütz wrote:
 On Friday, 21 March 2014 at 09:56:49 UTC, Chris wrote:
 Btw, I was initially inspired by Objective-C's NSSet that can 
 hold arbitrary objects.
That's because Objective-C's objects are references. It would be equivalent to Adam Ruppe's suggestion of using classes/interfaces.
Yes, I will explore that too. Originally I thought I would have an array of references, but that was wrong of course.
Mar 24 2014
prev sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 20 March 2014 at 16:28:46 UTC, Chris wrote:
 How can I instantiate Person with Trait, i.e. a template with a 
 template?

 struct Trait(T0, T1) {
   T0 name;
   T1 value;
   T1[T0] map;

   this(T0 name, T1 value) {
     this.name = name;
     this.value = value;
     map[name] = value;
   }
 }

 class Person(T) {
   T traits[];

   void addTrait(T trait) {
     traits ~= trait;
   }
 }


 void main()
 {
   auto trait1 = Trait!(string, string)("Name", "John");
   auto trait2 = Trait!(string, int)("Age", 42);
   writefln(%s", trait1.map);
   writefln(%s", trait2.map);
   // above code compiles and works
 }
templates can be passed to templates as alias parameters, or as part of a TemplateArgumentTuple. See http://dlang.org/template.html#aliasparameters
Mar 20 2014