Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Jonathan M Davis via Digitalmars-d
On Friday, May 19, 2017 9:04:24 PM PDT Stefan Koch via Digitalmars-d wrote:
> On Friday, 19 May 2017 at 21:01:09 UTC, Jonathan M Davis wrote:
> > Wait, what? Doesn't D specifically _not_ have SFINAE? You can
> > use static if to test what compiles, and the branch whose
> > condition compiles is then the on that gets compiled in, which
> > kind of emulates what you'd get with SFINAE, but that's not
> > really the same as SFINAE, which just outright picks the the
> > template specialization which happens to compile while letting
> > the others that don't compile not generate errors. D complains
> > when you have multiple, matching templates. So, what do you
> > mean that D has SFINAE?
> >
> > - Jonathan M Davis
>
> If a template does trigger a static assert,
> that static assert is ignored if there is another template in the
> overload set that could match.

Why on earth would it work that way? It sounds like a bug to me.

- Jonathan M Davis



Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Dominikus Dittes Scherkl via Digitalmars-d

On Friday, 19 May 2017 at 21:25:22 UTC, Stefan Koch wrote:
On Friday, 19 May 2017 at 21:23:11 UTC, Dominikus Dittes 
Scherkl wrote:
And it's not visible from the API or documentation - you need 
to look into the source to disambiguate - I'm not convinced 
and still consider this bad style.


If they take exactly the same parameters the compiler will flag 
an error.
But if the parameters are merely compatible you can use static 
assert, to shoot things out of the overload set.


Hm. To keep with your example:

string enumToString(E)(E v)
{
   static assert(is(E == enum), ... );
}

if I want to overload it with, lets say

string enumToString(T)(T n) if(isNumeric!T)
{
}

that looks very much like "exactly the same parameters", yes?
SO it won't compile - you have stolen the overload possibility.

What kind of "merely compatible" parameters do you have in mind, 
that would make your static assert pattern useful?




Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Basile B. via Digitalmars-d
On Friday, 19 May 2017 at 21:23:11 UTC, Dominikus Dittes Scherkl 
wrote:

On Friday, 19 May 2017 at 21:04:24 UTC, Stefan Koch wrote:


If a template does trigger a static assert,
that static assert is ignored if there is another template in 
the overload set that could match.


Wow. Didn't know that.
Is this really part of the D grammar?


No, no need to. This is not related to the grammar but to the 
semantic.





Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Stefan Koch via Digitalmars-d
On Friday, 19 May 2017 at 21:23:11 UTC, Dominikus Dittes Scherkl 
wrote:

On Friday, 19 May 2017 at 21:04:24 UTC, Stefan Koch wrote:


If a template does trigger a static assert,
that static assert is ignored if there is another template in 
the overload set that could match.


Wow. Didn't know that.
Is this really part of the D grammar?
Sometimes D is soo cool.

Still - too cool for me to see this. I don't like templates 
looking similar and even taking the same types but the compiler 
does something too intelligent to avoid an ambiguity.


And it's not visible from the API or documentation - you need 
to look into the source to disambiguate - I'm not convinced and 
still consider this bad style.


If they take exactly the same parameters the compiler will flag 
an error.
But if the parameters are merely compatible you can use static 
assert, to shoot things out of the overload set.


Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Dominikus Dittes Scherkl via Digitalmars-d

On Friday, 19 May 2017 at 21:04:24 UTC, Stefan Koch wrote:


If a template does trigger a static assert,
that static assert is ignored if there is another template in 
the overload set that could match.


Wow. Didn't know that.
Is this really part of the D grammar?
Sometimes D is soo cool.

Still - too cool for me to see this. I don't like templates 
looking similar and even taking the same types but the compiler 
does something too intelligent to avoid an ambiguity.


And it's not visible from the API or documentation - you need to 
look into the source to disambiguate - I'm not convinced and 
still consider this bad style.


Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Stefan Koch via Digitalmars-d

On Friday, 19 May 2017 at 21:01:09 UTC, Jonathan M Davis wrote:



Wait, what? Doesn't D specifically _not_ have SFINAE? You can 
use static if to test what compiles, and the branch whose 
condition compiles is then the on that gets compiled in, which 
kind of emulates what you'd get with SFINAE, but that's not 
really the same as SFINAE, which just outright picks the the 
template specialization which happens to compile while letting 
the others that don't compile not generate errors. D complains 
when you have multiple, matching templates. So, what do you 
mean that D has SFINAE?


- Jonathan M Davis


If a template does trigger a static assert,
that static assert is ignored if there is another template in the 
overload set that could match.




Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Jonathan M Davis via Digitalmars-d
On Friday, May 19, 2017 8:31:52 PM PDT Stefan Koch via Digitalmars-d wrote:
> On Friday, 19 May 2017 at 20:23:16 UTC, Dominikus Dittes Scherkl
>
> wrote:
> > On Friday, 19 May 2017 at 17:47:42 UTC, Stefan Koch wrote:
> >> On Friday, 19 May 2017 at 17:34:28 UTC, Dominikus Dittes
> >>
> >> Scherkl wrote:
> >>> [...]
> >>
> >> the static assert tells what's going on.
> >> It it does result in a simple overload not found.
> >
> > Hm. Maybe in this case it's ok, because enum is pretty much all
> > that can be expected as argument to "enumToString". But
> > normally I would calling not using a constraint "stealing
> > overload possibilities", because it would not be possible to
> > overload the same function for a different type if you use this
> > kind of assert.
> > And the error message is not really better.
>
> You can still overload :)
> D has SFINAE

Wait, what? Doesn't D specifically _not_ have SFINAE? You can use static if
to test what compiles, and the branch whose condition compiles is then the
on that gets compiled in, which kind of emulates what you'd get with SFINAE,
but that's not really the same as SFINAE, which just outright picks the the
template specialization which happens to compile while letting the others
that don't compile not generate errors. D complains when you have multiple,
matching templates. So, what do you mean that D has SFINAE?

- Jonathan M Davis



Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Stefan Koch via Digitalmars-d
On Friday, 19 May 2017 at 20:23:16 UTC, Dominikus Dittes Scherkl 
wrote:

On Friday, 19 May 2017 at 17:47:42 UTC, Stefan Koch wrote:
On Friday, 19 May 2017 at 17:34:28 UTC, Dominikus Dittes 
Scherkl wrote:

[...]


the static assert tells what's going on.
It it does result in a simple overload not found.


Hm. Maybe in this case it's ok, because enum is pretty much all 
that can be expected as argument to "enumToString". But 
normally I would calling not using a constraint "stealing 
overload possibilities", because it would not be possible to 
overload the same function for a different type if you use this 
kind of assert.

And the error message is not really better.


You can still overload :)
D has SFINAE


Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Dominikus Dittes Scherkl via Digitalmars-d

On Friday, 19 May 2017 at 17:47:42 UTC, Stefan Koch wrote:
On Friday, 19 May 2017 at 17:34:28 UTC, Dominikus Dittes 
Scherkl wrote:

On Friday, 19 May 2017 at 00:14:05 UTC, Stefan Koch wrote:


