Closed VBAndCs closed 5 years ago
Similar to #186
@AdamSpeight2008 I am aware that this many asked for doing something about this issue, but my suggestion is different, and it is doable. The problem with using the counter as a label is that it can be repeated in the same method, so, it needs more work to insure that the label name is unique. So, I suggest to allow us to define our labels.
@AdamSpeight2008 The problem with using the counter as a label is that it can be repeated in the same method, so, it needs more work to insure that the label name is unique
This doesn't make sense. The counter cannot be repeated within the loop, so there is no uniqueness problem.
If I adapt and compare the example in proposal #186 with your proposal:
' proposed in #186
For i As Integer = 1 To 2
For j As Integer = 2 To 3
If i = j Then
Exit For i
End If
If SomeCondition(i) Then
Continue i
End If
Next j
PerformSomeTask()
Next i
' proposed in #420
For i As Integer = 1 To 2 Alias=for1
For j As Integer = 2 To 3
If i = j Then
Exit for1
End If
If SomeCondition(i) Then
Continue for1
End If
Next j
PerformSomeTask()
Next i
In compilation, both would convert to:
For i As Integer = 1 To 2
For j As Integer = 2 To 3
If i = j Then
GoTo $Exit_i
End If
If SomeCondition(i) Then
GoTo $Continue_i
End If
$Continue_j: ' unused in this example, because I'm lazy
Next j
$Exit_j: ' unused in this example, because I'm lazy
PerformSomeTask()
$Continue_i:
Next i
$Exit_i:
I see no compiled difference, but:
Continue for1
, I would have to go looking for for1
to find out which loop variable is involved, whereas with the other proposal, Continue i
tells me exactly which loop is involved.@pricerc What about:
Sub Foo()
For i = 1 to 10
exit i
next
For i = 0 to 5
exit i
next
End Sub
These two loops will generate the same labels, and need to add extra ID. I once poposed using the counter in C#, but when I am implementing ZML I founf it eaier to use the label. Besides, there is no counter in Do and While loops. My proposal covers that too.
@pricerc What about:
Sub Foo() For i = 1 to 10 exit i next For i = 0 to 5 exit i next End Sub
These two loops will generate the same labels, and need to add extra ID.
No they won't:
Sub Foo()
For i = 1 to 10
GoTo $exit_i_1
next
$exit_i_1
For i = 0 to 5
GoTo $exit_i_2
next
$exit_i_2
End Sub
The labels would be actually be some mangled name, not something that would necessarily have a name that would be meaningful, I just used those for illustration. The compiler wouldn't be so dumb as to not know that it would need different labels.
So for For
loops, I'm sorry but the other proposal is much better.
Besides, there is no counter in Do and While loops. My proposal covers that too.
There is no example of that in your proposal, so I can't really comment on it, but I'd be very curious to see a real-world example of some code that's in common use that would benefit the new feature that you're proposing.
I decided to Google 'named while loop', and came across much the same discussion regarding Python.
The language proposal for "Labeled break and continue" is here
And is 'pretty much' the same discussion. Proposal 'A' in particular looks very much like this one.
The reason for its rejection explained here.
The reasons for the rejection are completely relevant to this proposal, because they transcend language:
However, I'm rejecting it on the basis that code so complicated to require this feature is very rare. In most cases there are existing work-arounds that produce clean code, for example using 'return'. While I'm sure there are some (rare) real cases where clarity of the code would suffer from a refactoring that makes it possible to use return, this is offset by two issues:
The complexity added to the language, permanently. This affects not only all Python implementations, but also every source analysis tool, plus of course all documentation for the language.
My expectation that the feature will be abused more than it will be used right, leading to a net decrease in code clarity (measured across all Python code written henceforth). Lazy programmers are everywhere, and before you know it you have an incredible mess on your hands of unintelligible code.
@VBAndCs The other proposal has already been approved by LDM.
The compiler (I think) lowers every loop construct to label ... GoTo label
form , during which it automatically inserts unique labels for each stage. That proposal suggests that the compiler could use them with the Exit For i
and Continue For i
.
I suspect the changes need to support this form will a lot less than this proposal, less potential to break existing code.
I may look at prototype the other proposal once I finish the one I currently working on.
@pricerc
These reasons are common to all new features, but did nor prevent them.
In fact this proposal is more important in C# and alikes. Exit do, Exit while, exit for can resolve the ambiguity when the two nested loops are of different types. But still there is a chance to have two nested loops of the same type, so we use goto in this case. This difference between C# and VB forced me to use lables to allow both programmers to use ZML in the same way.
In VB, we can make things better a littel if we add Exit For each
! I also suggested before in C# to use some identifiers. In VB this can be like: Exit Parent, and Exit Root.
You will find many requests in many languages to enhance this syntax. This doesn't makes sense after all these decades of programming and all new wonderfull features, to have to write goto just to control the flow of nested loops!
There is also the issue of using a flag just to know if the loop ended normally or broken from! I may suggest also to add this flag to the label, to be used like this:
If for1.EndedNormally Then
BASIC will be 55 years old in the next week. It is too long time to keep writing all these small workarounds over and over. If you think you are used to it, conseder the new generations with all tech they are playing with now, how will they respond to such focil syntax with the argument it is too much to fix that now!
A new generation worth to have a modern VB.
I don't think we are suggesting the explicit use of GoTo
, just the compiler hide it usage behind a syntactic screen.
I was not talking about the other proposal. I was talking of the workaround that we use when we have two loops of the same type so Exit 'type' applies only to the inner loop.
Exit For
already does that, the loop identifier is optional.
And this will be the case with two nested do loop. How can you exit the outer loop while there is no counter? My solution:
Do while cond1 Alias = Loop1
Do
If Cond2 Then Exit Do
If Cond3 Then Exit Loop1
Loop
Loop
The other proposal is currently restricted to For
, ForEach
as they have "labels" that can be used.
Other forms for loop don't require to have one. In those case I probably be explicit in my intent and use well described labels and goto. Or rewrite that section in a different form.
Do While cond1
Do
If cond2 Then Exit Do
If cond3 Then GoTo exit_loop1
Loop
Loop
exit_loop1:
Another thought: define a Loop object, with methods to control the loops, like:
Loop.Exit( )
and Loop.Continue( )
Loop.ExitOuter(level as integer)
and Loop.ContinueOuter(level as integer)
Loop.ExitRoot()
and Loop.ContinueRoot()
where level 0 is the current loop, level 1 is the parent loop, level 2 is the parent or the parent loop…. etc
Loop.HasExitedNormally
returns false if any loop exited with an exit command (or Loop.Exitxxx method)
BASIC will be 55 years old in the next week
Which is why I'm sure that if this was a common requirement, it would have been raised before!
This is VB.NET, not BASIC, but nonetheless, in the nearly 20 years the VB.NET's been a thing, this is not been seen as a significant shortcoming by the millions of users of this or most other programming languages. And I think the reasons for Python's rejection of the concept are part of the reason for this.
As far as I can tell, it is a very rare scenario. Certainly in over 30 years of programming, I've had at most a handful of occasions where something like this might have made my life a little easier. The fact is that 99% of the time break
and continue
are sufficient. The other 1% have trivial (GoTo) or structural (Refactoring) workarounds.
Can you provide a larger example of the problem you're trying to solve with this? It might help the rest of us understand it a bit better.
Oh, and I'm not opposed to this concept of a 'named loop', by the way (if it seems like I am), I just think it needs a bit more justification, because while the 'for loop' stuff is relatively trivial (because it already has a 'name'), the while loop is a more complicated piece of work (because we need to figure out how to name the loop), so needs a better justification.
I certainly faced this many times, but I don't like goto
so I use a Boolean flag like ExitOuterLoop
like this:
Dim ExitOuterLoop = false
Do
Do
If Cond Then
ExitOuterLoop = true
Exit Do
End If
' …………
loop
If ExitOuterLoop Then Exit Do
' …………
Loop
Which is longer and less efficient, but more structural and readable. By the way, I use Do/while loops as infinite loops most of the time and exit them from the body, because If I can determine a static end-loop condition, I can write a for loop. So, edit nested do loops is a common task for me.
@VBAndCs that's just a normal structured programming technique that I learnt in my first year of university in the mid 80's using TurboPascal. And back then there was no 'break' and 'continue', so you'd have 'If' blocks all over the place. Even now, I avoid the use of 'Exit Do|Loop|Etc', because they're only just barely better than a GoTo, and some (e.g. my lecturers) would argue that they do not belong in a 'structured' language.
What I'm curious to see is a real-world example, not just mock-up, because I'm unable to think up an example that doesn't have a simple structured alternative. In my experience, there are usually several ways to do something, and I frequently struggle with one way of doing something before eventually finding out that there is a simple technique that I just didn't think of originally. It could be refactoring into multiple methods, or changing to a different loop construct. Or something funky with a Select Case.
I think this is is part of why this normal scenario hasn't come up in this forum - you're not the first person to want to exit a multi-layer loop, so that means that most people are either happy doing it the way you just described, or they've found an acceptable alternative.
Even if your proposal was accepted and implemented, it would be at best months away. In the mean time, while such questions would probably be better served by StackOverflow, the people on this forum may be able to suggest an alternative for the specific problems you're dealing with today. However, for that to happen, we'd all need to see a more complete example. Ideally, a link to a repo with some code that illustrates it.
I can't search git hub for such usage. The two nested do loop is not such rare situation. The real problem ocuurs when you deal with three or more nested loops, which is rare except in math permutations, scintifice calcuations and 3d graphics. Maybe VB and yet C# ate rarely used in these areas because there are more efficient languages and tools for these apps, and .net intrinsic numeric types are not ment for these apps.
By the way:
I want to comment on the BASIC
thing: Visual Basic was a languge with visual Interface. Now, We have Only Basic.NET, but the Visual part doesn't belong to the language it self! In other words: Nothing Visual in VB.NET, so actualy it is just B.NET!
And I wish we can rename the language to be: Microsoft Basic.Core (MB.Core) :).. Unless of course the language allows a visual code designer like the MVPL.
Once again: My proposals are not issues
, but aim to enhance the language design, and I am OK if you see some of them not suitable.
Thanks.
I can't search git hub for such usage. The two nested do loop is not such rare situation.
You have your own repository, you could put a sample up there and share it.
And if it's 'not rare', then you should have no trouble finding an example in your own code.
If you use the Windows or XAML Forms designers; they're still Visual, but you're right, they're strictly part of the wider framework, which was all about bringing the power of the VB 'visual design' experience to C#. And lately, it seems use of visual screen designers has been 'deprecated', which I think is unfortunate.
Today, Visual Basic is really just a name with some history, Changing it now would probably cause more confusion than just leaving it as-is. There are literally hundreds of BASIC dialects, I don't think it would be helpful to add more, so if the name was to change, I think it would have to be to something completely different, A bit like Pascal becoming Delphi.
Maybe A#?
It's difficult to search my apps now. And I can libe with VB but I like .Core more :) I can offer a new workaround for the nested Do loops:
Do
' .....................
If Not (Function()
Do
If Cond Then Return False
' …………….
Loop
)( ) Then Exit Do
Loop
It is strange that language allows such complex structure, but doesn't offer a simple exit outer solution :)
By the way, this will be slightly better with my proposed Get
blocks:
Do
' …………
If Not (Get
Do
If Cond Then Return False
' …………….
Loop
End Get) then Exit Do
Loop
On second though, here is a funny workaround for the nested do loops:
While True
' …………
Do
If Cond Then Exit While
' …………….
Loop
End While
Of course this can't always work with 3 nested loops, but it is rare! I will close this, but it inspired me with a new idea https://github.com/dotnet/vblang/issues/398#issuecomment-487169344. Thanks.
@VBAndCs as I said; there are usually several alternatives. There are a few on StackOverflow as well (e.g. using Try/Catch blocks).
Your observation on the complexity of using the anonymous function one is interesting, because at face value, it seems more complicated than what you're asking for. But what's happened is that you've refactored your loop to use a method (one of the options I said was available to you). And the compiler's always been able to handle that.
It also happens to be a more 'structured' approach, because you no longer have 'jump' instructions (GoTo, Exit Loop).
It's difficult to search my apps now.
I like to open a CMD prompt and use FindStr /s :)
Alias
is a keyword used with API declare statement. I suggest to use it to optionally define a label name for (for, do, while) loops, to have more control over exit and continue statements, like this: Ex:Note that for1 should be treated as var name, so it can't be repeated inside method scope. The above code can be lowered to:
I implemented this idea in ZML 1.0 (repo - NuGet, but I don't have a keyword issue in xml tags, so I am using the label attribute. I think VB.NET can use
#label
as a keyword not to preserve the label word. It can even allow using #for1 directly without a keyword. Using#
before new keywords spatially when they are optional, can make it easy to add new features to VB without worrying about breaking anything. Anyway, Alias is a good alternative. This is a ZML sample:this will generate