Page 2 of 3

Posted: Tue May 12, 2009 3:41 pm
by Demivec
Here's another version with a slight twist to Kaeru's. This one handles "single" loops of just one execution.

Code: Select all

;counting loop with variable Step value
Procedure loopy(aStart,aStop,aStep)
  Debug "Cust: " + Str(aStart) + " To " + Str(aStop) + " Step " + Str(aStep)
  If (aStep > 0 And aStop < aStart) Or (aStep < 0 And aStop > aStart) Or aStep = 0
    ProcedureReturn aStart
  EndIf 
  
  Protected aLoop = aStart
  Repeat
    ;loop code performed here
    Debug aLoop
    
    ;end of loop routines
    aLoop + aStep
    If aStep < 0
      If aLoop < aStop
        Break
      EndIf
    Else
      If aLoop > aStop
        Break
      EndIf 
    EndIf 
  ForEver
  ProcedureReturn aLoop
EndProcedure 

;standard For/Next with nonvariable Step
Macro loopy2(aStart,aStop,aStep)
  Debug "For: " + Str(aStart) + " To " + Str(aStop) + " Step " + Str(aStep)
  For aLoop = aStart To aStop Step aStep
    Debug aLoop
  Next
EndMacro

;counting loop that uses floats
Procedure loopy3(aStart.f,aStop.f,aStep.f) 
  Debug "Float: " + StrF(aStart,2) + " To " + StrF(aStop,2) + " Step " + StrF(aStep,2)
  If (aStep > 0 And aStop < aStart) Or (aStep < 0 And aStop > aStart) Or aStep = 0
    ProcedureReturn aStart
  EndIf 
  
  Protected aLoop.f = aStart
  Repeat
    ;loop code performed here
    Debug StrF(aLoop,2)
    
    ;end of loop routines
    aLoop + aStep
    If aStep < 0
      If aLoop < aStop
        Break
      EndIf
    Else
      If aLoop > aStop
        Break
      EndIf 
    EndIf 
  ForEver
  ProcedureReturn aLoop
EndProcedure 

;test each possible loop with a selection of values
loopy(5, 60, 9)
loopy2(5, 60, 9)
loopy(5, 60, -9)
loopy2(5, 60, -9)
loopy(60, 5, 9)
loopy2(60, 5, 9)
loopy(60, 5, -9)
loopy2(60, 5, -9)
loopy(-5, -60, 9)
loopy2(-5, -60, 9)
loopy(-5, -60, -9)
loopy2(-5, -60, -9)
loopy(-60, -5, 9)
loopy2(-60, -5, 9)
loopy(-60, -5, -9)
loopy2(-60, -5, -9)
loopy(5, 5, 9)
loopy2(5, 5, 9)
loopy(5, 5, -9)
loopy2(5, 5, -9)
loopy(-5, -5, 9)
loopy2(-5, -5, 9)
loopy(-5, -5, -9)
loopy2(-5, -5, -9)
Debug ""
loopy3(5.2, 60.7, 9.3)
loopy3(5.2, 60.7, -9.3)
loopy3(60.7, 5.2, 9.3)
loopy3(60.7, 5.2, -9.3)
loopy3(-5.2, -60.7, 9.3)
loopy3(-5.2, -60.7, -9.3)
loopy3(-60.7, -5.2, 9.3)
loopy3(-60.7, -5.2, -9.3)
loopy3(5.2, 5.2, 9.3)
loopy3(5.2, 5.2, -9.3)
loopy3(-5.2, -5.2, 9.3)
loopy3(-5.2, -5.2, -9.3)
I've included a complete (almost) set of tests to demonstrate it functions well (for looping, maybe not for speed). The tests include a version that operates with integers and one that operates with floats. The standard For/Next is included also for comparison.

It is noted that if some slightly sloppy programming is not contrary to your style you can just modify the For/Next loop variable incrementing/decrementing it according to your needs. Even so, this has at least two noteworthy limitations: you have to do a special check to make sure the loop's ending conditions are not met before it starts (depends on the sign of the Step), and you are still limited to using integers (no float values for the Step).

Posted: Tue May 12, 2009 4:04 pm
by Kaeru Gaman
I had another idea for a Modification:

Code: Select all

LoopCount = LoopStart
Repeat

;********************
;** In-Loop Action **
  Debug LoopCount