string enumToString(E)(E v)
{
static assert(is(E == enum),
"emumToString is only meant for enums");


Why that assert? We can check it at compiletime. Doesn't this 
cry for a constraint? I would use asserts only ever for stuff 
that's only known at runtime.


string enumToString(E)(E v) if(is(E == enum))
{
   ...
}


the static assert tells what's going on.
It it does result in a simple overload not found.


Hm. Maybe in this case it's ok, because enum is pretty much all 
that can be expected as argument to "enumToString". But normally 
I would calling not using a constraint "stealing overload 
possibilities", because it would not be possible to overload the 
same function for a different type if you use this kind of assert.

And the error message is not really better.



Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Stefan Koch via Digitalmars-d
On Friday, 19 May 2017 at 17:34:28 UTC, Dominikus Dittes Scherkl 
wrote:

On Friday, 19 May 2017 at 00:14:05 UTC, Stefan Koch wrote:


string enumToString(E)(E v)
{
static assert(is(E == enum),
"emumToString is only meant for enums");


Why that assert? We can check it at compiletime. Doesn't this 
cry for a constraint? I would use asserts only ever for stuff 
that's only known at runtime.


string enumToString(E)(E v) if(is(E == enum))
{
   ...
}


the static assert tells what's going on.
It it does result in a simple overload not found.


Re: [Semi-OT] to!string(enumType)

2017-05-19 Thread Dominikus Dittes Scherkl via Digitalmars-d

On Friday, 19 May 2017 at 00:14:05 UTC, Stefan Koch wrote:


string enumToString(E)(E v)
{
static assert(is(E == enum),
"emumToString is only meant for enums");


Why that assert? We can check it at compiletime. Doesn't this cry 
for a constraint? I would use asserts only ever for stuff that's 
only known at runtime.


string enumToString(E)(E v) if(is(E == enum))
{
   ...
}


Re: [Semi-OT] to!string(enumType)

2017-05-18 Thread Stefan Koch via Digitalmars-d

On Thursday, 18 May 2017 at 23:15:46 UTC, ag0aep6g wrote:

On 05/19/2017 12:31 AM, Stefan Koch wrote:

string enumToString(E)(E v)
{
 static assert(is(E == enum), "emumToString is only meant 
for enums");

 mixin ({
 string result = "final switch(v) {\n";
 foreach(m;[__traits(allMembers, E)])
 {
 result ~= "\tcase E." ~ m ~ " :\n"
 ~ "\t\treturn \"" ~ m ~ "\";\n"
 ~ "\tbreak;\n";
 }
 return result ~ "}";
 } ());
}


I'm sure that can be de-uglified a fair bit without hurting 
performance.


1) "final switch(v) {" and the closing brace can be moved out 
of the string. This should be completely free.


2) No need for `break` after `return`. Also free.

3) With a static foreach over `__traits(allMembers, E)` you can 
get rid of the function literal. Doesn't seem to affect 
performance much if at all.


So far:


string enumToString(E)(E v)
{
static assert(is(E == enum),
"emumToString is only meant for enums");
final switch (v)
{
foreach(m; __traits(allMembers, E))
{
mixin("case E." ~ m ~ ": return \"" ~ m ~ "\";");
}
}
}


4) If EnumMembers is an option, you can get rid of the string 
mixin altogether:



string enumToString(E)(E v)
{
import std.meta: AliasSeq;
import std.traits: EnumMembers;
static assert(is(E == enum),
"emumToString is only meant for enums");
alias memberNames = AliasSeq!(__traits(allMembers, E));
final switch(v)
{
foreach(i, m; EnumMembers!E)
{
case m: return memberNames[i];
}
}
}


That takes a bit longer. May just be the time it takes to parse 
the std.* modules. Object size stays the same.


Nice work beatifying the implementation.

Although AliasSeq and EnumMembers are unnecessary.
I incorporated your idea into the following version:

string enumToString(E)(E v)
{
static assert(is(E == enum),
"emumToString is only meant for enums");
switch(v)
{
foreach(m; __traits(allMembers, E))
{
case mixin("E." ~ m) : return m;
}

default :
{
string result = "cast(" ~ E.stringof ~ ")";
uint val = v;
enum headLength = E.stringof.length + "cast()".length;
uint log10Val = (val < 10) ? 0 : (val < 100) ? 1 : 
(val < 1000) ? 2 :
(val < 1) ? 3 : (val < 10) ? 4 : (val < 
100) ? 5 :
(val < 1000) ? 6 : (val < 1) ? 7 : 
(val < 10) ? 8 : 9;

result.length += log10Val + 1;
for(uint i;i != log10Val + 1;i++)
{
cast(char)result[headLength + log10Val - i] = 
cast(char) ('0' + (val % 10));

val /= 10;
}

return cast(string) result;
}
}
}



Re: [Semi-OT] to!string(enumType)

2017-05-18 Thread H. S. Teoh via Digitalmars-d
On Thu, May 18, 2017 at 11:42:25PM +, Stefan Koch via Digitalmars-d wrote:
> On Thursday, 18 May 2017 at 22:31:47 UTC, Stefan Koch wrote:
> 
> > Granted this version will result in undefined behavior if you pass
> > something like (cast(ET) 3) to it.
> > But the 55x increase in compilation speed is well worth it :)
> 
> This code will replicate to!string behavior perfectly but will only take 30
> milliseconds to compile:
> 
> string enumToString(E)(E v)
> {
[...snip awesome stuff...]

Where's the PR? ;-)


T

-- 
Windows: the ultimate triumph of marketing over technology. -- Adrian von Bidder


Re: [Semi-OT] to!string(enumType)

2017-05-18 Thread Stefan Koch via Digitalmars-d

On Thursday, 18 May 2017 at 22:31:47 UTC, Stefan Koch wrote:

Granted this version will result in undefined behavior if you 
pass something like (cast(ET) 3) to it.

But the 55x increase in compilation speed is well worth it :)


