www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Annoyance: 'Shadowing declaration is deprecated'+ mixins

reply Don Clugston <dac nospam.com.au> writes:
Is there any chance of getting the 'shadowing declaration is deprecated' error 
message disabled, for code inserted via a mixin?

It means that if you inject a 'for' loop into the current function, it appears 
to work, but will fail if another variable with the same name already exists.

void main()
{
// double i=300.0;
    mixin("for (int i=0; i<10; ++i) { func(i); }");
}

When such code is generated by a mixin, the shadowing does not indicate a 
probable error.

This is proving to be quite annoying for my BLADE rewrite.
Jul 24 2007
next sibling parent reply downs <default_357-line yahoo.de> writes:
Don Clugston wrote:
 Is there any chance of getting the 'shadowing declaration is deprecated' 
 error message disabled, for code inserted via a mixin?
 
 It means that if you inject a 'for' loop into the current function, it 
 appears to work, but will fail if another variable with the same name 
 already exists.
 
 void main()
 {
 // double i=300.0;
    mixin("for (int i=0; i<10; ++i) { func(i); }");
 }
 
 When such code is generated by a mixin, the shadowing does not indicate 
 a probable error.
 
 This is proving to be quite annoying for my BLADE rewrite.

void main() { double i=300.0; () { mixin("for int i=0; i<10; ++i) { func(i); }"); }(); } This declares and calls a delegate in the same line, thereby establishing a distinct scope. Beware performance degredation though. --downs
Jul 24 2007
parent downs <default_357-line yahoo.de> writes:
downs wrote:
 Beware performance degredation though.

Ahem. Degr_a_dation. Sorry.
Jul 24 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Don Clugston wrote:
 Is there any chance of getting the 'shadowing declaration is deprecated' 
 error message disabled, for code inserted via a mixin?
 
 It means that if you inject a 'for' loop into the current function, it 
 appears to work, but will fail if another variable with the same name 
 already exists.
 
 void main()
 {
 // double i=300.0;
    mixin("for (int i=0; i<10; ++i) { func(i); }");
 }
 
 When such code is generated by a mixin, the shadowing does not indicate 
 a probable error.
 
 This is proving to be quite annoying for my BLADE rewrite.

I guess one obvious solution is to give your counter variables some names that are more likely to be unique: mixin("for (int __i8473=0; __i8473<10; ++__i8473) { func(__i8473); }"); --bb
Jul 24 2007
next sibling parent reply Tristam MacDonald <swiftcoder gmail.com> writes:
Bill Baxter Wrote:
 Don Clugston wrote:
 Is there any chance of getting the 'shadowing declaration is deprecated' 
 error message disabled, for code inserted via a mixin?
 
 It means that if you inject a 'for' loop into the current function, it 
 appears to work, but will fail if another variable with the same name 
 already exists.
 
 void main()
 {
 // double i=300.0;
    mixin("for (int i=0; i<10; ++i) { func(i); }");
 }
 
 When such code is generated by a mixin, the shadowing does not indicate 
 a probable error.
 
 This is proving to be quite annoying for my BLADE rewrite.

I guess one obvious solution is to give your counter variables some names that are more likely to be unique: mixin("for (int __i8473=0; __i8473<10; ++__i8473) { func(__i8473); }");

Hmm... This looks like a prime candidate for something like Scheme's 'gensym' call (which basically alliases an unique, un-named, and un-nameable symbol). Does anyone know of a way to accomplish the same at compile time in D?
Jul 24 2007
parent reply Pragma <ericanderton yahoo.removeme.com> writes:
Tristam MacDonald wrote:
 Bill Baxter Wrote:
 Don Clugston wrote:
 Is there any chance of getting the 'shadowing declaration is deprecated' 
 error message disabled, for code inserted via a mixin?

 It means that if you inject a 'for' loop into the current function, it 
 appears to work, but will fail if another variable with the same name 
 already exists.

 void main()
 {
 // double i=300.0;
    mixin("for (int i=0; i<10; ++i) { func(i); }");
 }

 When such code is generated by a mixin, the shadowing does not indicate 
 a probable error.

 This is proving to be quite annoying for my BLADE rewrite.

names that are more likely to be unique: mixin("for (int __i8473=0; __i8473<10; ++__i8473) { func(__i8473); }");

Hmm... This looks like a prime candidate for something like Scheme's 'gensym' call (which basically alliases an unique, un-named, and un-nameable symbol). Does anyone know of a way to accomplish the same at compile time in D?

FWIW, there was a thread here a while back about generating unique values at compile time. In short, it's not possible (using pure D anyway) to maintain a state extrinsic to a set of template evaluations or CTFE calls. You need that property in order to guarantee uniqueness in your symbols by employing a counter variable to distinguish them. You have to either adopt some template warts to explicitly pass this state to every template/CTFE or use something outside D for all generated symbols to be unique. BCS (I think) suggested a rather elegant hack that uses a C preprocessor to work around this limitation. Another suggestion was to couple __LINE__ and __FILE__ to get *some* measure of uniqueness per-line. So it can be done, but it won't necessarily be pretty. It kinda makes me wish D had a __UNIQUE__ symbol (reliably unique for a given module/compilation unit?) for this kind of stuff. const char[] sym = __UNIQUE__; mixin("for (int " ~ sym ~ "=0; " ~ sym ~ "<10; ++" ~ sym ~ ") { func(" ~ sym ~ "); }"); -- - EricAnderton at yahoo
Jul 24 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to Pragma,

 You have to either adopt some template warts to explicitly pass this
 state to every template/CTFE or use something outside D for all
 generated symbols to be unique.  BCS (I think) 

