-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Return should be legal in Subs #38
Comments
"Return", I understand means to return some value (in a Function or Property Get procedure). But it could also be understood as "return to the calling procedure", although that meaning seems a bit forced IMO. |
This is prior arts in several other languages. In fact, there's prior art in VBx with its |
Total aside, but in VB6 I often use Something like...
|
I always understood the Return of Gosub as a "return to the calling line+1" but the Return of procedures that need to return a value as something different, as "return this value and exit". |
The problem with this request is indeed the conflict with the legacy However, just |
My two cents: Exit Sub is just fine then. It's a one liner. With Exit Function we can't return a value without having two lines. But that's not the case for Exit Sub. |
It's probably a runtime error because there is no require to balance the
Given that a |
GoSub/Return statements force VB6 codegen to generate a hidden local variable to keep track of "gosub list/call-stack" and there is ___vbaGosubFree call in routine prolog to deallocate this data structure no matter if it's empty or still contains outstanding GoSub calls that never Returned.
Pretty much the same as in .Net -- the exception is handled by parent try/catch block a.k.a "On Error GoTo Label" (if any) or if unhandled at all a run-time msgbox is displayed with the unhandled error description before aborting the process. |
I think that rules should be as simple as possible. |
BTW, I think I recall there was a comment from Wayne about the new Return keyword couldn't be allowed if there was a Gosub in the same procedure (not sure if I'm right because I can't find that message now here, may be it was in Vbforums). Since the new Return keyword needs to be followed by an expression, like |
My point is that if the RTE3 goes unhandled (whether specifically or generally under catch-all handler), then we know that the program would have crashed and therefore was not written correctly in the first place. Or as C guys like to call it, "undefined behavior". 😄 Somewhere else we discussed that backward compatibility can stop at the point where code starts crashing. If unhandled RTE3 results in an abort where the execution is terminated, that's also where the backward compatibility can stop. Unfortunately to support that, this requires code path analysis to statically determine whether RTE3 is possible. That can get complicated when branching or jumping are involved.
While this is technically possible, I think the 2 different uses within the same procedure would be quite jarring and confusing. Following the principle of least astonishment, I'd prefer that the The irony here is that the |
About the first point, you can write this legal code in VB6:
Why someone would do that I don't know, but it is possible. About GoSub, you must be right about its origin (and how it came into VB6), but I do not agree with most people that think that it is intrinsically evil (or something like that). |
See, that's why we want to make sure it's easy to refactor the code and the ability to refactor code is heavily dependent on whether the refactoring can be done without changing the behavior with the code. With In a modern language & IDE, this would be easily done by doing a "Extract Method" refactoring which also take care of moving variables or converting into a parameter. But with a We do not want tB to fall in the same position that VB* codebase has where people look at it, and say "Forget it. Let's just rewrite the whole thing from scratch" which is actually another mistake. The desire to rewrite rather than refactor will stem from the fact that you can't reliably refactor code with elements similar to |
I see your point on refactoring, and I agree. Well, GoSub seems at first glance easier to refactor, you need to look for the last Return and that's the End Sub, and others Returns in the middle are Exit Sub. GoTo seems impossible, a GoTo can jump anywhere. I also defend the occasional use of GoTos in VB6, because sometimes you need, for example, to do this:
|
For continuity reasons I believe we should strive to get this Return syntax allowed in Subs. The runtime error of the old syntax is a consideration, but this is largely mitigated by us simply disabling the new Return syntax when the legacy Gosub is encountered within a procedure. That just leaves the nonsensical use of Return, with it throwing a runtime error in the old syntax without any Gosub appearing in the procedure... and I feel that supporting that 'feature' would be taking the 100% compatibility goal too literally here, without considering the bigger picture. |
LoL
Well, if you or I as an adult, were to pick up a baby rattle and start playing with it, giggling like a pre-toddler again, I wouldn't call that intrinsically evil either; but any reasonable observer of such behavior would quickly conclude that there is some sort of significant maturity issue at play with us for doing so. Supreme Court Justice Robert H. Jackson first used the "suicide pact" phrase in comparison to the US Constitution, and I begin to wonder at this discussion if we're not edging towards being able to use that phrase in comparison to the concept of "100% Backwards Compatibility". Perhaps we should clarify a little on the question of "How much Backwards Compatibility is 'Too Much' backwards Compatibility?" Otherwise we risk condemning tB to re-commit the sins of the past when a significant part of our hope for this was some more progress towards the future? ...to say nothing of the relative effort involved in getting every jot and tiddle "just like before" -vs- the opportunity cost of not making other important progress. |
@mburns08109 I thought the point was so that pure VB6 code would compile and run in tB as-is. To me (someone who maintains a lot of old VB6 code - and there are many of us) that would be extremely valuable. From other posts I had the impression that tB would also offer some set of selectable options to gradually move away from the legacy limitations of VB6. A separate mode where |
I was kind-of hinting more towards what Ben was saying about refactorability -vs- trash-and-redo, and hint that if "backwards compatibility" questions don't get examined in the light of what he was saying, then perhaps we're edging more towards the "suicide pact" side of things than we should really be comfortable with (as opposed to offering any concrete advice about whether gosub-less Return statements should be either supported, treated with the same runtime error that VB6/VBA do, or treated as compiler errors). I guess what I'm trying to say is: when is it okay to leave some old things on the trash heap of history -vs- assuring that every memory leak is repeated for the sake of compatibility? Could this gosub-less return topic be one of those issues? |
Only if it's leaking memory :-)) Are we repeating a memory leak here indeed or I'm missing the hyperbole? Btw, something innocuous as adding new keywords to the language breaks compatibility too. For instance TB added |
There are two ways of following rules 1) when you understand the reason behind the rule, 2) when you don't understand it. When it comes to God's rules, you need to follow them for your own good, better if you understand, and if you don't understand, better for you to follow the rules anyway because God is an Authority and He knows why even if you don't (in your tiny human mind). When it comes to men rules, there are laws, you are obliged to obey the laws whether you understand the reasons behind them or not. And the government is also an authority that enforce the laws. When it comes to other rules, that more than rules are common beliefs, or traditions, you can also obey 1) if you understand, and 2) if you don't understand why that rule is (and perhaps where it comes from). Many people believe something because many other people does, or prominent people say so. When it comes to "never, ever using GoTo", what do you think?
When you understand the issue, you can agree or disagree (hence to obey or not obey, or just obey in part, according to what you understand that is more convenient), but if you don't understand it, you can only obey or disobey by blind faith (and perhaps criticize other that don't follow the rule that you follow -but don't understand-) If you think that someone using occasionally GoTo in VB6 (I'm not talking about other languages) is like playing with a baby rattle, think what you want. |
It's not really what I think that's the issue that should concern you (which is partly why I didn't voice a direct opinion on the options). It's the question of how you our your successors will view the code when looking at it from a future perspective - especially if, as Ben hinted at, the question of the day at that point will be "refit/repair/refactor this?" - or "nuke it from orbit and start over?" (the extra Hyperbole is included free of charge.) |
There are already many millions of VB6 code lines already, you cannot change that fact. If tB adds anonymous functions, GoSub, and possibly GoTo too, won't be justified anymore and nobody should use that in new code. When the programmers writes a GoSub or GoTo, tB will issue a warning, that should be enough. It looks to me like the vaccinated complaining because some others don't want to take the vaccine. |
When you're trying to provide 100% backward compatibility, then there is no such thing as "Too Much" backwards compatibility. I understand the point you are trying to make, but the difference between 100% compatible and 99% compatible is WAY MORE than 1% when it comes to developer migration effort. Microsoft understood this when they created Excel. Anything that prevents existing VBx code from running in twinBASIC will cause many developers that are tB-curious to simply throw up their hands and think, "just another failed VBx clone." When you're trying to gain market share as an upstart, you need a product that Just Works™. Now, I think it's reasonable to stop at 99.999% compatibility if the final 0.001% amounts to actual implementation bugs in VBx AND there is a project-wide "Quirks Mode" flag that will recreate those old bugs for the developers that relied on them for whatever reason. But |
The way to encourage better programming practices moving forward is to provide an opt-in mode that disables language features like |
Bump. A Return outside of a Gosub block, then catching the runtime error that is certain to result is... bizarre? I feel like this could easily be accommodated by an "absolute" project switch for legacy compatibility. Almost nobody would be caught by this, and a project switch could keep the 100% promise. |
Just wanted to put out a different approach:
The |
Need to be really conservative with taking over keywords... |
Hmm, |
But it wouldn't be a result in Subs, and nobody is talking about removing
This is already legal and prints the expected 4. |
@fafalone Its not a third way. There would be no need for 'return Value' syntax so that new usgage in twinBasic could be retired before V1, a perfectly legitimate change. The proposals I made were to try and resolve the issue around the use of return in a Sub. The = is needed as I envisage result (or whatever name is used) being an alias for the Method name variable. |
Oh, my. This thread is sprawling far beyond what should be the original scope. Some of the points sounds like they are a separate proposal, and probably should be dealt in their own issue, and other points seems to be taking a different approach altogether. Let's recap: VBx currently:
While I seriously doubt there's anyone trapping for run-time error 3 tB currently:
Other languages tend to follow the same convention where:
tB currently doesn't have a The ideal and simplest outcome would be to just allow The other idea of Using |
Now I figured out something which was not apparent immediately. With I'm all for having plain |
The only fully back compatible solution I can think of is to have the |
Hmm, that entails that for consistency, the .bas/.cls files wouldn't have other tB features (c.f. #13 ). I don't think that's the case currently. I'm not sure how I feel about the idea of having the file extension enabling/disabling the language features. |
Have we considered using Sub Foo()
Exit
Debug.Print "not called"
End Sub Function Bar() As String
Exit "return value"
Debug.Print "not called"
End Sub Or some combination with Function Bar() As String
Exit With "return value"
Debug.Print "not called"
End Sub |
This comment was marked as off-topic.
This comment was marked as off-topic.
I disagree. If we use vbWatchdog as-is then yes. If instead a new |
This would seem to avoid the compatibility issues though TBH I'm ambivalent about overloading the word Also, from my POV, I find it mildly annoying that if you had a situation where you had to alter the procedure from If we were to implement
Just to point this out, we have an open issue on Try/Finally as a keyword ( #61 ) which also hits on the issues we already have to deal with the different keywords & strategies for leaving a routine and error handling which as I explained over there is ironically errorprone. Anyway, to your point; I need to ask - is it a good idea to alter the behavior of the |
I'd be against modifying |
I think we're talking about different things. Consider this hypothetical pseudo-code:
The question is if there's a |
We're not talking about different things, I'm aware you meant if it was inside the That's what I meant-- you're changing the meaning of I'd say that yes, it's breaking backwards compatibility, because you're changing the meaning of existing code simply by virtue of someone wanting to add a This doesn't destroy the value of the |
My point is that when inside a Note that the same problem would exist with |
I really can't see how having to figure out that I think the value in Mind you I would, as mentioned above, support a different |
I can't see the point in arguing about try/catch in the context of a return syntax. In VBA, vbWatchdog was constrained by the need to work within existing VBA code. With twinBasic, try/catch/finally syntax can be added as new twinBasic syntax. The only constraints on such an addition being any potental conflicts between code implementing vbWatchdog try/catch and any new try catch syntax. |
Apologies if I'm missing something here or misinterpreting. I'm confused by the idea of calling this "altering the behavior" of Exit or it posing a risk to backwards compatibility. Right now "Exit Sub" or "Exit Function" to me means not just jump out, there is also clean-up of COM objects calling The behaviour of "Exit " is not defined inside a try-catch-finally block because it doesn't exist in VBA yet, so we can't be "changing" the behaviour and breaking backwards compatibility, the behaviour is yet to be defined. And having There is no backwards compatibility to break because this: Function Foo()
Try
Exit Function
Finally
' Clean up before exit
End Try
Exit Function ...is not valid code yet. So there is no backwards compatibility to consider. There is "expected behaviour" to consider, and designing features to feel idiomatic in VBA and unsurprising. But you're not going to break any existing code by defining a finally block to run on an early @bclothier is right in that the value of a finally block is that it always runs regardless of what happens inside the try block. To free resources or close context managers. note I'm ignoring |
FWIW I had the same instinct, everyone has expectations for |
Those are handled by the compiler whereas the The point is that if
Now suppose we then update the procedure and put in a
What's the behavior of You are correct that right now, the behavior of In this view, I think I'm arguing that
Just FYI. In VBx's vbWatchDog, the
I should note that I've made boneheaded mistakes like this:
|
People only have to convert their VBx code to tB once, but then they have to maintain it forever after. It seems better to me to err on the side of having a well behaved language feature vs. making the transition to tB a little easier. Otherwise the programmer will pay for that many times over instead of just once when they update to tB. Personally I would expect that the @bclothier thought experiment... If hypothetically there were an IDE refactoring that would transform from your first example to the second... that could indeed cause some surprises. Perhaps having the refactoring add a warning and/or comment about how it affects goto / exit would be a good idea in that case. The VS2010 VB migration assistant would very liberally add warnings like that. (E.g., for array bounds change from 1- to 0- based). |
This was supposed to be an example of refactoring by hand. If IDE were to provide a refactor, it'd be probably smarter than that and substitute in The more recent languages avoid this problem by simply never giving the equivalent of |
I don't think hidden non-user code is a reasonable comparison here. VB programmers don't think about, or consider, hidden codepoints, whereas we very much expect consistent behavior in user code flow. Hidden code isn't subject to all the random errors and bad practices of user code; there's no world where everyone writes flawless finally blocks that don't trigger errors.
This also seems entirely unreasonable. Code doesn't cease to the VB6 language just because you've put it inside another type of code flow control block. This is like saying we can throw all the rules of the language right out the window because of some unrelated label. It's absolutely breaking backwards compatibility to change the meaning of existing code, end of story. It doesn't matter that it's a
And I for one certainly look forward to taking advantage of that value. I don't care to have it forced upon me by breaking the rules for existing syntax. I'll personally, in forseeable cases, not be using If we are going to handcuff users, I much prefer Ben's alternative of disallowing
This was .NET's philosophy; I'm using VBx and tB because I prefer that language, despite it's shortcomings, over "better" languages, for the uses where it's practical (and even somewhat impractical, if it's possible). |
That seems to be 100% accurate - the essential definition of what "backwards compatibility" probably means to most people. But once you alter your code deliberately, why would it be expected to behave the same way? Alteration could be updating it to use a tB language feature that did not exist in VBx, or anything else. I don't think this is the sense in which "backwards compatibility" really applies. |
Keep in mind that typically in a migration project, it's seldom all at once. More likely, they'll want to keep everything as-is and update only this and that and gradually update stuff as they go, which helps amortize the development costs. That's the biggest win with the backward compatibility promise of tB that other languages can't even begin to fulfill. |
Can't we just generalise Exit, so that it doesn't need to be told what it's exiting (other than it not being a loop)? Presumably for functions and property-gets, it just returns the default? How about |
Don't think
Compare with a C-family pseudocode:
The appeal of BASIC is that you can at least identify what type of blocks you're closing. A generalized
So yeah, I don't think a generalized form will work very well.
I find it interesting that you cannot |
Sorry, my second paragraph was disconnected from the first. I guess I initially envisaged a general At this point, I'm only proposing |
Wait... How about, in a Sub, you can |
FWIW, I think it comes close to |
Describe the bug
Trying to
Return
from aSub
raises a "internal error"To Reproduce
Create the code:
It will highlight
Return
as an error.Expected behavior
No error. It should be legal to return. Had I put in something to return (e.g.
Return 1
orReturn "foo"
), then it's appropriate to show an error since it's aSub
.BTW, I prefer this over
Exit Sub
because this avoids the need to change the code should it change fromSub
toFunction
(or vice versa).Desktop (please complete the following information):
The text was updated successfully, but these errors were encountered: