Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 13, 2017 Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Hi, In Extended Pascal, you can derive from a basic type and change the default initialiser like so: type int1 = integer value 1; var i : int1; ii : int1 value 2; assert(i = 1); assert(ii = 2); I have it working in D, but it seems a little clumsy. Is there a better way? struct initial(T, T val) { private T _payload = val; alias _payload this; static initial opCall(T v) { initial s; s._payload = v; return s; } } unittest { alias initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); } |
February 13, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bastiaan Veelo | Dne 13.2.2017 v 16:28 Bastiaan Veelo via Digitalmars-d-learn napsal(a): > Hi, > > In Extended Pascal, you can derive from a basic type and change the default initialiser like so: > > type int1 = integer value 1; > var i : int1; > ii : int1 value 2; > assert(i = 1); > assert(ii = 2); > > I have it working in D, but it seems a little clumsy. Is there a better way? > > > struct initial(T, T val) > { > private T _payload = val; > alias _payload this; > > static initial opCall(T v) > { > initial s; > s._payload = v; > return s; > } > } > > unittest > { > alias initial!(int, 1) int1; > int1 i; > assert(i == 1); > int1 ii = 2; > assert(ii == 2); > } > https://dlang.org/phobos/std_typecons.html#.Typedef |
February 13, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Dne 13.2.2017 v 17:40 Daniel Kozak napsal(a): > Dne 13.2.2017 v 16:28 Bastiaan Veelo via Digitalmars-d-learn napsal(a): > >> Hi, >> >> In Extended Pascal, you can derive from a basic type and change the default initialiser like so: >> >> type int1 = integer value 1; >> var i : int1; >> ii : int1 value 2; >> assert(i = 1); >> assert(ii = 2); >> >> I have it working in D, but it seems a little clumsy. Is there a better way? >> >> >> struct initial(T, T val) >> { >> private T _payload = val; >> alias _payload this; >> >> static initial opCall(T v) >> { >> initial s; >> s._payload = v; >> return s; >> } >> } >> >> unittest >> { >> alias initial!(int, 1) int1; >> int1 i; >> assert(i == 1); >> int1 ii = 2; >> assert(ii == 2); >> } >> > https://dlang.org/phobos/std_typecons.html#.Typedef or you can use Proxy https://dlang.org/phobos/std_typecons.html#.Proxy struct initial(T, T val) { private T _payload = val; mixin Proxy!_payload; this(T v) { _payload = v; } } unittest { alias initial!(int, 1) int1; int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); } |
February 13, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Kozak | On Monday, 13 February 2017 at 16:40:02 UTC, Daniel Kozak wrote:
> https://dlang.org/phobos/std_typecons.html#.Typedef
Thanks for the pointers. Both Typedef and Proxy create types that don't mix with the base type, which I want to the contrary. So I guess I'll go with
struct Initial(T, T val)
{
private T _payload = val;
alias _payload this;
static Initial opCall(T v)
{
Initial s;
s._payload = v;
return s;
}
static T init()
{
return val;
}
}
unittest
{
alias Initial!(int, 1) int1;
int1 i;
assert(i == 1);
int1 ii = 2;
assert(ii == 2);
assert(ii.init == 1);
assert(int1.init == 1);
void f(int val)
{
assert(val == 1);
}
f(i);
int i0;
assert(i0 == 0);
i = i0;
assert(i == 0);
assert(i.init == 1);
i0 = ii;
assert(i0 == 2);
assert(i0.init == 0);
}
|
February 13, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bastiaan Veelo | On Monday, 13 February 2017 at 22:16:36 UTC, Bastiaan Veelo wrote:
> On Monday, 13 February 2017 at 16:40:02 UTC, Daniel Kozak wrote:
>> https://dlang.org/phobos/std_typecons.html#.Typedef
>
> Thanks for the pointers. Both Typedef and Proxy create types that don't mix with the base type, which I want to the contrary. So I guess I'll go with
Why not use a constructor instead of static opCall? Also, it's generally a bad idea to define `.init` for any type as code generally expects this to be the compiler-generated property (e.g. a value of type Initial!(int, 1) not of type int). So, perhaps like this:
struct Initial(T, T val)
{
private T _payload = val;
alias _payload this;
this(T v)
{
_payload = v;
}
enum initial = val;
}
unittest
{
alias Initial!(int, 1) int1;
static assert(int1.initial == 1); // typeof(int1.initial) == int
static assert(int1.init == 1); // typeof(int1.init) == typeof(int1)
int1 i;
assert(i == 1);
int1 ii = 2;
assert(ii == 2);
assert(ii.init == 1);
assert(int1.init == 1);
void f(int val)
{
assert(val == 1);
}
f(i);
int i0;
assert(i0 == 0);
i = i0;
assert(i == 0);
assert(i.init == 1);
i0 = ii;
assert(i0 == 2);
assert(i0.init == 0);
}
|
February 14, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Monday, 13 February 2017 at 22:59:11 UTC, John Colvin wrote: > [ snip ] sorry, made a typo, that should have been > alias int1 = Initial!(int, 1); > static assert(int1.initial == 1); // typeof(int1.initial) == int > static assert(int1.init == 1); // typeof(int1.init) == int1 |
February 14, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Tuesday, 14 February 2017 at 01:31:10 UTC, John Colvin wrote:
> On Monday, 13 February 2017 at 22:59:11 UTC, John Colvin wrote:
>> [ snip ]
>
> sorry, made a typo, that should have been
>
>> alias int1 = Initial!(int, 1);
>> static assert(int1.initial == 1); // typeof(int1.initial) == int
>> static assert(int1.init == 1); // typeof(int1.init) == int1
What is the difference between
alias Initial!(int, 1) int1;
and
alias int1 = Initial!(int, 1);
? Or was the typo in the comments alone?
Thanks.
|
February 14, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Monday, 13 February 2017 at 22:59:11 UTC, John Colvin wrote: > Why not use a constructor instead of static opCall? I don't know, this comes from http://dlang.org/spec/struct.html#dynamic_struct_init. Your constructor looks a lot better. Am I missing a test case where static opCall would be called, but not the constructor? Why do the docs use static opCall? > Also, it's generally a bad idea to define `.init` for any type as code generally expects this to be the compiler-generated property (e.g. a value of type Initial!(int, 1) not of type int). Thanks. I can't remember what confused me to think that typeof(int1.init) had to be int. > enum initial = val; [...] > static assert(int1.initial == 1); // typeof(int1.initial) == int These lines have no purpose beyond illustration, right? I now have the following, featuring the novel Scherkl-Nielsen self-important lookup: /** Creates an type that is mostly $(PARAM T), only with a different initial value of $(PARAM val). */ struct Initial(T, T val) { private T _payload = val; alias _payload this; this(T v) { _payload = v; } // https://dlang.org/blog/2017/02/13/a-new-import-idiom/ private template from(string moduleName) { mixin("import from = " ~ moduleName ~ ";"); } void toString(scope void delegate(const(char)[]) sink, from!"std.format".FormatSpec!char fmt) { import std.array : appender; import std.format : formatValue; auto w = appender!string(); formatValue(w, _payload, fmt); sink(w.data); } } unittest { alias int1 = Initial!(int, 1); static assert(int1.init == 1); // typeof(int1.init) == int1 int1 i; assert(i == 1); int1 ii = 2; assert(ii == 2); assert(ii.init == 1); assert(int1.init == 1); void f(int val) { assert(val == 1); } f(i); int i0; assert(i0 == 0); i = i0; assert(i == 0); assert(i.init == 1); i0 = ii; assert(i0 == 2); assert(i0.init == 0); import std.string; assert(format("%6d", ii) == " 2"); } |
February 14, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bastiaan Veelo | On Tuesday, 14 February 2017 at 10:49:19 UTC, Bastiaan Veelo wrote:
> On Tuesday, 14 February 2017 at 01:31:10 UTC, John Colvin wrote:
>> On Monday, 13 February 2017 at 22:59:11 UTC, John Colvin wrote:
>>> [ snip ]
>>
>> sorry, made a typo, that should have been
>>
>>> alias int1 = Initial!(int, 1);
>>> static assert(int1.initial == 1); // typeof(int1.initial) == int
>>> static assert(int1.init == 1); // typeof(int1.init) == int1
>
> What is the difference between
>
> alias Initial!(int, 1) int1;
>
> and
>
> alias int1 = Initial!(int, 1);
>
> ? Or was the typo in the comments alone?
>
> Thanks.
just a more modern style. I think the old style would have been deprecated if it wasn't for how much old code used it.
|
February 14, 2017 Re: Alias type with different initialiser. | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bastiaan Veelo | On Tuesday, 14 February 2017 at 11:34:22 UTC, Bastiaan Veelo wrote: > On Monday, 13 February 2017 at 22:59:11 UTC, John Colvin wrote: >> Why not use a constructor instead of static opCall? > > I don't know, this comes from http://dlang.org/spec/struct.html#dynamic_struct_init. Your constructor looks a lot better. Am I missing a test case where static opCall would be called, but not the constructor? Why do the docs use static opCall? The docs are just trying to illustrate that opCall is only used for initialisation if the initialiser is of a different type. Constructors are always used for initialisation if they are there, they completely hide static opCall in that context. static opCall can return anything of any type, constructors implicitly return a reference to `this`. A constructor is the way to initialise a type and some code - such as std.conv.emplace - actually calls the constructor manually (it's accessible via .__ctor) to do so. static opCall doesn't necessarily represent an initialiser function, so generic code won't necessarily know to use it. Overall, static opCall is rarely the solution you need. >> Also, it's generally a bad idea to define `.init` for any type as code generally expects this to be the compiler-generated property (e.g. a value of type Initial!(int, 1) not of type int). > > Thanks. I can't remember what confused me to think that typeof(int1.init) had to be int. > >> enum initial = val; > [...] >> static assert(int1.initial == 1); // typeof(int1.initial) == int > > These lines have no purpose beyond illustration, right? they check that the implementation does have a member .initial and that it is equal to the value we requested as the initialiser. It also enforces that it is accessible at compile-time. > > I now have the following, featuring the novel Scherkl-Nielsen self-important lookup: > > /** > Creates an type that is mostly $(PARAM T), only with a different initial value of $(PARAM val). > */ > struct Initial(T, T val) > { > private T _payload = val; > alias _payload this; > > this(T v) > { > _payload = v; > } > > // https://dlang.org/blog/2017/02/13/a-new-import-idiom/ > private template from(string moduleName) > { > mixin("import from = " ~ moduleName ~ ";"); > } > > void toString(scope void delegate(const(char)[]) sink, from!"std.format".FormatSpec!char fmt) > { > import std.array : appender; > import std.format : formatValue; > auto w = appender!string(); > formatValue(w, _payload, fmt); > sink(w.data); > } > } > > unittest > { > alias int1 = Initial!(int, 1); > static assert(int1.init == 1); // typeof(int1.init) == int1 > > int1 i; > assert(i == 1); > int1 ii = 2; > assert(ii == 2); > assert(ii.init == 1); > assert(int1.init == 1); > > void f(int val) > { > assert(val == 1); > } > f(i); > > int i0; > assert(i0 == 0); > i = i0; > assert(i == 0); > assert(i.init == 1); > i0 = ii; > assert(i0 == 2); > assert(i0.init == 0); > > import std.string; > assert(format("%6d", ii) == " 2"); > } I would recommend making `template from(string moduleName)` global (maybe in a utils module?), there's no reason for it to be a member of Initial. |
Copyright © 1999-2021 by the D Language Foundation