Jump to page: 1 2
Thread overview
Templated structs / variant values
Aug 14, 2013
Marek Janukowicz
Aug 15, 2013
JS
Aug 15, 2013
Jacob Carlborg
Aug 19, 2013
Marek Janukowicz
Aug 19, 2013
H. S. Teoh
Aug 19, 2013
Marek Janukowicz
Aug 20, 2013
Jacob Carlborg
Aug 20, 2013
Dicebot
Aug 20, 2013
Marek Janukowicz
Aug 20, 2013
Dicebot
Aug 20, 2013
Marek Janukowicz
August 14, 2013
I need to have a generalized "settings" functionality that should work like
this:
* I need to be able to add this to a class
* each setting has its name, description, type and default value
* I need to iterate over all settings for given object

API would more or less look like:
class A {
 ... here I somehow define a setting called "maxTime"
}

A a = new A();

auto b = a.settings["maxTime"].value; // b would contain default value,
because it wasn't set explicitly yet
string s = a.settings["maxTime"].description; // s would contain setting
description
a.settings["maxTime"].value = 10.seconds; // This would only work if maxTime
setting is of type duration
foreach( name, value; a.settings ) ...

Now the problem that I have is with storing those settings. What I've come up with so far are either Variants or templated structs (either really templated and type parametrized structs returned from template functions). The problem with variants is that I don't know how to force the value to be of certain type (variant accepts anything). As for templates and structs I tried something like:

auto setting (string name, string description, T, T deflt)() {
  struct Setting {
    string name = name;
    T value;
  }
  return Setting(name, deflt);
}

but then I don't know if there is any way to build an array of those to be able to iterate over them.

I know generally there should be some kind of "setting definition" defined on class level that would keep shared information (like names and defaults) and then per-instance data containing just actual values, but I don't really care and any solution where this shared information is copied for every instance would also be fine.