guilty
 suggested a rather
 elegant hack that uses a C preprocessor to work around this
 limitation.

actually I couldn't get it working because I couldn't fake ++ under the preprocessor
 Another suggestion was to couple __LINE__ and __FILE__ to
 get *some* measure of uniqueness per-line.  So it can be done, but it
 won't necessarily be pretty.
 

The final solution that worked used that (and some other entropy sources as well) |module uniq; | |const char[] prefix = ""; |pragma(msg, prefix~"module uniq;") | |/** use this template as a unique uint | | make sure that each usage has a unique string (__FILE__":"~itoa!(__LINE__) is a good starting point) | | compile the program once, filter the output for lines that start with prefix and then recompile with that output replacing this file. |*/ |template UniqID(char[] str) |{ | const uint UniqID = 0; | pragma(msg, "template UniqID(char[] str : \""~str~"\") {const uint UniqID = __LINE__;}") |}
 It kinda makes me wish D had a __UNIQUE__ symbol (reliably unique for
 a given module/compilation unit?) for this kind of stuff.
 
 const char[] sym = __UNIQUE__;
 mixin("for (int " ~ sym ~ "=0; " ~ sym ~ "<10; ++" ~ sym ~ ") { func("
 ~ sym ~ "); }");

make it a GUID... and have fun debugging _e4f74de910de478b8a8c7f79b92f8459(int _53e2b8bd63534fafbf3a0fe5caa955b4, float _f1e57ba407ba4b4185cb41f6b902f1cd)
Jul 24 2007
prev sibling parent reply "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Pragma" <ericanderton yahoo.removeme.com> wrote in message 
news:f85gh5$g8l$1 digitalmars.com...
<snip>
 It kinda makes me wish D had a __UNIQUE__ symbol (reliably unique for a 
 given module/compilation unit?)  for this kind of stuff.

 const char[] sym = __UNIQUE__;
 mixin("for (int " ~ sym ~ "=0; " ~ sym ~ "<10; ++" ~ sym ~ ") { func(" ~ 
 sym ~ "); }");

Why create a workaround for this language deficiency rather than fixing it? http://www.digitalmars.com/d/pretod.html#mixins "Mixins create a scope, macros do not." "Mixins automatically create unique identifiers as required using a standard algorithm, macros have to do it manually with kludgy token pasting." This of course applies to template mixins. But why not make these points apply to text mixins just the same? Stewart.
Jul 25 2007
parent Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Stewart Gordon wrote:

 "Pragma" <ericanderton yahoo.removeme.com> wrote in message
 news:f85gh5$g8l$1 digitalmars.com...
 <snip>
 It kinda makes me wish D had a __UNIQUE__ symbol (reliably unique for a
 given module/compilation unit?)  for this kind of stuff.

 const char[] sym = __UNIQUE__;
 mixin("for (int " ~ sym ~ "=0; " ~ sym ~ "<10; ++" ~ sym ~ ") { func(" ~
 sym ~ "); }");

Why create a workaround for this language deficiency rather than fixing it? http://www.digitalmars.com/d/pretod.html#mixins "Mixins create a scope, macros do not." "Mixins automatically create unique identifiers as required using a standard algorithm, macros have to do it manually with kludgy token pasting." This of course applies to template mixins. But why not make these points apply to text mixins just the same?

Or extend templates to contain statements so you get three flies with one hit: macros, a fix to this problem & syntax highlighting back. Well, not completely, but the other deficiencies should be obvious by then.
Jul 25 2007
prev sibling parent Don Clugston <dac nospam.com.au> writes:
Bill Baxter wrote:
 Don Clugston wrote:
 Is there any chance of getting the 'shadowing declaration is 
 deprecated' error message disabled, for code inserted via a mixin?

 It means that if you inject a 'for' loop into the current function, it 
 appears to work, but will fail if another variable with the same name 
 already exists.

 void main()
 {
 // double i=300.0;
    mixin("for (int i=0; i<10; ++i) { func(i); }");
 }

 When such code is generated by a mixin, the shadowing does not 
 indicate a probable error.

 This is proving to be quite annoying for my BLADE rewrite.

I guess one obvious solution is to give your counter variables some names that are more likely to be unique: mixin("for (int __i8473=0; __i8473<10; ++__i8473) { func(__i8473); }");

