BASIC functions to save/restore all variables
David Gee (1833) 268 posts |
Microsoft QuickBasic/QBssic had static variables in functions and procedures (subs) about 30 years ago. And structures (Type… End Type) too. Most of these made their way into Visual Basic. Though there were some weirdnesses when it came to calling subroutines. Being Microsoft, they then proceeded to make it all horrendously complicated so it’s now just an alternative longer-winded syntax for C#. |
Bryan (8467) 468 posts |
Simples! with a few caveats. The main one being that it only works with Integer and String variables accessed with Indirection Operators – as per Section 23 of the BBC Basic Referrence Manual. I have a BASIC program which has been doing this sice the days of the BBC Micro. Before the program starts the !Run file loads the Data, for example :- The BASIC program starts with At end of program, or any other time the data needs saving If I have got the basics right from memory, then you can see that the data always loads at the same addess every time the program is run – leaving plenty of space for the program to grow bigger over time. My Raspeberry Pi has ooodles of RAM. The variables to be saved must always be accessed using indirection operators. (the primary caveat to the idea). Othe variables of any type can be used as required and will not be saved. |
GavinWraith (26) 1563 posts |
Only if we are talking about BBC BASIC does ancestor make much sense. For other languages I guess the term has to mean an enclosing scope , which is not the same. And all higher order languages use the notion of upvalue which is precisely a variable defined in an enclosing scope . How would you define the notion of currying without it? The implementation of a higher-order language cannot get away with a single global stack; a more complex data-structure is needed. OK, BASIC is a first-order language, but that has an educational cost. This was Dijkstra’s point: if all you know is a first-order language some methods of coding remain inconceivable.
|
Rick Murray (539) 13850 posts |
I’ve updated the link to a direct download (doesn’t need Drive/scripting) so it’ll work with NetSurf.
That works fine. Given 234, 345, 456 as inputs, both BASIC and ABC return 702. I think what we’re talking about is more like: DEFFNcomplex(a%, b%, c%) LOCAL d%, e% PROCstrip PROCstrip =a% + b% + c% + d% + e% DEFPROCstrip d% = d% + 2 * e% e% = e% / 2 ENDPROC Which will be relying upon being able to access d% and e% in a child function, which works but ideologically shouldn’t. There’s a huge bug, anyway, as d% and e% are never set. ;)
That’s a bit harsh. ABC behaves in exactly the same way as C, and probably most other concurrent languages, in treating LOCAL as local to the function. If one is writing code like Steve’s example (passing values, using RETURN to update them) then that’s fine.
I don’t think it makes sense, because in this case you’re essentially relying upon a side effect of something, notably that local definitions take effect from that point on. The danger here is that different code paths may result in a non-global being assigned different values. There are unlikely to be arguments, this is a peculiarity of BASIC.
Yes. BASIC has exactly two types of variable. The current global-scope ones, or the previous ones that are stashed on the stack.
This is not documented anywhere. I think it’s something the interpreter does because of how it works, but not something you should rely upon.
That makes sense, but I think I’ve used goto in C maybe twice in my life. I also believe in the principle that, in a function, you should exit at the first opportunity. I know some schools of thought hold that a function should have exactly one entry and exit point, but I have no truck with that nonsense. One entry point, of course. DEF FNmyFunc(x%, y%) LOCAL rval% IF (y% > 0) THEN rval% = x% DIV y% ENDIF =rval% ;) I’ve also fixed your fatal bug.
I found and downloaded a copy of QBASIC from 1991. It’s something like 370Kish in length, so, yeah, I’d expect it to have a few more features than our interpreter that is about 300K smaller.
Exactly. It’s a BASIC thing.
A quick Google suggests that currying is a word (named after somebody) where a lambda function accepts exactly one parameter. I’m looking at your code example and trying to figure out what that is, but I do rather worry (having never come across currying before) that it might be some artificial restriction for some sense of code purity. Surely a function should accept “as many parameters as are necessary”.
I think these days things are massively more complex than in the past, not just in what paradigm is used (objects, frameworks, and so on) but also because one might want a language to spread the work around the available hardware (multiple cores, for instance) without the programmer having to explicity manage this. If nothing else, this sort of thing could be handled – if not by the language itself – by a library that makes it work. As for a single stack? Well, let’s consider something like a simple web video player. There’s the fetcher, there’s the demux, the video codec (which may or may not require seperate code to blat the pixels to the screen in some manner), the audio codec, possibly some form of optional audio correction like EQ or just downsampling 48kHz 7.1 to whatever the machine copes with. It’s probably a bit foolish, however, to compare 2023 tech with 1981 tech. ;-) |
jan de boer (472) 78 posts |
forgive me if i am wrong, but i always thought that LOCAL variables were preset to zero or "" in the case of a string variable. So d% and e% will evaluate to 0 and no error notification appears. ‘Nice’ is is not ;-) |
Rick Murray (539) 13850 posts |
Yes, I think locals do default to zero, but… d% equals zero plus two times zero Repeat as much as you like, it’s still zero. ;) It might be that changing BASIC’s scope rules isn’t viable? After all, LOCAL variables are actually globals. When the function finishes, they’re just set to zero, but they’re still there as a known and valid variable. 10 PROCmeh 20 PRINT myvar% 30 END 40 50 DEFPROCmeh 60 LOCAL myvar% 70 myvar% = 123 80 ENDPROC |
Paolo Fabio Zaino (28) 1882 posts |
Technically, we both introduced a bug (no fix in your code), division by 0 is certainly NOT zero, it’s instead undefined ;) , but sure the IF/ENDIF in this case doesn’t cause the code to become harder to read. The point of the example was to ensure there is always a clear and single exit point from a function and not multiple exit points which would be hard to control over time. It’s perfectly fine to use IF/ENDIF of course, however people won’t do it and use IF ENDPROC/= instead, which is the problem (aka causes multiple exit points). |
Paolo Fabio Zaino (28) 1882 posts |
C is a different beast, we are talking of an example of first-order traditionally interpreted language (aka not even transformed into bytecode). Creating hirearchies of multiple IF/ENDIF in such a scenario will reduce performance, hence the fact that so many use IF ENDPROC/= . In C, given the nature of the language (C is a language that was expressly designed for compiler developers!), you’ll have a ton of optimisations that will make the hirearchy of many if {} very, very (veryyy) light weight. BBC BASIC, in the other hand, still has slow expression evaluation (this is the reason why a FOR/NEXT loop is so much faster than the warious REPEAT/UNTIL, WHILE/ENDWHILE etc), FOR/NEXT evaluation is highly optimised, but if you try this:
For the people that may not fully understand the above code: x% will “reach” value 0 only when the value of I% will be above 10000. This code, that is for testing and understanding only (aka completely useles for real life cases), simulate the introduction of an expression evaluation for the FOR/NEXT loop in BBC BASIC (not in machine code). This is to simulate what happens (for example) in a REPEAT/UNTIL I%<10000 basically. Compare it with other loops that use expression evaluation (in BBC BASIC, aka not in machine code) and you’ll see FOR/NEXT performance equate with (if not getting slower than) the other loops. Point is, BBC BASIC is a traditional interpreted language1 (again not even bytecode), so it’s extremely sensitive (in terms of performance and bugs) to the way people write their programs. Another example (that describes well it’s nature): you may have syntax errors in your code, living there for decades lol if that specific branch of code doesn’t get executed that often. 1 Yes I strongly believe that BBC BASIC should be rewritten from the ground up, but that is just my personal optinion. |
Colin Ferris (399) 1818 posts |
BBC BASIC has already been rewritten in {C} for the ‘Arc’ years ago. By the way is there a BBC BASIC for Android – things like a ‘Arc’ type calculator for a smartphone would be nice. :-) |
Rick Murray (539) 13850 posts |
Matrix/Brandy is portable C so it runs on just about anything. I even made a version (without graphics) for my PVR. ;) Alas, it is GPL… |
Paolo Fabio Zaino (28) 1882 posts |
Which one do you mean? Matrix Brandy BASIC? If so then, Matrix is an implementation that tends to stick as much as possible to the original BBC BASIC we still use on RISC OS, so it’s another old school interpreter, not a rewrite from the ground up to remove all the idiosyncrasies. |
Rick Murray (539) 13850 posts |
Is this wise? You say removing idiosyncrasies, I say introducing incompatibilities. Perhaps BASIC should be left as is, and something else introduced to eventually replace it? Lua? Python? If it’s a friendly licence and available directly in the ROM, I don’t see why it can’t ultimately “do all the stuff BASIC does”. |
David Gee (1833) 268 posts |
Richard Russell has a version of BBC Basic for Android (and Linux, Mac, iOS) based on BBC Basic for Windows, but using SDL to do the graphics: here: https://www.bbcbasic.co.uk/bbcbasic.html Unlike C, Pascal does allow you to declare functions and procedures inside other procedures and functions — I believe Ada is the same. |
Paolo Fabio Zaino (28) 1882 posts |
True, but again I mentioned it as just my opinion (aka: not something we may all need). The point is, if we need a ROM based programming language, then we should have one that doesn’t stop the OS from improving. What I mean by this is, both Obey and BBC BASIC were great in the 80s, ok in the 90s, now… well… ermmm… please find a nice way to say what I want to say XD
I agree with the principle. For what concerns both Lua and Python, IMHO they are far better built using GCC and having support for OpenDL than being shrunk down to be in ROM and Modules. |
Rick Murray (539) 13850 posts |
I don’t “do” tact. You’d be better off asking
The problem here is that if we can’t find something that can be made a ROM module, then we won’t have something that could potentially replace BASIC. The thing is, BASIC is always there and always present. It can be relied upon. Of course, the alternative is to simply leave BASIC as it is, and hook a disc based interpreter into things (not as a ROM module), with the expectation that the machine will be booted with a standard set of resources. There is precedence here as while the internet stack is in ROM (well, for some of us…), it doesn’t do much without the boot sequence to correctly configure all the bits in the right order. Plus all the various things in System, plus the entire set of user choices, fonts over the built in ones, etc etc etc. That would, certainly, be an easier option. If I recall, the DDE (or is it the RISC OS source?) already has a version of Perl….but I think we’d be better with a language people can read. :P As for BASIC, I don’t need to say “freeze it except for tweaks and updates to the assembler” as that’s about where it’s been since a long time. No point fixing the LOCAL weirdness, as it’s not actually documented that you can access local variables from other functions, so anybody doing so is relying on “because it seems to work” behaviour. But, then, to work with older systems it would need to be available as a softloaded module, meaning disc based resources, so we might as well dump a modern language there. Question is – what? |
Paolo Fabio Zaino (28) 1882 posts |
Indeed. I think a good sugestion might be to start from understanding which scripting language is actually the favorite among the majority of the community here… then see if it can be implemented as a Module. |
David J. Ruck (33) 1636 posts |
bash |
Chris Hall (132) 3558 posts |
There’s a huge bug, anyway, as d% and e% are never set. ;) The huge bug is trying to define as LOCAL a variable whose global version does not (yet) exist! Perhaps such an attempt should produce an error ‘Unable to create LOCAL variable as no such global variable exists’. The whole point of a LOCAL variable is so that you can use a loop counter such as i% without worrying about corrupting its value higher up the stack. There’s no point in defining a variable as LOCAL if you are not trying to protect a global varaibel!! |
Steve Pampling (1551) 8172 posts |
As a sample of (assumed) bottom up programming where the subroutines have been defined first1 and the defined LOCAL is ready to have a protected global variable, it seems fine. 1 Quite likely if you’re in the habit of re-using code blocks that you managed to make bug free and independent. My belief is that when you get it right, cherish it. |
Rick Murray (539) 13850 posts |
Ideas like that set one up for a lifetime of bad programming. To quote, even, the BASIC manual: It is good practice to declare all variables used in a procedure as local, since this removes the risk that the procedure will alter variables used elsewhere in the program.That BASIC works in that odd way is an implementation detail. Because if you’re not declaring variables as LOCAL, they’re being created global and sprayed all over the place. Bad dog, BAD. |
Rick Murray (539) 13850 posts |
<waits patiently for everybody to say “BASIC”> |
Steve Pampling (1551) 8172 posts |
Part of me wonders how many programs would break because the author assumed that declaring a variable within a subroutine without stating LOCAL would default to global. |
Rick Murray (539) 13850 posts |
First thing I did in my Visual Basic programs: Option Explicit This requires variables to be desired before use (like C etc). |
Chris Hall (132) 3558 posts |
Part of me wonders how many programs would break because the author assumed that declaring a variable within a subroutine without stating LOCAL would default to global. None. The variable would be global. This requires variables to be desired before use (like C etc). Something that you would only do once a programme is working perfectly (obviously). |
David Gee (1833) 268 posts |
It should have read “declared before use”. Assuming that’s what you understood it to be, I don’t see why you would wait until the program is working perfectly—declaration helps you to write programs correctly. In “classic” VB there was also |