;********************

  LoopCount + LoopStep
  If LoopStart < LoopStop
    If LoopCount > LoopStop Or LoopCount < LoopStart
      LoopEnd = #True
    EndIf
  Else
    If LoopCount < LoopStop Or LoopCount > LoopStart
      LoopEnd = #True
    EndIf
  EndIf
Until LoopEnd
this should allow ANY variations, even Floats for each Value and changing of the StepValue while running, even changing of the sign.
(sure, there are certain conditions where the loop will never end.)
with this, this is MORE than any Variation of a For-Loop will allow.


@topic
In fact, I wouldn't mind if a new additional For Loop would be implemented...

But I really don't want any detail of the existing For-Loop to be changed, I don't want it to lose a sincle cycle.

Posted: Thu May 14, 2009 8:56 am
by akj
@Demivec:

You have missed the point with your macro suggestion.
I accept that this works:

Code: Select all

loopy2(5, 60, 9)
but what I'm trying to do is more akin to

Code: Select all

y = 6 + 3
loopy2(5, 60, y)
But this fails to work.


@KaeruGaman:
You say
I don't want it to lose a single cycle.
But the compiler will detect when the Step value is a constant and will generate code identical to that produced currently and absolutely no speed will be lost. It's only when the compiler detects that Step is a variable or expression, that it will generate more complex code.


After seeing the suggested For/Step/Next emulations, I still think that

Code: Select all

For LoopCount = LoopStart to LoopEnd Step LoopCount
  . . .
Next
is infinitely preferable to something like

Code: Select all

LoopCount = LoopStart
LoopEnd = #False
Repeat
  . . .
  LoopCount + LoopStep
  If LoopStart < LoopStop
    If LoopCount > LoopStop Or LoopCount < LoopStart
      LoopEnd = #True
    EndIf
  Else
    If LoopCount < LoopStop Or LoopCount > LoopStart
      LoopEnd = #True
    EndIf
  EndIf
Until LoopEnd
And as it happens the latter emulation code (suggested by KaeruGaman) is flawed as it does not correctly implement the equivalent of

Code: Select all

For x = 5 To 60 Step -9
This is because the body of the emulation loop is evaluated at least once (due to the Repeat statement), but it should not be evaluated at all.

Posted: Thu May 14, 2009 11:08 am
by Demivec
akj wrote:@Demivec:

You have missed the point with your macro suggestion.
I accept that this works:

Code: Select all

loopy2(5, 60, 9)
but what I'm trying to do is more akin to

Code: Select all

y = 6 + 3
loopy2(5, 60, y)
But this fails to work.
@akj: I did get your point. I didn't use the macro to solve the problem, I used the macro to setup a For/Next loop with the same start/stop/step values the only way it can be done currently (which is limited). In other words the macro demonstrates everything you say is the problem. Since a variable step isn't permitted I couldn't do it with a procedure (see pdwyer's comments, and my solution). The macro wasn't the solution, it was to show the solution resulted in a loop that functioned identically to a corresponding For/Next loop that had a constant Step. The solution exceeds in that it does everything the For/Next loop does and it has a variable Step. As mentioned previously the solution has not been speed tested for comparison.
@KaeruGaman:
You say
I don't want it to lose a single cycle.
But the compiler will detect when the Step value is a constant and will generate code identical to that produced currently and absolutely no speed will be lost. It's only when the compiler detects that Step is a variable or expression, that it will generate more complex code.


After seeing the suggested For/Step/Next emulations, I still think that

Code: Select all

For LoopCount = LoopStart to LoopEnd Step LoopCount
  . . .
Next
is infinitely preferable to something like

Code: Select all

LoopCount = LoopStart
LoopEnd = #False
Repeat
  . . .
  LoopCount + LoopStep
  If LoopStart < LoopStop
    If LoopCount > LoopStop Or LoopCount < LoopStart
      LoopEnd = #True
    EndIf
  Else
    If LoopCount < LoopStop Or LoopCount > LoopStart
      LoopEnd = #True
    EndIf
  EndIf
Until LoopEnd
I used a procedure to demonstrate a working solution, it could also have been done with a macro or two. In this way it avoids the procedure call:

Code: Select all

;counting loop (w/variable Step value) setup routines
Macro BeginLoop(vLoop, aStart, aStop, aStep = 1) ;vLoop must be a variable, not a constant nor an expression
  vLoop = aStart
  If (aStep > 0 And aStop < aStart) Or (aStep < 0 And aStop > aStart) Or aStep = 0
  Else
    Repeat
      
