A 'rant' about For..Next

Hello everybody.

The correct syntax for a for loop in Xojo is this:

For i As Integer = 0 To 10 ... Next

But

For i As Integer To 10 ... Next
Is bad syntax. But WHY???
Following the logic of the Xojo framework, i As Integer is declared as i = 0
Why in the name of God do we have to explicit give a value. Implicit should be enough.

So I vote that the “= aRandomNumber” should be optional.

What are the thoughts about this subject?

The current form makes it explicit and your option could lead to annoying bugs. Even if that’s not true, the form has never bothered me and I wouldn’t want the Xojo engineers to spend any time on this.

That its trivial and not worth further consideration. Hey, you asked.

Yeah, no problem with that :wink:

I just wanted to make the language more consistent. It’s not like we declare an int as followed:

Dim i As Integer = 0 

Historically, the form “for var as type …” was introduced as a shorthand convenience to avoid:

dim i as integer
for i = 0 to 10

The For statement is not the same as the Dim statement, so your comparison is not… well, I can’t think of a gentler word than, “valid”.

You see to be reading “For i As Integer = 0 To 10” more like:

For (i As Integer = 0) To 10

It is really more equivalent to:

For (i As Integer) = (0 To 10)

The “0 To 10” is the loop boundary and not technically the initializer for the integer. Maybe Joe will correct me about the specifics. Regardless, don’t expect any traction on this.

It’s purely a syntactic rule with no underlying technical reason. All the mentioned for loop boils down to is this (at a high level, the actual stuff generated has jumps and exception landing pads and cleanups, etc):

// Begin a new scope so that 'i' doesn't stick around
If True Then
  Dim i As Integer = 0
  While i <= 10
    // code
    i = i + 1
  Wend
End If

Supporting another syntax wouldn’t be hard, assuming there’s no grammar ambiguities I haven’t thought of. It’s more an issue of:

  • Every language change starts out with -100 points and has to justify itself from there. Anything added to the language is there pretty much forever. For example, we still have Inline68k just because I know there’s code out there that has it.
  • It’s a minor syntax change that, in my opinion doesn’t have much benefit and actually hurts readability. Reading it aloud as “For i As Integer = 0 To 10” is much clearer, to me.
  • It’d be yet another way a for/next loop can be expressed.

ok… while we are on the subject … from a compiler and execution point of view which is “better”

allocate I one time … use it many

dim i as integer
for i=x to y
    ..... do something.....
next i
for i=a to b
..... do something else ...
next i

or

allocate I many times as used.

for i as integer=x to y
    ..... do something.....
next i
for i as integer=a to b
..... do something else ...
next i

personally I ALWAYS use the first format. personal rule “All Dims go at the top of a method”… your opinions may vary :slight_smile:

I also prefer to have all my Dims at the top of a method.

[quote=68146:@Dave S]ok… while we are on the subject … from a compiler and execution point of view which is “better”
[/quote]

In terms of code generation, there’s not a ton of difference, but I definitely prefer the second approach because it keeps the scope of the variable as restricted as possible. The less variables in scope means the less I have to think about when reading the code.

I’ve grown to loathe reading code with Dim’s at the top of the method, especially when the variable names aren’t descriptive. It’s often something like this:

dim ab, bc, cd, ef as double
dim ar(), ag, agx, tt() as Int64
// A few more lines like this

// 20 lines of code here, and finally…
ef = ab + ar(0) // What the ef?!?

I now go with declaring the variable when used. As for Dave’s question, I declare the variable within the For loop to preserve scope. I usually use variations of “i” or “index”, and have no need for them outside of the loop.

So the performance in both cases is identical? The question was more related to performance than preference.

I haven’t tested, but the only time I’d expect to be able to measure a difference is when you have something like this:

for outerIndex as integer = 1 to 10000000
  for innerIndex as integer = 1 to something

The innerIndex would be redeclared 10,000,000 times, but I’d expect this difference to measured in milliseconds at most.

In Basic I mostly put declarations at the top of a routine. But in C I strive to keep it within scope only as you’re supposed to do.

Why the difference for me? Two reasons.

  1. Because the C construct (for example) ‘int MyVal’ looks so streamlined. The bulky Dim i As Integer clutters up my code IMHO. YOu have the DIM and the AS. Clutter.

  2. BASIC initializes integers during declarations, which is additional work and something I don’t necessarily want done. (Although I’m a hypocrite here and I almost always init during declaration (int i = 0). Still, the bulkiness clutters the code (reason #1).

Also, I’m sure all compilers optimize so if a declaration is in a loop and the token has already been allocated storage, it just uses the same storage and doesn’t realloc again.

My test code:

  #if not DebugBuild
    #pragma BackgroundTasks False
    #pragma BoundsChecking False
    #pragma NilObjectChecking False
  #endif
  
  dim msg as string
  dim sw as new Stopwatch_MTC
  sw.Start
  
  for outerIndex as integer = 1 to 10000000
    for innerIndex as integer = 1 to 2
      innerIndex = innerIndex
    next
  next
  
  sw.Stop
  msg = format( sw.ElapsedMicroseconds, "#," ) + " microsecs"
  AddToResult msg

vs.

  #if not DebugBuild
    #pragma BackgroundTasks False
    #pragma BoundsChecking False
    #pragma NilObjectChecking False
  #endif
  
  dim msg as string
  dim sw as new Stopwatch_MTC
  sw.Start
  
  dim innerIndex, outerIndex as integer
  for outerIndex = 1 to 10000000
    for innerIndex = 1 to 2
      innerIndex = innerIndex
    next
  next
  
  sw.Stop
  msg = format( sw.ElapsedMicroseconds, "#," ) + " microsecs"
  AddToResult msg

About 3.5 ms slower for the former in a compiled app. Hardly worth worrying about.

The cost of initialization is so insanely cheap compared to absolutely everything else that this shouldn’t be a concern. There are two major sources of slowdowns in my experience:

  • Every object and string creation/destruction calls malloc/free, which aren’t cheap. This could partly be mitigated by some sort of custom allocator, but I don’t think the wins would be substantial.
  • Exception handling. Since every function can throw, basic blocks end up being very very short and it’s much harder for optimizers to do analysis on.

“What the ef” wins today.

I’m glad somebody got it. :slight_smile:

[quote=68146:@Dave S]ok… while we are on the subject … from a compiler and execution point of view which is “better”

allocate I one time … use it many

dim i as integer
for i=x to y
    ..... do something.....
next i
for i=a to b
..... do something else ...
next i

or

allocate I many times as used.

for i as integer=x to y
    ..... do something.....
next i
for i as integer=a to b
..... do something else ...
next i

personally I ALWAYS use the first format. personal rule “All Dims go at the top of a method”… your opinions may vary :)[/quote]

I tend to use the second since your first format COULD result in using I outside its intended scope

[code]dim i as integer
for i=x to y
… do something…
next i
for i=a to b
… do something else …
next i

if i > 42 then[/code]

but that depends on your intent

[quote=68154:@Kem Tekinay]I’ve grown to loathe reading code with Dim’s at the top of the method, especially when the variable names aren’t descriptive. It’s often something like this:

dim ab, bc, cd, ef as double
dim ar(), ag, agx, tt() as Int64
// A few more lines like this

// 20 lines of code here, and finally…
ef = ab + ar(0) // What the ef?!?

[/quote]
OMG I hate the multiple definitions on one line ESP this style

dim ab, bc, cd, ef as double, ar(), ag, agx, tt() as Int64