TRUE as integer?
Pages: 1 2
Chris (121) 472 posts |
Trying to unpick some old code, when I came across
in a loop. Is this equivalent to
If so, is there any disadvantage to substituting the latter for the sake of clarity? |
Andy S (2979) 504 posts |
Was the author trying to save a tiny bit of memory by using TRUE rather than introducing a new constant? Would this even work? I would have thought it would get interpreted as the same code but I know next to nothing about how BASIC works under the skin. Either way, it looks horrible to me. |
Jeffrey Lee (213) 6048 posts |
TRUE is a single-byte token, so there’s no difference in memory use. Maybe it’s a performance optimisation? Processing the TRUE token is likely to be a lot faster than parsing a number (even if it’s just a single integer digit) |
Clive Semmens (2335) 3276 posts |
If you’re into that kind of level of optimization,
would be even better. Or was the code already using all the resident integer variables? |
Chris (121) 472 posts |
Yes, that’s what I was wondering about. The question is whether it’s worth preserving the rather arcane formulation now that machines are so much faster. The code probably dates from the Arthur-era, or even earlier, and the loop only runs from 7 to 0, so I’m guessing the speed difference between the two constructions would be unnoticeable. |
Clive Semmens (2335) 3276 posts |
If the loop only runs from 0 to 7, it would have already been unnoticeable in Arthur days. Habit? |
Chris (121) 472 posts |
Yes, I guess so! (Btw, it’s not my code – I’m just trying to make sense of it, and hadn’t seen that formulation before.) |
nemo (145) 2554 posts |
It’s a common substitution for BASIC compressors and optimisers. TRUE is much faster to evaluate than -1 (though “much” is relative here). I built a version of BASIC that had lots of hard-wired constants in it, including “TASK”. The advantage is actually two-fold:
|
Gerald Holdsworth (2084) 81 posts |
Just did a comparison, just to see for myself – first on BBC Master, then on RiscPC running RISC OS 5.24: |
Chris (121) 472 posts |
I guess it seems to me that these kind of substitutions are best left to optimisers, rather than being in the source. But then I suppose that judgement depends what’s more important – speed or clarity – and whether the code’s ever going to be edited by anyone else. |
Clive Semmens (2335) 3276 posts |
Did you also try it with c% instead of C%? Should be a tad slower. |
Clive Semmens (2335) 3276 posts |
I don’t know about you, but I for one don’t fancy trying to unpick code after it’s been mangled by a compressor or optimizer… |
Rick Murray (539) 13850 posts |
Probably won’t make much overall difference, but… Start with T% = TIME (no need to use a float for that!), and enter an empty loop until T% <> TIME. Then set T% to TIME again. I threw together this:
Pi2 ARMv7 900MHz gives me… *SomeTimings C% + Q%: 36 += Q% : 31 C% + 1 : 36 +=1 : 31 -=TRUE : 29 …as the most consistent running it twenty times. The most interesting thing is that there is no notable change between Q% or 1 for the increment, but there is a noticable change between the All tests performed single tasking, not in a TaskWindow. For that, the results are: *SomeTimings C% + Q%: 36 += Q% : 32 C% + 1 : 36 +=1 : 31 -=TRUE : 30 For the lulz, I compiled it with ABC. The result was 9cs for everything.
I completely agree. Unless there is a VERY pressing need, life’s too short to waste time with such things. |
Clive Semmens (2335) 3276 posts |
Go on, how much difference does using C% versus using c% make? |
Gerald Holdsworth (2084) 81 posts |
On a BBC Master, C% was 25cs faster than c%. On the RiscPC, negligible – sometimes c% was faster than C%, and others it was the other way round…only by 3 or 4cs though. |
nemo (145) 2554 posts |
As I’m sure I’ve mentioned elsewhere, be very careful with optimisers that rename variables to the resident integer variables – this code will behave very oddly if ‘optimised’ in that way: REPEAT PROCp UNTILvariable%=0 END DEFPROCp LOCALvariable% variable%=0 ENDPROC By ‘oddly’ I mean ‘will randomly go into an infinite loop’. |
Clive Semmens (2335) 3276 posts |
Let me know of any “optimizers” that do this, and I’ll know to avoid them. I like optimizers written by competent individuals… (Not that I use optimizers at all…) |
Clive Semmens (2335) 3276 posts |
Mind you, that code would behave pretty oddly anyway, since variable% is declared LOCAL, and is therefore not available in the UNTIL line… Or are they two different variables both called variable% ? Perfectly legal, if confusing – and they should be recognized as two different variables by the optimizer, unless it’s been written by a total incompetent… |
Frank de Bruijn (160) 228 posts |
A local variable that didn’t exist outside the procedure before the first call is created and made 0, so variable% does exist (and is 0) after the PROCp call. Change variable% to (e.g.) V% and there won’t be a need to create a ‘global’ V%, but the existing V% may have any value, so the loop may never end. |
Clive Semmens (2335) 3276 posts |
Eh? It’s a LOCAL variable. It only exists inside the procedure. |
Clive Semmens (2335) 3276 posts |
Interesting – just tried that, and it behaves as you say. All these years I’ve been programming in BASIC and never discovered that. Crazy though to work like that. Nemo’s code remains very odd – either it’s a failure of logic (testing a variable that you haven’t created) or it’s an odd way to check that your procedure has, as a side-effect, created something you know damn well it should have created. Perhaps some versions of BASIC work the way I assumed, and others work this way? In that case, this could be a very abstruse way to check which version of BASIC you’ve got… |
Chris Hall (132) 3558 posts |
The RiscBASIC compiler compiles it (and runs it) without error (as it should, as it is compatible with the interpreter) and the ABC compiler says variable% does not exist (as it does not do LOCAL variables, instead using PRIVATE variables, but then it never pretended to be compatible with the interpreter). Attempting a compile with RiscBASIC can act as a syntax check and will flag up any undefined functions and procedures, whether or not they are called at run time. Eh? It’s a LOCAL variable. It only exists inside the procedure. And in any procedures or functions called by that procedure, i.e. until the procedure has ended. Unless of course you are using ABC where it vanishes whilst any other procedures or functions are called (not sure whether you see the global value or some random data). |
nemo (145) 2554 posts |
That’s one of those questions that answers itself really. BBC BASIC on Beeb and RISC OS works like that. My example code was deliberately contrived of course, but illustrative of a class of error that’s easy to make, especially in the typical “change and try, change and try” mode of BASIC development. The fact that the code works (much like your assumption of how BASIC must work) right up until the moment it suddenly doesn’t is testament to how this kind of thing can actually ship in commercial products. And has. One of the interesting greebles with Wimp2 was that it could sometimes deliver null polls to programs that had masked off null polls… resulting in code being called before it was expected to be by the programmer. It was (un)surprising how many BASIC programs just blew up because of unknown variables. One construction that I (emphasis for comedy value) fell foul of was this method of safely initialising a global variable in some library code:
This ensures the variable exists and starts at zero. One can then:
However, one day StrongBS decided that |
nemo (145) 2554 posts |
For Clive’s benefit, the BBC Basic we are familiar with has Dynamic Scope. That is to say, the set of ‘variables’ that a particular procedure or function is able to access can change outside its control. For example: global%=12 PROCprintglobal PROCcheat END DEFPROCprintglobal:PRINTglobal%:ENDPROC DEFPROCcheat:LOCALglobal%:global%=99 PROCprintglobal:ENDPROC In reality, though This is not how ‘local’ variables work in other languages, and in other implementations of Basic. Naturally, for Basic to be able to save the current value, the variable must be made to exist if it doesn’t already. Hence my contrived example works perfectly… as long as it’s not one of the resident integer variables. Oh, and the reason the resident integer variables don’t get zeroed by |
Clive Semmens (2335) 3276 posts |
That I was aware of. I feel utterly stupid not realizing about the creation of global variable% when a procedure uses it locally, since I knew about the way the global variable got saved to allow the local version to use the same slot…not a problem I’d have bumped into, since I never use variables without initializing them… whistling innocently and crossing his fingers behind his back… |
Pages: 1 2