A case for the BASIC CASE statement
Steve Fryatt (216) 2105 posts |
Indeed. It’s by far the clearest way to implement an To be fair, this kind of thing is why I tend to prefer to use C these days… :-) |
Steve Drain (222) 1620 posts |
It might be worth mentioning that |
Clive Semmens (2335) 3276 posts |
It doesn’t cause me problems at all, but I know as a matter of long teaching experience that things like that do cause problems for lots of people. For them, it makes code less clear. And except in rare cases where speed or memory economy are of the essence, clarity is the second most important thing in coding, second only to correctness. (Says the author of mudlike and occasionally incorrect code.) |
Steve Fryatt (216) 2105 posts |
I’m genuinely curious as to what the “correct” way to implement an
structure is in BASIC. Unless one resorts to messy hacks involving wrapping everything up in separate procedures and jumping out of
…which doesn’t scale well. Compare that to
This has the benefit of being a recognisable idiom (starting As I think I’ve already said, there’s a reason why I don’t use BASIC much these days… :-) |
Clive Semmens (2335) 3276 posts |
There are lots of “correct” ways – that’s just a question of not being logically incorrect. The questions are: (1) What’s the clearest way? I don’t know the answers to (2) or (3), but I don’t think they matter very much in most cases (and when they do, I wouldn’t write the code in BASIC anyway). The answer to the first question is entirely subjective. For what it’s worth, my own subjective impression is that most students find your “only clean approach” that doesn’t scale well far clearer than the CASE TRUE OF construction – although I’d certainly be inclined to introduce them to CASE TRUE OF if they had an instance with five or more cases. How often do such cases occur? I don’t think I’ve ever had one – whereas CASE X OF with a dozen cases is not unusual. |
Rick Murray (539) 13851 posts |
On the other hand, there is always: IF X THEN Do Stuff ENDIF IF Y THEN Do Stuff ENDIF The thing to bear in mind is that this method permits multiple things to be potentially TRUE while nested IF ELSE IF and CASE TRUE OF stop at the first matching clause. But, yeah, it’s a shame BASIC doesn’t have an ELSEIF to make code a little less messy. |
Xavier Louis Tardy (359) 27 posts |
Rick, a jump takes 2 S + 1 N on the ARM2, so when memory and CPU speed are the same, ie 8 Mhz, that’ll be 4 cycles, not 2. |
Clive Semmens (2335) 3276 posts |
To match the logic of Steve’s example, it would have to be: IF X THEN Do Stuff ENDIF IF Y AND NOT X THEN Do Stuff ENDIF and then you run into problems if X isn’t either TRUE or FALSE. |
Steve Drain (222) 1620 posts |
if (X) { // Do this... } else if (Y) { // ...do this... } else if (Z) { // ...do this... } else { // ...do this. } Because of the way BASIC works, you can do: IF X THEN <do this> ELSEIF Y THEN <do that> ELSEIF Z THEN <do other> ENDIF ENDIF ENDIF You must have enough It has the advantage that the expressions can be non-zero for true, but it is rather clumsy and I prefer the Edit: I do realise that this is just a reformat of Steve’s original, but doing it this way makes the action clearer, I think. |
Rick Murray (539) 13851 posts |
“Because of this pipeline, 2 instruction cycles are lost on a branch (as the pipeline must refill). It is therefore often preferable to make use of conditional instructions to avoid wasting cycles.” - http://www.wss.co.uk/pinknoise/ARMinstrs/ARMinstrs.unpaged What I’m not entirely clear on (and it never bothered me enough to find out) is if the instruction timing is exactly 2S plus 1N, or if it is 2S+1N and then two stalls for pipeline refill… |
Xavier Louis Tardy (359) 27 posts |
Figures given are from the VLSI manual.(and yes, it is for the ARM2). |
Rick Murray (539) 13851 posts |
Just to clarify: I’m not saying Branch is not 2S+1N (the document linked says that same thing), I’m pointing out that two cycles are lost due to pipeline refill… …therefore using conditionals instead of branching is more efficient. |
Jeffrey Lee (213) 6048 posts |
CASE TRUE OF WHEN X REM Do this... WHEN Y REM ...do this... WHEN Z REM ...do this... OTHERWISE REM ...do this. ENDCASE Does the language specification guarantee that WHEN clauses are evaluated in order? Or that (if multiple clauses pass their test), that only one WHEN will be executed? If evaluating the expression of a WHEN statement has side-effects, are there any guarantees for which expressions will/won’t be evaluated? All very important questions if you’re attempting to write a BASIC compiler, or hand-translating BASIC into other languages. I’m guessing the answer is that the specification doesn’t state what happens, but the implementation will evaluate each of the WHEN expressions in order, stopping evaluation once it finds the first one that passes its test. |
Steve Drain (222) 1620 posts |
Yes.
Yes.
That is an interesting point. Straightfowardly, each expression is evaluated in turn until one is equal to the expression following However, an expression could include a
It does, and is in the BASIC Reference Manual. |
Rick Murray (539) 13851 posts |
The BASIC guide states: A CASE statement can contain any number of WHEN statements but only the statements of the first one which contains a matching value will be executed It also says that OTHERWISE is used to match anything that wasn’t matched by a previous WHEN, and notes that because of this, putting WHEN after an OTHERWISE would be useless. It implies that the WHEN statements are checked in order, but does not specifically state this. Not that I could see, at least. Just sayin’, because there are so many holes in the BASIC “spec” that if you were to write a compiler, EVAL would only be a small worry compared to what can be done in BASIC. ;-) |
Steve Drain (222) 1620 posts |
You are not looking in the right place.
Edit: Actually, I think I see what your quibble is, but it is as clear as day to me that |
Clive Semmens (2335) 3276 posts |
Indeed. 10 : X% = 1 : Y% = 2 20 : CASE X% OF 30 : WHEN FNA(3) : PRINT "AHA" 40 : WHEN 3 : PRINT "THREE" 50 : WHEN 2 : PRINT "OHO" 51 : WHEN X% - Y% : PRINT "HMM" 52 : WHEN 1 : PRINT "YES!" 60 : ENDCASE 70 : PRINT "DONE" 80 : END 90 : 100 : DEFFNA(C%) 110 : X% = 2 111 : Y% = 1 120 : = 6The X% in the CASE statement is evaluated when the statement is executed, and doesn’t change when FNA changes X% – but the values of X% and Y% at the time of execution of the WHEN statement in line 51 are changed by the execution of FNA in line 30. Might this vary between implementations of BASIC? I hope not – but it’s a pretty crazy corner case anyway. |
Clive Semmens (2335) 3276 posts |
(On consideration, it’s pretty obvious that this will not vary between implementations: imagine that the expression in line 30 were something more complicated. It would be ridiculous to re-evaluate it for every WHEN. Equally, it would be ridiculous to evaluate all the expressions in the WHENs on the basis of whatever values any variables had before any of the other WHENs were executed, since there’s a fairly high probability some of them won’t need to be evaluated at all.) |
Rick Murray (539) 13851 posts |
You know, it would be logically valid to write an interpreter that finds the OTHERWISE, notes it, and then evaluates the WHEN conditions in reverse order. It would be irregular and frankly obtuse, but it would still match the description as given. ;-) Now to discuss why WHEN is evaluated from top to bottom of the CASE structure. Simple. Sophie must have been a believer in “no unnecessary work”. The BASIC code is extremely concise, as is his other well known project, TWIN. Since BASIC starts at the beginning an evaluates each line of instructions in turn, by what possible reason would the list of WHEN statements be anything other than top-down? That said, by the definition of a CASE structure as given by the user guide! a BASIC compiler could be free to implement the structure in a different order to that given. Consider this: CASE something OF WHEN 5 : ...five... WHEN 3 : ...three... WHEN 1 : ...one... WHEN 2 : ...two... OTHERWISE: ...none... ENDCASE A really smart compiler (that doesn’t exist!) might be tempted to spot the almost-sequential nature of the entries and do something like: CMP Rx, #(CaseEnd-CaseStart)/4 ADDCC PC, PC, Rx, LSL #2 B Case_Otherwise CaseStart B Case_One B Case_Two B Case_Three B Case_Otherwise B Case_Five CaseEnd This would match most use cases (pun intended!) with sequential or near-sequential elements, even though the list is in a different order. Why? Because one WHEN is supposed to match, so order shouldn’t be significant unless something strange is going on. |
Clive Semmens (2335) 3276 posts |
Perhaps I should have mentioned that I ran the code in my earlier post on the Pi/RC15, and it said, as I expected, “HMM.” Having already said “HMM,” it did not proceed to say “YES!” although it would have done if it hadn’t already been satisfied at line 51. I doubt it’s worth trying it on other machines or other versions of BASIC. |
Rick Murray (539) 13851 posts |
Yes, it’s fun to see how this works… once you remove those additional ‘:’ characters (else BASIC will complain “Missing ENDCASE at line 20”. ;-) On entry X% is ‘1’ and this is what the CASE locks in as it’s “match this” value. FNA gives the result ‘6’ (non-match), however in doing so it modifies X% and Y% to be 2 and 1 respectively. The next WHEN is 3, no match. Then 2, again no match. Then comes the WHEN X%-Y% line. This retrieves the current values, and since 2-1 is 1, it’s a match. The program prints “HMM” and exists the CASE. The WHEN 1 is never executed, as the original value has never been matched. Here’s a shorter mindscrew along the same lines as to why X% is not X%: 10 X% = 1 20 CASE X% OF 30 WHEN FNA(X%): PRINT "FNAr!" 40 WHEN X% : PRINT "Matched!" 50 OTHERWISE : PRINT "No match!" 60 ENDCASE 70 END 80 : 90 DEFFNA(V%) 100 X%+=1 110 =NOT V% |
Clive Semmens (2335) 3276 posts |
It’s not all that strange to have more than one WHEN that could match. Having functions in the WHENs that change a global variable involved in later WHENs IS strange, certainly! (Although I can imagine devious souls making use of it…) |
Clive Semmens (2335) 3276 posts |
D’uh – Zap put those in! |
Clive Semmens (2335) 3276 posts |
Ah – I find there’s an option to not have those stupid colons in Zap… 8~) The code runs, because Zap’s displaying the colons, but not saving them in the tokenized file. Only when you “dump to text”… |
Rick Murray (539) 13851 posts |
Just rebuilt Brandy v1.20 (as the available one crashed). It behaves the same as real BASIC. |