www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Anoying problem, but what else can be done?

reply BCS <ao pathlink.com> writes:
this fails

foreach(i, j; Tuple!(1,2,3,4)
{
  loopLable: while(test())
  {
    while(otherTest())
    {
      if(lastTest())
        break loopLabel;
      else
        continue  loopLabel;
    }
  }
}

The reason is that loopLabel is used once for each iteration of the foreach, 
which is unrolled. Seeing as labels have functions scope, this is an error.

the solution is a take on a duff's device:

switch(-1)
{
case -1:
  foreach(i, j; Tuple!(1,2,3,4))
  {
    case i*2:;

        // BTW should "break case i;" work?
    while(test())
    {
      while(otherTest())
      {
        if(lastTest())
          goto case i*2+1;  // goto end of loop
        else
          goto case i*2;    // goto start of loop
      }
    }

    case i*2+1:;
  }
}


Yuck!! And it gets worse if you try to nest it.

A better solution would be to define that labels have function scope from 
a syntactic standpoint, meaning that the first code would be valid because, 
while the labels references more than one location in the final program, 
it only occurs onces in the code. This would be somewhat bad but only because 
you can't jump from one iteration to the next (IIRC the switch/case/goto 
case can).

A better solution would be name:number labels (I'll use the " " for this 
but the syntax is irrelevant)

foreach(i, j; Tuple!(1,2,3,4))
{
  loopLable i: while(test())  // different label each time
  {
    while(otherTest())
    {
      if(nextTest())
        break loopLabel i;      // ok, unique label
      if(lastText())
        continue  loopLabel i;  // ditto

      static if(i>1) goto loopLabel (i-1); // math on number ok
    }
  }
}

It also eliminates the problem of having to do math on case numbers if you 
have more than one place in the loop you want to jump to.

foreach(i, j; Tuple!(1,2,3,4))
{
  Lable i: 
  if(jump()) goto Label i;

  Next i:
  if(jump()) goto Next i;
}

Anyway, I'm not sure I like any of these, what do you all think of them?
Feb 03 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
BCS wrote:
 this fails
 
 foreach(i, j; Tuple!(1,2,3,4)
 {
  loopLable: while(test())
  {
    while(otherTest())
    {
      if(lastTest())
        break loopLabel;
      else
        continue  loopLabel;
    }
  }
 }
 
 The reason is that loopLabel is used once for each iteration of the 
 foreach, which is unrolled. Seeing as labels have functions scope, this 
 is an error.
 
[snip "Duff's Device"-like workaround]
 
 A better solution would be to define that labels have function scope 
 from a syntactic standpoint, meaning that the first code would be valid 
 because, while the labels references more than one location in the final 
 program, it only occurs onces in the code. This would be somewhat bad 
 but only because you can't jump from one iteration to the next (IIRC the 
 switch/case/goto case can).
I'd like this to work, but for any identifiers (labels, variables, aliases, whatever). Whatever is declared in a 'static' foreach body should be local to that iteration of it, because AFAICT it's pretty much guaranteed to be an error or bug otherwise.
 A better solution would be name:number labels (I'll use the " " for this 
 but the syntax is irrelevant)
 
 foreach(i, j; Tuple!(1,2,3,4))
 {
  loopLable i: while(test())  // different label each time
  {
    while(otherTest())
    {
      if(nextTest())
        break loopLabel i;      // ok, unique label
      if(lastText())
        continue  loopLabel i;  // ditto
 
      static if(i>1) goto loopLabel (i-1); // math on number ok
    }
  }
 }
 
 It also eliminates the problem of having to do math on case numbers if 
 you have more than one place in the loop you want to jump to.
 
 foreach(i, j; Tuple!(1,2,3,4))
 {
  Lable i:  if(jump()) goto Label i;
 
  Next i:
  if(jump()) goto Next i;
 }
 
 Anyway, I'm not sure I like any of these, what do you all think of them?
Perhaps your proposed syntax could still be implemented as an additional feature allowing you to jump to other iterations, but I think the original should just do the "obvious" thing. Again, if implemented it should also apply to other declarations, not just labels. I ran into a similar situation a few days ago when I declared an alias in a 'static' foreach. It kept using the alias from the first iteration for all subsequent iterations (IIRC not even a 'duplicate definition' error!).
Feb 03 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to Frits,

 BCS wrote:
 
 Perhaps your proposed syntax could still be implemented as an
 additional
 feature allowing you to jump to other iterations, but I think the
 original should just do the "obvious" thing.
 Again, if implemented it should also apply to other declarations, not
 just labels.
 I ran into a similar situation a few days ago when I declared an alias
 in a 'static' foreach. It kept using the alias from the first
 iteration for all subsequent iterations (IIRC not even a 'duplicate
 definition' error!).
 
Ouch! BTW I'm working on a program that uses a bunch of this kind of stuff so they are real concerns. (Code forthcoming <g>) OTOH it still has to use the case trick because it needs to do a "goto case n;" for a non const n, (this doesn't work so I have to wrap the switch in a while(true) and fall out the bottom). Now I'm wishing for label variables like in C++ under gcc: void* to = forever ? loop : dont; loop: goto to; dont:;
Feb 03 2007
prev sibling parent Don Clugston <dac nospam.com.au> writes:
Frits van Bommel wrote:
 BCS wrote:
 this fails

 foreach(i, j; Tuple!(1,2,3,4)
 {
  loopLable: while(test())
  {
    while(otherTest())
    {
      if(lastTest())
        break loopLabel;
      else
        continue  loopLabel;
    }
  }
 }

 The reason is that loopLabel is used once for each iteration of the 
 foreach, which is unrolled. Seeing as labels have functions scope, 
 this is an error.
[snip "Duff's Device"-like workaround]
 A better solution would be to define that labels have function scope 
 from a syntactic standpoint, meaning that the first code would be 
 valid because, while the labels references more than one location in 
 the final program, it only occurs onces in the code. This would be 
 somewhat bad but only because you can't jump from one iteration to the 
 next (IIRC the switch/case/goto case can).
I'd like this to work, but for any identifiers (labels, variables, aliases, whatever). Whatever is declared in a 'static' foreach body should be local to that iteration of it, because AFAICT it's pretty much guaranteed to be an error or bug otherwise.
NO! Definitely not true. Suppose you want to create an alias for the first 'int' item in a tuple. You don't know which iteration will create the alias. I've made use of the current behaviour, even with labels. It allows you to write things like: foreach(...) { static if (somecomplexcondition) { LabelX: ... } static if(someothercondition) { goto LabelX; } } You can create a state machine in this way; you need to be able to jump from one foreach iteration into another one.
Feb 05 2007