Functions with more than one entry
Pages: 1 2
Paul Sprangers (346) 524 posts |
Wouldn’t it be useful if a function (in BASIC) could have more than one entry, and hence more than one exit? For example:
Or does it already exist? If so, what is the exact syntax? |
GavinWraith (26) 1563 posts |
Should that not be more than one returned value ? Like this perhaps?
|
GavinWraith (26) 1563 posts |
I have often wondered why BASIC, C, Pascal, ….. only have functions returning a single value. It is not as if multi-returns or multi-assignments involved any great difficulties of implementation. Functions expect to find their arguments on the stack, and to exit with their return values on the stack. FORTH, Pop and Lua are the only languages with multi-returns that I can think of offhand. Because most procedures need to return errors as well as calculated values, it makes sense to have multi-returns. A frequent convention of Lua is that a function returns either a non-nil value if the calculation is successful, or nil followed by an error in case of failure. So or, more compactly
|
Paul Sprangers (346) 524 posts |
Yes, that’s what I meant, apologise. (My English is sort of self-construct, not to mention my BASIC.) |
Gerald Holdsworth (2084) 81 posts |
I’ve written functions in Pascal with multiple return values. You just use an array, or an object, to return them. Javascript can also return multiple values, using this same method. |
David J. Ruck (33) 1635 posts |
BASIC doesn’t have any type of data structure so you can’t return a struct as in C. Maybe it’s time to expand your horizons to Python which automatically turns multiple return values into a |
Stuart Swales (8827) 1357 posts |
Just use a |
Rick Murray (539) 13840 posts |
It is possible, but only due to the looseness of the parser. It shouldn’t be used in actual code.
This is due to the heritage of functions being a mathematical construct. Hence, they are supposed to accept some form of input, perform a calculation, and return the result. Actually, it isn’t strictly true. While a function in BASIC only has one formal return value, both PROC and FN can have an input variable prefixed with RETURN in which case it is passed by reference rather than by value.
VisualBasic has a similar construct using ByVal and ByRef (IIRC, it’s been years…), however in both of these cases there is a risk of grotty things happening by allowing functions to directly mess with the input values in a global scope. Edit: I was writing this when Stuart mentioned RETURN.
Depends upon the language implementation. Under RISC OS, APCS-based languages will place the first four input values into R0-R3, and expect the output in R0.
Hehe… a lot of DeskLib’s convention is to return NULL if something worked. If it’s non-NULL, then it’s probably a pointer to an error block. This isn’t always true – File_Open for example returns zero if there was a problem or otherwise a file handle, but certainly a lot of the lower level SWI calls are defined like: extern os_error *Wimp_SetColour(int colour);
I can see this being abused somewhat, leading to potentially messy code and/or muddling up what is returned what. Was it pigs,fly or fly,pigs? In more grown up languages than BASIC, this situation is handled using structures. These can be either passed on entry (with the contents updated by the function and a simple go/fail response) or the structure can be built by the function and passed as the exit value.
True, but you can fake it by building the structure manually and passing the address to the data block. A bit of mindscrew that will be extremely familiar to anybody who’s ever written a Wimp program in BASIC. It’s doable, but it’s about as pretty as the result of a late night curry and one beer too many.
Ugh. I don’t like languages that “try to be clever”. Like PHP’s lack of typing for variables. Can lead to some interesting oddities when a variable is a number and PHP decides to interpret it as a string/number when you wanted a number/string. For example:
This can bite you in the arse if you’re trying to compare for equality and PHP figures that they’re not the same type so aren’t equal. The string “1” is not the same as the number 1, for instance. |
GavinWraith (26) 1563 posts |
+1.
+1. |
Stuart Swales (8827) 1357 posts |
That’s Peephole Optimiser 101 though.
Algol 68 had the helpful “Cannot coerce object of mode void to mode void”… |
David J. Ruck (33) 1635 posts |
There’s nothing clever about returning a |
David Boddie (1934) 222 posts |
Ahem,
|
Steve Drain (222) 1620 posts |
There’s a lot of snooty attitudes here. ;-) To return multiple values you use >f=\(x,y)=>x+y,x*y end;print (f(3,7)) 10 21 is: DEFPROCf(x,y,RETURN s,RETURN p):s=x+y:p=x*y:ENDPROC PROCf(3,7,s,p):PRINT s,p 10 21 and you also have variables with the sum and product. |
GavinWraith (26) 1563 posts |
OK, I agree, but I am definitely snooty. I suppose in theory one could avoid FN and assignment altogether and only have PROC, once you introduce a new primitive PROCassign(RETURN x, y). It would look horrid though. Why INPUT X and not X = INPUT, but K$ = GET$ and not GET K$? Lets face it, the syntax of BASIC is a horrid mess, and a burden on beginner and compiler-writer alike. Having types lends meaning to programs, and helps to avoid most errors. The trouble is that for lots of algorithms you don’t actually need to know what the type is, only how to distinguish different types. That in Pascal you need a different function to sort numbers from one to sort strings is clearly a nonsense. C’s use of pointers fits well for this situation. But the downside is that C predicates a particular memory model: consecutive chunks of memory labelled by the smallest address. Other languages try to avoid this assumption, using the idea that objects in memory have descriptors whose details are left to a specialized memory manager, not itself part of the language. A high level language (like the user) has no business mandating a particular memory model or fiddling with addresses; but then C is a low-level language. |
Rick Murray (539) 13840 posts |
Why? Numbers are regular. Numbers have predictable qualities such as 2 being a larger amount than 1. Sure, humans manage to mess this up (is 1.01 > 1? what is -1?), but these are mainly issues of interpretation…or perhaps more specifically limits of interpretation. That &FFFFFFFF is -1 is the nonsense here, but we accept it as a compromise. Strings, on the other hand, are a sequence of values that we give meaning to. And in many cases without coherent agreement to the meaning. Is your website declared as ISO 8859/1? Don’t write in Welsh because officially everybody is supposed to interpret that as a synonym for Windows CP-1252, which has subtle differences in the free-for-all middle bit. Even with Unicode, there are different types, with UTF-8 being the popular one (it works well with C), but since it is a string of bytes without an obvious marker, it’s easy to mess it up. From time to time my Amazon orders come with a gibberish address, as Amazon clearly uses UTF-8 and the vendor’s system printed this out as if it were something like the aforementioned CP-1252. Let me ask you – would you put Å before B or after Z? What would you do if it was expressed as ÃŶ? How would you sort non-Latin names? In Japanese, for example, the vowels are あ a, い i, う u, え e, and お o (and this isn’t even counting the thousands of Kanji and their multiple readings). A lot more complicated than numbers! |
Rick Murray (539) 13840 posts |
Too many years spent hacking sanity into other people’s ***tty code. Not mine, I hasten to add, my code is perfect. (well, you did mention snooty attitudes ☺) |
Steve Drain (222) 1620 posts |
It is hardly relevant now, but with BASIC and Basalt you could create structures much like C and pass them by reference. With some trickery you can do that in BASIC alone. However, I have never found a need to use those structures in anger. For instance, you can do this to fill an icon block, with no indirection in sight: P%=block% [OPT 2 & xmin% & ymin% & xmax% & ymax% & flags% = LEFT$(text$,11) = 0 ] Here’s a shortform version with values. ;-) P%=block%:[OPT 2:&100:&100:&200:&200:&&0700035:="Text":=0:] [none of this is tested, but you get the idea!) Edit: Does this count as a trick? It is in the language and documented. |
Steve Drain (222) 1620 posts |
In BASIC you use Martin Avison’s *Sort, of course, but that is ASCII for strings, Rick. ;-( |
Steve Drain (222) 1620 posts |
I have never done it before, but I just tried a combintion of OS_HeapSort and Territory_Collate, which does the trick. It is pretty simple in BASIC, but does require an assembler wrapper round Collate, AFAICT. Of course, this does rely on a working territory for the language you want to sort in. ;-) Edit: This does not work. I was seeing an artefact. ;-( ;-( |
Stuart Swales (8827) 1357 posts |
Stick a NULL on the strings ;-) |
Rick Murray (539) 13840 posts |
Oh? Seems like a pretty interesting idea to “leverage” (fx: vomit emoji) OS facilities to save having to write a sort routine. Let’s have a crack at this (updated to perform two types of sort)…
Which does this: *NameSortTest Before sorting 0000985C : April 0000986C : Emily 0000987C : Æronwen 0000988C : Jessica 0000989C : Ásfríðr 000098AC : Clíodhna 000098BC : Aubrey 000098CC : Clemence 000098DC : Clotilde 000098EC : Angela After basic string sort 000098EC : Angela 0000985C : April 000098BC : Aubrey 000098CC : Clemence 000098DC : Clotilde 000098AC : Clíodhna 0000986C : Emily 0000988C : Jessica 0000989C : Ásfríðr 0000987C : Æronwen After territory-collate sorting 000098EC : Angela 0000985C : April 0000989C : Ásfríðr 000098BC : Aubrey 0000987C : Æronwen 000098CC : Clemence 000098AC : Clíodhna 000098DC : Clotilde 0000986C : Emily 0000988C : Jessica * Okay, it didn’t quite know what to do with Æronwen, but it was a bit of a cheat using the AE ligature. Otherwise, it appears to have sorted correctly, putting Ásfríðr between April and Aubrey, and Clíodhna between Clemence and Clotilde. |
GavinWraith (26) 1563 posts |
My fault for not explaining myself clearly. A sorting algorithm has nothing to do with the type x of the elements in the array to be sorted. It takes as an argument a comparison function : a function of two arguments, a and b of type x, which returns true if a is to come before b and false otherwise. Whether x is numbers of some kind or strings or whatever does not matter to the algorithm, only to the comparison function. Box-shuffling does not care about what is in the boxes. The notion that values can be containers, an intentionally vague word, for other values is not really expressible in BASIC, but it is an important idea nonetheless. Not allowing ASCII NUL as a character in a string is a nasty limitation, asking for trouble. Now alphabetic ordering is another can of worms entirely. |
Jean-Michel BRUCK (3009) 359 posts |
Why not try C++ |
Rick Murray (539) 13840 posts |
Ah, and there’s the distinction. There are two ways that one can sort something. The first is to have a generic sort which calls out to a comparison routine as you suggest, and as used above in my BASIC example. The other way is to have a ready-built function to perform a sort according to a predetermined type of value. Interestingly, standard C only offers qsort() which takes a base address, a count of objects, their size, and a pointer to a comparison routine. So you have to “do it yourself” in C.
It has provided benefits, though. By reserving a specific character to mark the end of the string, it is possible to have strings of arbitrary length. Systems that use a single byte to hold the length (like BASIC) are limited with strings maxing out at 255 or 254 bytes (depending on whether or not the terminator is required – it shouldn’t be given an explicit length, but…). The downside is that the length of a string cannot be determined without literally walking it and counting the bytes, but since the length is essentially arbitrary 1, it is certainly preferable to the alternative. As to why null, well, perhaps because in the VT world, all of the other characters have meaning. SOH, STX, ETX, EOT, ENQ, ACK, BEL… and that’s the first seven. |
Steve Drain (222) 1620 posts |
Hmm. My code does exactly the same 1, but it is not correct, I think. You have: 660 MOV R3, #%000 ; cardinals, ignore case, ignore accents This is the default flags, taking acount of case and accents, so the sort should appear as the first HeapSort, with Æronwen at the end, I suggest. It looks as though R3=%11 is applied, whatever. That is the ‘artefact’. A lttle bit more experimenting makes me unsure that Collate is working as specified, although I am sure that I have had a version that did. I am still on RO 5.25. More work needed. 1 It is a a bit briefer and much more BASICy. ;-) |
Pages: 1 2