EndMacro
    
;end of counting loop (w/variable Step) routines
Macro EndLoop(vLoop, aStart, aStop, aStep = 1) ;vLoop must be a variable, not a constant nor an expression
      vLoop + aStep
      If aStep < 0
        If vLoop < aStop
          Break
        EndIf
      Else
        If vLoop > aStop
          Break
        EndIf
      EndIf
    ForEver
  EndIf
EndMacro

Repeat
  Text$ = InputRequester("Loop values, Type [Enter] to exit", "Enter start,Stop, And Step (i.e. 5,60,9)","")
  If Text$=""
    Break
  EndIf
  
  b = Val(StringField(Text$,1,","))
  c = Val(StringField(Text$,2,","))
  d = Val(StringField(Text$,3,","))
  
  Debug "Loop: " + Str(b) + " To " + Str(c) + " Step " + Str(d)
  BeginLoop(a,b,c,d)
    Debug a
  EndLoop(a,b,c,d)
  Debug "----Loop end value: " + Str(a)
  
ForEver
Doing things this way you can also put one loop inside of another. I was going to post an example of that but I leave it as an exercise for the interested reader.

Notwistanding all the above, I agree with the feature request. It seems like it could be accomplished with compiling one of two different styles of loop depending on whether a variable step was used or not. :wink:

Posted: Thu May 14, 2009 11:52 am
by akj
@Demivec:

Yes, sorry. I did misinterpret the purpose of the loopy2() macro, but on re-reading your post, I now understand what you had in mind.

I feel your BeginLoop() and EndLoop() macros are much closer to an acceptable solution and I will probably adopt them until For/Next supports Step expressions. Thanks.

Posted: Thu May 14, 2009 11:57 am
by Demivec
akj wrote:@Demivec:

Yes, sorry. I did misinterpret the purpose of the loopy2() macro, but on re-reading your post, I now understand what you had in mind.

I feel your BeginLoop() and EndLoop() macros are much closer to an acceptable solution and I will probably adopt them until For/Next supports Step expressions. Thanks.
Your welcome, I'm glad I could be of some help.

Posted: Thu May 14, 2009 1:20 pm
by Kaeru Gaman
akj wrote:But the compiler will ...
the compiler will do what Fred teaches him to do,
and it will take a whole lot of work to change the implementation of some long established feature in four, five, six compiler versions,
and in a way that the result is reliable and durable.

ever heard the words "never change a running system"?

people don't say this of religion, but just of experience....
akj wrote:After seeing the suggested For/Step/Next emulations, I still think that
[code1]
is infinitely preferable to something like
[code2]
If you don't like the more code, built a macro out of it or set a code folding....
akj wrote:And as it happens the latter emulation code (suggested by KaeruGaman) is flawed as it does not correctly implement the equivalent of

Code: Select all

For x = 5 To 60 Step -9
This is because the body of the emulation loop is evaluated at least once (due to the Repeat statement), but it should not be evaluated at all.
by definition, no!
a For-Loop is defined to be executed at least once.
this is the way it was since I first touched BASIC, over 25 years ago.


as I already said, I do not mind implementing some more conveniant and flexible version of a For-Loop.
and as I also said, and you quoted, I do not want to lose a single cycle when using the variation we already have.
since we have no genie Image who creates us five new compilers by one wish,
every change of an established feature is a bloody big task.

Posted: Thu May 14, 2009 2:10 pm
by akj
@Kaeru Gaman:

You say:
the compiler will do what Fred teaches him to do
and:
since we have no genie who creates us five new compilers by one wish
Please do not underestimate Fred's capabilities!



You also say:
by definition, no!
a For-Loop is defined to be executed at least once.
But this is not true in practice. I choose four Basic compilers at random and the documentation for each supports my assertion that under appropriate circumstances the For-Loop body will NOT be executed at all (PureBasic also works this way). The facts are here:
GW-Basic
www.antonis.de/qbebooks/gwbasman/fornext.html
"The body of the loop is skipped if the initial value of the loop times the sign of the step exceeds the final value times the sign of the step."
VisualBasic
msdn.microsoft.com/en-us/library/5z06z1kb.aspx
"Entry into the Loop: When execution of the For...Next loop begins, Visual Basic evaluates start, end, and step for the only time. It then assigns start to counter. Before it runs the statement block, it compares counter to end. If counter is already past the end value, the For loop terminates and control passes to the statement following the Next statement. Otherwise the statement block runs."
PowerBasic
http://www.powerbasic.com/support/help/ ... ements.htm
"The body of the loop is skipped altogether if the initial value of Counter is greater than stop (or, for a negative increment, if Counter is less than stop)."
FreeBasic
www.freebasic.net/wiki/wikka.php?wakka=KeyPgFornext
"If endvalue is less than startvalue then a negative stepvalue must be specified or the statement block will not execute at all, since startvalue compares greater than endvalue."