I know the description above is a bit messy (it's quite late now), but hopefully you can get the picture. Any ideas how to approach this problem?

-- 
Marek Janukowicz
August 15, 2013
On Wednesday, 14 August 2013 at 22:28:13 UTC, Marek Janukowicz wrote:
> I need to have a generalized "settings" functionality that should work like
> this:
> * I need to be able to add this to a class
> * each setting has its name, description, type and default value
> * I need to iterate over all settings for given object
>
> API would more or less look like:
> class A {
>  ... here I somehow define a setting called "maxTime"
> }
>
> A a = new A();
>
> auto b = a.settings["maxTime"].value; // b would contain default value,
> because it wasn't set explicitly yet
> string s = a.settings["maxTime"].description; // s would contain setting
> description
> a.settings["maxTime"].value = 10.seconds; // This would only work if maxTime
> setting is of type duration
> foreach( name, value; a.settings ) ...
>
> Now the problem that I have is with storing those settings. What I've come
> up with so far are either Variants or templated structs (either really
> templated and type parametrized structs returned from template functions).
> The problem with variants is that I don't know how to force the value to be
> of certain type (variant accepts anything). As for templates and structs I
> tried something like:
>
> auto setting (string name, string description, T, T deflt)() {
>   struct Setting {
>     string name = name;
>     T value;
>   }
>   return Setting(name, deflt);
> }
>
> but then I don't know if there is any way to build an array of those to be
> able to iterate over them.
>
> I know generally there should be some kind of "setting definition" defined
> on class level that would keep shared information (like names and defaults)
> and then per-instance data containing just actual values, but I don't really
> care and any solution where this shared information is copied for every
> instance would also be fine.
>
> I know the description above is a bit messy (it's quite late now), but
> hopefully you can get the picture. Any ideas how to approach this problem?

I don't really follow what exactly you are trying to do. You first example is written using an associate array format which D already can handle. If you are wanting more "member" like behavior then there are several ways to go about it.

e.g.,

1. a.maxTime can be used by using opDispatch and redirecting it to settings["maxTime"].

2. You can use string mixins to create your own DSL like behavior to code how you want. This is somewhat complex and there is no syntax highlighting or property error analysis but it works.


If you are wanting to have default settings and specific settings for objects then it can be done. I did this once in C#. You can write a whole framework to do this. I used an AA that would lookup the value for the object(using the objects hash) and if it didn't exist it would get the parent value, if that didn't exist it would work itself up the tree until it found one.



e.g.,

A a = new A;

writeln(a.settings.maxTime); // uses opDispatch. maxTime is looked up in the global settings. If settings[a.hash~"maxTime"] exists then it's value is the maxTime setting for a. If it doesn't exist, try settings[a.parent.hash~"maxTime"], etc...

August 15, 2013
On 2013-08-15 00:29, Marek Janukowicz wrote:
> I need to have a generalized "settings" functionality that should work like
> this:
> * I need to be able to add this to a class
> * each setting has its name, description, type and default value
> * I need to iterate over all settings for given object
>
> API would more or less look like:
> class A {
>   ... here I somehow define a setting called "maxTime"
> }
>
> A a = new A();
>
> auto b = a.settings["maxTime"].value; // b would contain default value,
> because it wasn't set explicitly yet
> string s = a.settings["maxTime"].description; // s would contain setting
> description
> a.settings["maxTime"].value = 10.seconds; // This would only work if maxTime
> setting is of type duration
> foreach( name, value; a.settings ) ...
>
> Now the problem that I have is with storing those settings. What I've come
> up with so far are either Variants or templated structs (either really
> templated and type parametrized structs returned from template functions).
> The problem with variants is that I don't know how to force the value to be
> of certain type (variant accepts anything). As for templates and structs I
> tried something like:
>
> auto setting (string name, string description, T, T deflt)() {
>    struct Setting {
>      string name = name;
>      T value;
>    }
>    return Setting(name, deflt);
> }
>
> but then I don't know if there is any way to build an array of those to be
> able to iterate over them.
>
> I know generally there should be some kind of "setting definition" defined
> on class level that would keep shared information (like names and defaults)
> and then per-instance data containing just actual values, but I don't really
> care and any solution where this shared information is copied for every
> instance would also be fine.
>
> I know the description above is a bit messy (it's quite late now), but
> hopefully you can get the picture. Any ideas how to approach this problem?
>

Perhaps you can do something like this:

struct Setting (T, string desc)
{
    T value;
    enum description = desc;
    alias value this;

    this (T value)
    {
        this.value = value;
    }
}

class A
{
    Setting!(int, "foo bar") bar = 3;

    auto settings ()
    {
        return Tuple!(typeof(bar), "bar")(bar);
    }
}

void main ()
{
    auto a = new A;
    assert(a.bar.description == "foo bar");
    assert(a.bar.value == 3);
    assert(a.bar == 3);
    assert(a.settings.bar == 3);
}

In "settings" you should be able to:

1. Iterate over all fields of the type Setting using __tratis(derivedMembers)
2. Create and return tuple of all these fields

But then you won't be able to set the value via "settings".

Perhaps a variant is easier, but then you need to tell it what type to return, something like:

auto bar = a.settings["bar"].value!(int);

http://dlang.org/traits.html#derivedMembers

-- 
/Jacob Carlborg
August 19, 2013
Jacob Carlborg wrote:

> On 2013-08-15 00:29, Marek Janukowicz wrote:
>> I need to have a generalized "settings" functionality that should work
>> like this:
>> * I need to be able to add this to a class
>> * each setting has its name, description, type and default value
>> * I need to iterate over all settings for given object
>>
>> API would more or less look like:
>> class A {
>>   ... here I somehow define a setting called "maxTime"
>> }
>>
>> A a = new A();
>>
>> auto b = a.settings["maxTime"].value; // b would contain default value,
>> because it wasn't set explicitly yet
>> string s = a.settings["maxTime"].description; // s would contain setting
>> description
>> a.settings["maxTime"].value = 10.seconds; // This would only work if
>> maxTime setting is of type duration
>> foreach( name, value; a.settings ) ...
>>
>> Now the problem that I have is with storing those settings. What I've come up with so far are either Variants or templated structs (either really templated and type parametrized structs returned from template functions). The problem with variants is that I don't know how to force the value to be of certain type (variant accepts anything). As for templates and structs I tried something like:
>>
>> auto setting (string name, string description, T, T deflt)() {
>>    struct Setting {
>>      string name = name;
>>      T value;
>>    }
>>    return Setting(name, deflt);
>> }
>>
>> but then I don't know if there is any way to build an array of those to be able to iterate over them.
>>
>> I know generally there should be some kind of "setting definition" defined on class level that would keep shared information (like names and defaults) and then per-instance data containing just actual values, but I don't really care and any solution where this shared information is copied for every instance would also be fine.
>>
>> I know the description above is a bit messy (it's quite late now), but hopefully you can get the picture. Any ideas how to approach this problem?
>>
> 
> Perhaps you can do something like this:
> 
> struct Setting (T, string desc)
> {
>      T value;
>      enum description = desc;
>      alias value this;
> 
>      this (T value)
>      {
>          this.value = value;
>      }
> }
> 
> class A
> {
>      Setting!(int, "foo bar") bar = 3;
> 
>      auto settings ()
>      {
>          return Tuple!(typeof(bar), "bar")(bar);
>      }
> }
> 
> void main ()
> {
>      auto a = new A;
>      assert(a.bar.description == "foo bar");
>      assert(a.bar.value == 3);
>      assert(a.bar == 3);
>      assert(a.settings.bar == 3);
> }

Thank you for this code, I narrowed my requirements a bit and ended up with this:

struct Setting (T, string desc, T deflt)
{
  T value = deflt;
  string description = desc;
  alias value this;

  this (T value)
  {
    this.value = value;
  }
}

class A {

  Setting!(int, "Some max int", 10) max;
  Setting!(string, "name", "default name") name;

}

This looks very neat to me: definition is provided via template parameters while the actual value is provided via argument.

> In "settings" you should be able to:
> 
> 1. Iterate over all fields of the type Setting using
> __tratis(derivedMembers)

How do I do that? My understanding of types in case of templates is really poor... If I do something like:

    foreach( s; __traits(derivedMembers, typeof(this))) {

how do I go from "s" into type of this member (especially that a type is an instantiated struct template?). And more generally - how do I check the type of a variable?

> 2. Create and return tuple of all these fields
> 
> But then you won't be able to set the value via "settings".

What I really is need is a JSON of name => value pairs and corresponding method to update the settings from such JSON structure. Or it may be AA with Variant values, it's really quite straightforward to convert between one and the other. But I have a problem of how to get a list of all fields of type Setting (as mentioned above).

-- 
Marek Janukowicz
August 19, 2013
On Tue, Aug 20, 2013 at 01:09:16AM +0200, Marek Janukowicz wrote:
> Jacob Carlborg wrote:
[...]
> > In "settings" you should be able to:
> > 
> > 1. Iterate over all fields of the type Setting using
> > __tratis(derivedMembers)
> 
> How do I do that? My understanding of types in case of templates is really poor... If I do something like:
> 
>     foreach( s; __traits(derivedMembers, typeof(this))) {
> 
> how do I go from "s" into type of this member (especially that a type is an instantiated struct template?).

To get the type:

	alias type = typeof(__traits(getMember, this, s));

To get the value:
	auto value = __traits(getMember, this, s);

Or you can get both:

	auto value = __traits(getMember, this, s);
	alias type = typeof(value);


> And more generally - how do I check the type of a variable?

	int x;
	assert(is(typeof(x) == int));


T

-- 
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
August 19, 2013
H. S. Teoh wrote:

> On Tue, Aug 20, 2013 at 01:09:16AM +0200, Marek Janukowicz wrote:
>> Jacob Carlborg wrote:
> [...]
>> > In "settings" you should be able to:
>> > 
>> > 1. Iterate over all fields of the type Setting using
>> > __tratis(derivedMembers)
>> 
>> How do I do that? My understanding of types in case of templates is really poor... If I do something like:
>> 
>>     foreach( s; __traits(derivedMembers, typeof(this))) {
>> 
>> how do I go from "s" into type of this member (especially that a type is an instantiated struct template?).
> 
> To get the type:
> 
> alias type = typeof(__traits(getMember, this, s));
> 
> To get the value:
> auto value = __traits(getMember, this, s);
> 
> Or you can get both:
> 
> auto value = __traits(getMember, this, s);
> alias type = typeof(value);
> 
> 
>> And more generally - how do I check the type of a variable?
> 
> int x;
> assert(is(typeof(x) == int));

Thanks, but how do I get the list of members that are of instantiated Setting struct type? If I do it like this:

alias type = typeof(__traits(getMember, this, s));
      if (is ( type == Setting))

I get:

Error: struct aa.Setting(T, string desc, T deflt) is used as a type

-- 
Marek Janukowicz
August 20, 2013
On 2013-08-20 01:51, Marek Janukowicz wrote:

> Thanks, but how do I get the list of members that are of instantiated
> Setting struct type? If I do it like this:
>
> alias type = typeof(__traits(getMember, this, s));
>        if (is ( type == Setting))
>
> I get:
>
> Error: struct aa.Setting(T, string desc, T deflt) is used as a type

That's a good question. There's probably some smart template/is-expression syntax to strip out arguments and only leaving Setting.

-- 
/Jacob Carlborg
August 20, 2013
On Tuesday, 20 August 2013 at 06:42:47 UTC, Jacob Carlborg wrote:
> On 2013-08-20 01:51, Marek Janukowicz wrote:
>
>> Thanks, but how do I get the list of members that are of instantiated
>> Setting struct type? If I do it like this:
>>
>> alias type = typeof(__traits(getMember, this, s));
>>       if (is ( type == Setting))
>>
>> I get:
>>
>> Error: struct aa.Setting(T, string desc, T deflt) is used as a type
>
> That's a good question. There's probably some smart template/is-expression syntax to strip out arguments and only leaving Setting.

if(is(type == Setting!U, U...))
August 20, 2013
Dicebot wrote:

>>> Thanks, but how do I get the list of members that are of
>>> instantiated
>>> Setting struct type? If I do it like this:
>>>
>>> alias type = typeof(__traits(getMember, this, s));
>>>       if (is ( type == Setting))
>>>
>>> I get:
>>>
>>> Error: struct aa.Setting(T, string desc, T deflt) is used as a
>>> type
>>
>> That's a good question. There's probably some smart template/is-expression syntax to strip out arguments and only leaving Setting.
> 
> if(is(type == Setting!U, U...))

This is not enough for me - I have many instantiations of Setting struct template and I need all of them, regardless of parameters they were instantiated with.

-- 
Marek Janukowicz
August 20, 2013
On Tuesday, 20 August 2013 at 11:22:35 UTC, Marek Janukowicz wrote:
>> if(is(type == Setting!U, U...))
>
> This is not enough for me - I have many instantiations of Setting struct
> template and I need all of them, regardless of parameters they were
> instantiated with.

Have you actually tried this snippet? It does exactly that. "U..." is a pattern for variadic template argument list. Constraint will match Setting instance with any number of any template arguments.
« First   ‹ Prev
1 2