Yes. Although I don't like "likely" <g>. More difficult is the situation when the mixin is recursive. Each nested level needs to use a different name.
Jul 24 2007
prev sibling parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Don Clugston wrote:

 Is there any chance of getting the 'shadowing declaration is deprecated'
 error message disabled, for code inserted via a mixin?
 
 It means that if you inject a 'for' loop into the current function, it
 appears to work, but will fail if another variable with the same name
 already exists.
 
 void main()
 {
 // double i=300.0;
     mixin("for (int i=0; i<10; ++i) { func(i); }");
 }
 
 When such code is generated by a mixin, the shadowing does not indicate a
 probable error.
 
 This is proving to be quite annoying for my BLADE rewrite.

I hope that when macros come there will be a possibility to choose between hygienic and unhygienic versions. I've started to think string mixins are a big design mistake. Looking at those compile time unique id hacks from Lisp coder's POV it's amazing to see how badly you can implement something so obvious. I wrote about macros a while ago and noticed that by increasing the power of template mixins and alias parameters it would be possible to achieve the same things and more without sacrificing e.g. syntactical transparency.
Jul 25 2007
parent reply Don Clugston <dac nospam.com.au> writes:
Jari-Matti Mäkelä wrote:
 Don Clugston wrote:
 
 Is there any chance of getting the 'shadowing declaration is deprecated'
 error message disabled, for code inserted via a mixin?

 It means that if you inject a 'for' loop into the current function, it
 appears to work, but will fail if another variable with the same name
 already exists.

 void main()
 {
 // double i=300.0;
     mixin("for (int i=0; i<10; ++i) { func(i); }");
 }

 When such code is generated by a mixin, the shadowing does not indicate a
 probable error.

 This is proving to be quite annoying for my BLADE rewrite.

I hope that when macros come there will be a possibility to choose between hygienic and unhygienic versions. I've started to think string mixins are a big design mistake. Looking at those compile time unique id hacks from Lisp coder's POV it's amazing to see how badly you can implement something so obvious. I wrote about macros a while ago and noticed that by increasing the power of template mixins and alias parameters it would be possible to achieve the same things and more without sacrificing e.g. syntactical transparency.

My post was actually to indicate that this lack of hygiene is a genuine nuisance (not merely aesthetically undesirable). I wonder when an unhygienic macro would actually be useful.
Jul 25 2007
parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Don Clugston wrote:
 Jari-Matti Mäkelä wrote:

 I hope that when macros come there will be a possibility to choose
 between hygienic and unhygienic versions. I've started to think string
 mixins are a big design mistake. Looking at those compile time unique id
 hacks from Lisp coder's POV it's amazing to see how badly you can
 implement something so obvious. I wrote about macros a while ago and
 noticed that by increasing the power of template mixins and alias
 parameters it would be possible to achieve the same things and more
 without sacrificing e.g. syntactical transparency.

My post was actually to indicate that this lack of hygiene is a genuine nuisance (not merely aesthetically undesirable). I wonder when an unhygienic macro would actually be useful.

Speaking of aesthetics makes it sound like it's only some academic nonsense not applicable in "real world". I've experienced the same problems even with very short metaprograms and created ugly looking ad-hoc workarounds. Most other languages solve the problem using similar techniques so I just wanted to tell there's no need to reimplement the wheel this time. This is a bad example, but hopefully highlights some of the problems with current constructs: import tango.io.Stdout; char[] a, i; char[] foo(char[] a) { return "for (int i=0; i<"~a~".length;i++) Stdout("~a~"[i]).newline;"; } mixin GenNewUniqPrefix!(); // defined elsewhere char[] ad_hoc_foo(char[] a) { char[] safe_prefix = getLastUniqPrefix(); // defined elsewhere char[] safe_a = safe_prefix ~ "a"; char[] safe_i = safe_prefix ~ "i"; return "for (int "~safe_i~"=0; i<"~safe_a ~".length;"~safe_i~"++) Stdout("~safe_a~"["~safe_i~"]).newline;"; } template hygienic_foo(alias a) { void hygienic_foo() { for(int i=0; i<a.length; i++) Stdout(a[i]).newline; } } /* not implemented yet macro macro_foo(alias a) { for(int i=0; i<a.length; i++) Stdout(a[i]).newline; } */ void main() { int[3] bar = [1,2,3]; class i {} mixin(foo("bar")); // collision hygienic_foo!(bar)(); macro_foo(bar); // not implemented yet }
Jul 25 2007
parent Don Clugston <dac nospam.com.au> writes:
Jari-Matti Mäkelä wrote:
 Don Clugston wrote:
 Jari-Matti Mäkelä wrote:

 I hope that when macros come there will be a possibility to choose
 between hygienic and unhygienic versions. I've started to think string
 mixins are a big design mistake.

nuisance (not merely aesthetically undesirable). I wonder when an unhygienic macro would actually be useful.

Speaking of aesthetics makes it sound like it's only some academic nonsense not applicable in "real world".

Yup. I've heard "hygienic" used as if it was purely academic. It's certainly not.
 Most other languages solve the problem using similar techniques so I just
 wanted to tell there's no need to reimplement the wheel this time.

Maybe. I hope macros can do it. It's going to be very hard to match the power of mixins, though. In particular, the case where symbol names are embedded in a string seems to be useful, important, and difficult.
Jul 25 2007