Finally you say:
If you don't like the more code, built a macro out of it
but there is no really good macro solution. The best that can be done is probably that achieved by Demivec's macro-pair BeginLoop() and EndLoop(), but I doubt whether he would claim it an ideal solution.

Posted: Thu May 14, 2009 2:23 pm
by pdwyer
Give the guy a break Kaeru, he just making a request and it's been noted that others would not like it if it changes the current working with constants (which it might not)

This isn't a Saddam election, you don't have to beat him into retracting his request!

It's a legit request with a legit concern raised. Leave him alone, it's not a court of law

Posted: Thu May 14, 2009 2:31 pm
by Kaeru Gaman
akj wrote:Please do not underestimate Fred's capabilities!
I don't underestimate Fred at all!

I just want everybody to remember that every change on the compilers means a lot of work for him, and that it's his decision if he wants to invest time and power in this task, since there are possibilities for each programmer to solve it a different way.

akj wrote:But this is not true in practice. I choose four Basic compilers at random and the documentation for each supports my assertion that under appropriate circumstances the For-Loop body will NOT be executed at all (PureBasic also works this way). The facts are here:...
interesting.
in fact, I did not bother with this detail of a For-Loop for a long time. *shrug*

sure it would be possible to change Demivec's code or mine in a way to solve ALL eventualities.

The more it should cover, the messier and uglier it gets, don't you think?

well... this exactly is the problem to implement it into the compiler.
the more waterproof you want it, the more complex it gets, and the more problems and bug-creating-coincidences arise.

also, I'm not sure if it is worth the risk that for a future beta-phase the For-Loop wouldn't be stable any longer, and the risk not to manage to solve it until stable version.

is it worth to anger up thousands of customers who were well satisfied with a For-Loop as it is?


I'm just playing the advocatus matris diavoli, nothing more...


so, I want you to ask yourself "is it worth the hussle"?

sure, if Fred would answer to this thread and wrote "yes it is", I would applaude,
but if he answered "no it isn't", I would just shrug and carry on with my own business.

Posted: Thu May 14, 2009 2:35 pm
by Kaeru Gaman
pdwyer wrote:Give the guy a break Kaeru, he just making a request and it's been noted that others would not like it if it changes the current working with constants (which it might not)

This isn't a Saddam election, you don't have to beat him into retracting his request!

It's a legit request with a legit concern raised. Leave him alone, it's not a court of law
oops, sorry.

I was already writing while you posted this.

yes, you're right.


@akj

I'm sorry, I didn't want to put you down!

I just happen to get carried away with my own arguing sometimes...

peace, mate! Image

Posted: Thu May 14, 2009 2:38 pm
by Demivec
Kaeru Gaman wrote:
akj wrote:And as it happens the latter emulation code (suggested by KaeruGaman) is flawed as it does not correctly implement the equivalent of

Code: Select all

For x = 5 To 60 Step -9
This is because the body of the emulation loop is evaluated at least once (due to the Repeat statement), but it should not be evaluated at all.
by definition, no!
a For-Loop is defined to be executed at least once.
this is the way it was since I first touched BASIC, over 25 years ago.
@Kaeru Gaman: If a For-Loop is defined to be executed at least once why doesn't it do so with the loop that akj mentioned?

Code: Select all

Debug "loop start"
For x = 5 To 60 Step -9
  Debug "doesn't execute"
Next
Debug "loop over
If what you said is true, PureBasic's For-Loop operates differently, maybe it's a bug. I think that I'll make a bug report that will request the PB manual be updated if this is expected behavior.

Posted: Thu May 14, 2009 2:44 pm
by blueznl
-1 for the request, I belong to the While / Wend crowd :-)

Posted: Thu May 14, 2009 2:48 pm
by akj
@Kaeru Gaman:

I gladly accept your peace offer.

This forum is the place to be for friendly, helpful advice and I am happy to go along with that.

Posted: Thu May 14, 2009 2:58 pm
by pdwyer
... and they all lived happily ever after ... :D