www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - local enum

reply Mr.Bingo <Bingo Namo.com> writes:
static foreach and enum do not play nice together!

import std.meta, std.stdio;
import std.string : leftJustify, center, rightJustify;
alias functions = staticMap!(ApplyRight!(Instantiate, string),
                              leftJustify, center, rightJustify);

void main()
{
	string result = "|";
	static foreach (f; functions)
	{
		enum y = &f;
		// pragma(msg, y("hello", 17));
		mixin("enum z = &"~f~".stringof;");
		pragma(msg, z);
          	auto x = &f; // not a template, but a function 
instantiation
         	result ~= x("hello", 17);
         	result ~= "|";
	}
	writeln(result); // "hello  ; hello ;  hello;
}

Besides the issue of trying to print out information about f at 
compile time, which is what I was working on here, since the 
above is a cool way to aggregate similar functions at compile 
time, I run in to the notorious issue of using enum's in loops!

The enums are local in nature and are used to store intermediate 
results but the looping tries to redefine them, which gives an 
error.

Instead, how about having a new type or keyword such as __local 
than can create a temporary enum that is only valid inside the 
loop just like a local variable:

void main()
{
	string result = "|";
	static foreach (f; functions)
	{
		__local enum y = &f;
		// pragma(msg, y("hello", 17));
		mixin("__local enum z = &"~f~".stringof;");
		pragma(msg, z);
          	auto x = &f; // not a template, but a function 
instantiation
         	result ~= x("hello", 17);
         	result ~= "|";
	}
	writeln(result); // "hello  ; hello ;  hello;
}

here y and z then are local to the static for each and only exist 
within it's scope. The compiler then will not error out about 
redefinitions.

I know this is a trivial example that does not require __local 
enums but in many cases they are necessary or reduce complexity.


Because I'm nice, I will give a hack that can be used, but this 
hack should only be used by those who think the compiler 
shouldn't automatically do this type of stuff for us:

void main()
{
	static foreach (k, f; [113,22,13])
	{
		mixin("enum y"~to!string(k)~" = f;");		
		mixin("pragma(msg, y"~to!string(k)~");");
	}
}

The idea is simply to create a new enum per loop.  This is not an 
acceptable hack but the compiler could do this internally really 
simple, which is what __local would signify reducing all the 
overhead and the above is then represented as


void main()
{
	static foreach (f; [113,22,13])
	{
		__local enum y = f;		
                 pragma(msg, y);
	}
}

Much nicer and one can imagine how this would simplify a lot of 
code.

Another, probably better idea is to simply allow enums to be 
overwritten at compile time:

void main()
{
         venum y;
	static foreach (f; [113,22,13])
	{
		y = f;		
                 pragma(msg, y);
	}
}
Jul 07 2018
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 7 July 2018 at 18:48:35 UTC, Mr.Bingo wrote:
 The enums are local in nature and are used to store 
 intermediate results but the looping tries to redefine them, 
 which gives an error.
Have you tried putting a second set of {} around it? static foreach(...) {{ // 2 intentional enum y = whatever; }} // 2 intentional ?
Jul 07 2018
parent Mr.Bingo <Bingo Namo.com> writes:
On Saturday, 7 July 2018 at 19:29:02 UTC, Adam D. Ruppe wrote:
 On Saturday, 7 July 2018 at 18:48:35 UTC, Mr.Bingo wrote:
 The enums are local in nature and are used to store 
 intermediate results but the looping tries to redefine them, 
 which gives an error.
Have you tried putting a second set of {} around it? static foreach(...) {{ // 2 intentional enum y = whatever; }} // 2 intentional ?
This doesn't always work as it conflates compile time scope and runtime scope. For example, suppose you want to create a series of runtime variables: static foreach(k,...) {{ mixin("auto x"~k~" = ..."); }} You want xk's to escape the foreach but they don't because of the inner {}. You can't move it out and expect things to work: static foreach(k,...) {{ { enum y = 3; } mixin("auto x"~k~" = y"); } better to achieve a proper solution that works in general. One doesn't want to write code then later have to modify it and then realize it can't be modified properly because of the lack of straight forward principles.
Jul 07 2018
prev sibling parent reply Seb <seb wilzba.ch> writes:
On Saturday, 7 July 2018 at 18:48:35 UTC, Mr.Bingo wrote:
 static foreach and enum do not play nice together!

 import std.meta, std.stdio;
 import std.string : leftJustify, center, rightJustify;
 alias functions = staticMap!(ApplyRight!(Instantiate, string),
                              leftJustify, center, rightJustify);

 [...]
__local has actually been suggested and implemented as part of DIP 1010. IIRC it was removed because A&W wanted to see how static foreach plays out. https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md
Jul 08 2018
parent reply Mr.Bingo <Bingo Namo.com> writes:
On Sunday, 8 July 2018 at 11:29:23 UTC, Seb wrote:
 On Saturday, 7 July 2018 at 18:48:35 UTC, Mr.Bingo wrote:
 static foreach and enum do not play nice together!

 import std.meta, std.stdio;
 import std.string : leftJustify, center, rightJustify;
 alias functions = staticMap!(ApplyRight!(Instantiate, string),
                              leftJustify, center, 
 rightJustify);

 [...]
__local has actually been suggested and implemented as part of DIP 1010. IIRC it was removed because A&W wanted to see how static foreach plays out. https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md
Interesting. A lot of goodies in that Dip! I guess we won't get any crackers though?
Jul 08 2018
parent Seb <seb wilzba.ch> writes:
On Sunday, 8 July 2018 at 18:45:48 UTC, Mr.Bingo wrote:
 On Sunday, 8 July 2018 at 11:29:23 UTC, Seb wrote:
 On Saturday, 7 July 2018 at 18:48:35 UTC, Mr.Bingo wrote:
 static foreach and enum do not play nice together!

 import std.meta, std.stdio;
 import std.string : leftJustify, center, rightJustify;
 alias functions = staticMap!(ApplyRight!(Instantiate, string),
                              leftJustify, center, 
 rightJustify);

 [...]
__local has actually been suggested and implemented as part of DIP 1010. IIRC it was removed because A&W wanted to see how static foreach plays out. https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md
Interesting. A lot of goodies in that Dip! I guess we won't get any crackers though?
As mentioned Timon already has an implementation for the goodies. At the review of the DIP, it was agreed to only merge the basic set of the DIP to gain more experience with it before adding more complexity. However, imho it became clear that static break and __local would be very useful. While there are hacks around it (you already mentioned the mixin trick and there's a similar one for static break: define a dummy symbol when you want to break out and check for its existence with typeof in an overall static if, the proposed syntax would be much more concise and readable. It just requires someone to step up and submit a follow-up DIP.
Jul 08 2018