This code will replicate to!string behavior perfectly but will 
only take 30 milliseconds to compile:


string enumToString(E)(E v)
{
static assert(is(E == enum), "emumToString is only meant for 
enums");

mixin({
string result = "switch(v) {\n";
foreach(m;[__traits(allMembers, E)])
{
result ~= "\tcase E." ~ m ~ " :\n"
~ "\t\treturn \"" ~ m ~ "\";\n";
}
result ~= "\tdefault: break;\n";
result ~= "}\n";
enum headLength = E.stringof.length + "cast()".length;
result ~= `
enum headLength = ` ~ headLength.stringof ~ `;
uint val = v;
char[` ~ (headLength + 10).stringof ~ `] res = "cast(` ~ 
E.stringof ~ `)";
uint log10Val = (val < 10) ? 0 : (val < 100) ? 1 : (val < 
1000) ? 2 : (val < 1) ? 3
: (val < 10) ? 4 : (val < 100) ? 5 : (val < 
1000) ? 6

: (val < 1) ? 7 : (val < 10) ? 8 : 9;
foreach(i;0 .. log10Val + 1)
{
res[headLength + log10Val - i] = cast(char) ('0' + (val % 
10));

val /= 10;
}

return res[0 .. headLength + log10Val + 1].idup;
`;
   return result;
} ());
}




Re: [Semi-OT] to!string(enumType)

2017-05-18 Thread ag0aep6g via Digitalmars-d

On 05/19/2017 12:31 AM, Stefan Koch wrote:

string enumToString(E)(E v)
{
 static assert(is(E == enum), "emumToString is only meant for enums");
 mixin ({
 string result = "final switch(v) {\n";
 foreach(m;[__traits(allMembers, E)])
 {
 result ~= "\tcase E." ~ m ~ " :\n"
 ~ "\t\treturn \"" ~ m ~ "\";\n"
 ~ "\tbreak;\n";
 }
 return result ~ "}";
 } ());
}


I'm sure that can be de-uglified a fair bit without hurting performance.

1) "final switch(v) {" and the closing brace can be moved out of the 
string. This should be completely free.


2) No need for `break` after `return`. Also free.

3) With a static foreach over `__traits(allMembers, E)` you can get rid 
of the function literal. Doesn't seem to affect performance much if at all.


So far:


string enumToString(E)(E v)
{
static assert(is(E == enum),
"emumToString is only meant for enums");
final switch (v)
{
foreach(m; __traits(allMembers, E))
{
mixin("case E." ~ m ~ ": return \"" ~ m ~ "\";");
}
}
}


4) If EnumMembers is an option, you can get rid of the string mixin 
altogether:



string enumToString(E)(E v)
{
import std.meta: AliasSeq;
import std.traits: EnumMembers;
static assert(is(E == enum),
"emumToString is only meant for enums");
alias memberNames = AliasSeq!(__traits(allMembers, E));
final switch(v)
{
foreach(i, m; EnumMembers!E)
{
case m: return memberNames[i];
}
}
}


That takes a bit longer. May just be the time it takes to parse the 
std.* modules. Object size stays the same.


Re: [Semi-OT] to!string(enumType)

2017-05-18 Thread Moritz Maxeiner via Digitalmars-d

On Thursday, 18 May 2017 at 22:31:47 UTC, Stefan Koch wrote:

Hi,

I just took a look into commonly used functionality of Phobos.
Such as getting the string representation of a enum.

[...]


Nice, thank you. I dream of a guide to compile time optimization 
in D. :)


Re: [Semi-OT] to!string(enumType)

2017-05-18 Thread Stefan Koch via Digitalmars-d

On Thursday, 18 May 2017 at 22:31:47 UTC, Stefan Koch wrote:

Hi,

I just took a look into commonly used functionality of Phobos.
Such as getting the string representation of a enum.

[...]

Using -vcg-ast we see that it expands to ~50 lines.