• Print

Author Topic: discussion: pointers to functions, and are they in the spirit of BASIC?  (Read 608 times)

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
discussion: pointers to functions, and are they in the spirit of BASIC?
« on: January 09, 2013, 12:55:26 AM »
This is a response to this topic:
http://www.qb64.net/forum/index.php?topic=10313.0

I'm not sure what the technical definition of "pointer" is, but I use it to mean a memory address, or a variable (or constant) that holds a memory address. The Wikipedia article suggests that it is the data type that is actually the pointer, the data type meant to hold an address.

Usually, pointers are pointers to data. So:

DIM x AS LONG
DIM y AS _OFFSET
x = 1
y = _OFFSET(x)

In this case, y could be called a pointer, holding the memory address of the variable x. I would also call the address itself a pointer, but I'm not sure if that is correct. I guess you could say that the _OFFSET type is a pointer type.

But memory doesn't just hold data, it holds code also. It holds functions, and functions have entry points. So:

SUB PrintSum (x AS LONG, y AS LONG)
 PRINT x + y
END SUB

That will become a function in the code. When you have:

PrintSum 5, 3

That is a function call. You see the name "PrintSum", but the resulting machine code doesn't use names. It will be a call to the memory address of the function's entry point.

So every function (except functions that are always inlined) has a specific instance in code, with an entry point.

Now, in most cases, you don't need to be concerned about addresses of functions. In the above case, I just write PrintSum, and let the compiler worry about the address. But what if I'm using a library that needs to call back to my code? Or, what if I'm using a library, but there is no way for me to know the addresses of its functions until run time?

The Windows API has both situations.

SetConsoleCtrlHandler is used to tell Windows to call one of your functions if, for example, the user clicks the "X" on your console window. (Think of it as being like the _EXIT keyword in QB64, but instead of you polling it, it calls a function for you, somewhat more like ON ... event trapping.) You must provide it with the memory address of your function's entry point.

With Component Object Model, you load a class at runtime, and then call functions of that class. Your program has no way of knowing the function entry points ahead of time. When you load the class, you get access to a "vtable", basically an array of memory addresses of functions.

The normal way (in C++) of using a DLL function is to just use the name directly. The import libraries, linker, and Windows' image loader take care of the addresses. However, what if you want to use a function if it is available, but not prevent the program from running if it isn't? For example, you might want to use the function GetConsoleProcessList from kernel32.dll. But that function is only available on Windows XP or later. If you use it directly in your code, you will cause a dependency on it that will prevent your program from even starting on Windows 2000. But if you import it at runtime, through LoadLibrary and GetProcAddress, then you can use it if it is there, but not prevent your program from running if it isn't. GetProcAddress returns the address of the function.



Did QBASIC 1.1 have pointers? Yes it did.

VARSEG returned the segment part of the address.
VARPTR and SADD returned the offset part of the address.
DEF SEG set the segment part of the address to be used in calls to PEEK, POKE, and CALL Absolute.
PEEK and POKE accessed data using the memory address.
CALL Absolute executed the function using the memory address. What was passed to CALL Absolute was a function pointer.

Here is an example:

Code: [Select]
DECLARE FUNCTION h2b$ (h AS STRING)
DIM x AS LONG
DIM t AS STRING
DIM code AS STRING * 17

t = "55" '                push bp
t = t + "89e5" '          mov bp, sp           ; set up stack frame
t = t + "1e" '            push ds
t = t + "53" '            push bx
t = t + "c55e06" '        lds bx, [bp+6]       ; read parameter as a pointer
t = t + "66ff07" '        inc dword [bx]       ; increment the variable pointed to by the parameter
t = t + "5b" '            pop bx
t = t + "1f" '            pop ds
t = t + "c9" '            leave                ; destroy stack frame
t = t + "ca0400" '        retf 4               ; return, removing 1 parameter

CLS
code = h2b$(t)
DEF SEG = VARSEG(code)
x = 5
PRINT x
CALL absolute(SEG x, VARPTR(code))
PRINT x
END

FUNCTION h2b$ (h AS STRING)
DIM i AS LONG
DIM t AS STRING
t = SPACE$(LEN(h) \ 2)
FOR i = 0 TO LEN(h) \ 2 - 1
 MID$(t, 1 + i, 1) = CHR$(VAL("&h" + MID$(h, 1 + 2 * i, 2)))
NEXT
h2b = t
END FUNCTION

code is a 17 byte fixed length string containing a function.
DEF SEG = VARSEG(code)
sets the segment for the subsequent CALL Absolute.

CALL Absolute(SEG x, VARPTR(code))

SEG x is the parameter. SEG means to use the full address.
VARPTR(code) is the address of the code string variable, which contains a function. In this case, VARPTR(code) returns a function pointer.
The address of x is pushed onto the stack, then the function pointed to by VARPTR(code) is called.

In this case, the function increments x. The equivalent BASIC function would be:

SUB IncDword (n AS LONG)    ' by ref parameter
 n = n + 1
END SUB

One major limitation of CALL Absolute is that it made no prevision for a direct return value.



QBASIC used a calling convention that pushed parameters from left to right, and had the function remove the parameters.

However, QuickBASIC 4.5 allowed the use of external __cdecl functions with the CDECL keyword with DECLARE.

On Windows, there are several calling conventions. The two main ones are __cdecl and __stdcall. Both of them push parameters from right to left. __stdcall has the function remove the parameters. __cdecl has the caller remove the parameters. Most of the C Standard Library functions as well as most of the QB64 functions are __cdecl. Most of the Windows API function, and most of the call back functions that Windows would call are __stdcall.

WINAPI and CALLBACK are macros for __stdcall.

There is also __fastcall which uses registers to the extent possible instead of the stack.

It is necessary to be able to specify whether a function is __cdecl or __stdcall. It is a bug that DECLARE DYNAMIC LIBRARY and DECLARE CUSTOMTYPE LIBRARY do not allow you to specify. See: http://www.qb64.net/forum/index.php?topic=4566.0

To be able to write useful callback functions in QB64, it should also be possible to specify whether QB64 functions will be __cdecl or __stdcall. It would also be necessary to be able to specify BYVAL parameters. Variable numbers of parameters for __cdecl functions would be nice, but I'm not aware of any callback functions that need a variable number of parameters.



Quote from: mn64 on January 08, 2013, 08:42:54 PM
i have no idea what you're talking about michael, so maybe it's fine, but whatever you do please make sure that i won't have to learn c++ to use qb64 in the future. i'm already (very mildly) concerned i'm going to have to learn gl...

i know the BASIC functions are always going to be there, but i'd hate for it to go from a basic project done with c++ to a c++ project done with basic. yep, being totally paranoid now. more like i just wanted to make the point ahead of time.

i've had pointers explained before. i always forget, because they've never done anything for me. i recall they're overused, abused and overrated. i remember being excited when i (thought i) heard how galleon was avoiding or only half-implementing them. that was years ago.

Galleon has always been pretty conservative about keeping QB64 "BASIC-like", so I don't expect that to change.

The Windows API documentation is written for C++, so learning how to use the Windows API requires at least some knowledge of C++.

I think it comes down to how powerful we want the language to be. A lot of power can be added to QB64, while still keeping a BASIC-like syntax. Is it still BASIC? I don't know.

When you give people power through new language features, it will be natural that they will start using them. Of course, some people will still program in the smaller subset, and those programs should continue to work. Other people will push into the new language features.

I think _MEM blocks are an example of this. It gives power to use pointers for data access. It's certainly not the syntax I would have preferred. A few people have already embraced _MEM, for example, SMcNeill. Others will be a bit more wary. I sill prefer my peekpoke library, because it is simpler, more BASIC-like, and requires much less typing.

I'm sure that some people are itching to use OpenGL directly in QB64, probably mostly people who already use OpenGL from C or C++. They have a head start. Others will be slower to catch on, or won't bother at all.

It is true that things like pointers can change the programming style. I think that Galleon shares this concern. See his response to http://www.network54.com/Forum/585676/message/1325553420/ . Frankly, I would like to be able to use pointers more easily in QB64. Hypothetically, you could make BASIC just as powerful, and have the same functionality as C, and even C++. At that point, syntax would be the main difference. As C++ has a much more compact syntax that requires much less typing, why not just use C++ and be done with it? Good question...

Frankly, I'm glad QB64 has some support for pointers. QB64 was not of much use to me until Galleon added _OFFSET in 0.941, and that is when I started really using it. However, you are correct that QB64 has only partial support for pointers. _MEM added a lot more support, but it is clunky. DECLARE LIBRARY allows custom code, like my peekpoke functions, and like the code I used to call Component Object Model functions. However, it is still not as easy as it is in C++.

For example, suppose that I have a data type:

TYPE t
 x AS LONG
 y AS LONG
 z AS LONG
END TYPE
DIM s AS t

Now, Let's say that I want to assign the y member to the z member using pointers. Right now, I would have to do:

DIM p AS _OFFSET
p = _OFFSET(s)
poked p + 8, peekd(p + 4) '   using peekpoke library

or:

DIM m AS _MEM
m = _MEM(s)
_MEMPUT m, m.OFFSET + 8, _MEMGET(m, m.OFFSET + 4, LONG) AS LONG

Why shouldn't I be able to do:

_MEMPUT m, m.OFFSET, _MEMGET(m, m.OFFSET, t.y) AS t.z

If so, then _MEM would have a clear advantage over peekpoke, which would not be able to do that kind of thing directly.

Contrast both the peekpoke style, and the _MEM style with C++'s brevity:

struct t {
 int x;
 int y;
 int z;
};
t s = {};
t * p = & s;
p->z = p->y;

If you want to see what Component Object Model currently looks like in QB64, see:
http://www.qb64.net/forum/index.php?topic=5613.0
Note how function pointers are handled. Unlike with QBASIC's CALL Absolute, I made the function pointer the first parameter, not the last.

In conclusion, I want to emphasize that pointers are not overrated.

At a low level, they are absolutely essential. Kind of like DO...LOOP and IF...THEN turn into something like GOTOs, every memory access, every jump, and every function call uses pointers (either absolute or relative). The higher level languages can abstract and hide it.

Even within the higher level languages, pointers are very useful for powerful, efficient code. Modern C++ tends to discourage raw pointers in favor of smart pointers, references (which actually are constrained pointers), and iterators. However, pointers are still absolutely essential for many things.

Even in BASIC, even if you aren't directly using pointers, it is still good to be aware of them. How would you explain "by reference" parameters otherwise?

Regards,
Michael

Edit: Fixed the variable name in the C++ example.
« Last Edit: January 09, 2013, 12:59:28 PM by mcalkins »
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

Johny B.

  • Sr. Member
  • ****
  • Posts: 487
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #1 on: January 09, 2013, 01:46:51 AM »
Are pointers very BASIC? Not really. Would I like a simple, full implantation of them in QB64? Yes. At the moment, I'm working on a project in C, and pointers let you do things such as linked lists and arrays of function pointers. They are most definitely not overrated.Going on from your talk on function pointers, I'd like to mention the usefulness of an array of function pointers. This means you can choose which function to call at runtime based on a number, which is an index into the array. It's the alternative to a SELECT CASE. However, it isn't very BASIC, but I certainly wouldn't mind.
"Time is an illusion; Lunchtime doubly so." - Douglas Adams

mcalkins

  • Hero Member
  • *****
  • Posts: 1269
    • qbasicmichael.com
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #2 on: January 09, 2013, 02:47:22 AM »
The vtables (virtual function tables) used by COM are arrays of function pointers.

I was looking in the wiki earlier, and saw:
http://www.qb64.net/wiki/index.php?title=ON...GOSUB
which might be slightly similar, but not as useful.

Regards,
Michael
« Last Edit: January 09, 2013, 03:18:26 AM by mcalkins »
The QBASIC Forum Community: http://www.network54.com/index/10167 Includes off-topic subforums.
QB64 Off-topic subforum: http://qb64offtopic.freeforums.org/

mn64

  • Full Member
  • ***
  • Posts: 184
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #3 on: January 09, 2013, 05:55:41 AM »
as far as i can tell michael, pointers suddenly become extremely important if you're knee-deep in oop stuff. only people that care about that seem to make a fuss over pointers. that's case 2, and it's the larger case for pointers.

since i'm not into the win api, or c++, my use for pointers in basic is roughly zero. has been for decades.

the thing i'm worried about: once they take over, people start using pointers for EVERYTHING. low-level, great... but i'm not starting up the car to go 1 block down the road, like these oop-happy coders. BASIC is a wonderful bicycle that way. it's not a car, it's definitely not a tank, but as a bicycle it's the best bicycle there is.

and of course there are libraries... so why isn't the library interface enough? serious question.

now case 1 is from dos days, when low-level really was low-level. in modern os design, going low-level when you don't need to is misbehaving. it's like saying "my software is more important than the stability of your system." sometimes it's justified, until you get these pointer-crazed evangelists talking about how vital they are.

VARPTR$ - enough said! because every single time i came across VARPTR$ (in PLAY, and more recently in DRAW in qb64) i replaced it with STR$ and that was that.

i understand STR$. i still have no idea why you'd use several VARPTR$ in a compound string macro, when each one adds an arbitrary extra 3 characters.

can you tell me why anyone would NEED VARPTR$ for PLAY or DRAW, when year after year, i've replaced it with STR$? because that's the main use of VARPTR$ i've seen.

and if y is a pointer, well then! i guess i use pointers every day. only i use them incidentally, because it's unavoidable. i don't try to make it more difficult for myself.

i'm not just being belligerent here, this one really baffles me. if the library interface to c++ code isn't sufficient, and you need pointers for that, so be it. i wish i understood. if BASIC really NEEDS pointers, for code that procedural and not object-based, (oh but y is an "object" too, so i guess we're all oop coders now...) in an age where you're not supposed to go low-level unless you must.

lastly, a stupidly unfair question: you figured out a buffer overflow using qb64. i know just enough about them that i know they're extremely difficult to be impervious to, so i'm not suggesting anything was airtight to begin with. but one of the core tenets of BASIC (the 8 rules myst and i used to talk about, which were outlined many many years ago) was that BASIC would shield the user from the operating system. that didn't stop SHELL, or assembly, but mostly if you wanted to, you could avoid those. (i've always liked SHELL a ton.)

with everyone getting pointer-happy, adding all the pointer-based features they can think of to make qb64 more c++-centric (my greatest fear) and just a little less basic each time around, (it's nowhere in the class of other non-basic-languge-centric versions of BASIC about this, on the contrary, qb64 is now the most BASIC BASIC ever) will all these new features mean that

a. there will be tons more ways to do buffer overflows and the like?

(especially) b. even by people who aren't creating them deliberately, by misunderstanding pointers and using/abusing them anyway?

and also:  (maybe most importantly)

c. will it be easier for qb64 programs in the future to disguise their real intentions, look llike harmless programs, and actually do serious harm to the user through deliberately botched pointer-based code?

in short: the more "low-level" functionality that becomes commonplace in qb64, without necessity mind you (if it's necessary, that's different i guess) the more often you will see bad code that does REALLY BAD stuff to the user? you know, like "low-level" bad stuff.

you know i come from a DOS background. but the rules for DOS are different. please, whatever low-level stuff you add to qb64, don't go crazy. prioritize. and don't make it into qb64++ or i'll never forgive you.

i'm not accusing you of anything, it's just i've seen it all before: "wouldn't it be nice if basic was actually like this other language?" *facepalm* anyone can do that, many have. keeping a language BASIC is one of the most difficult design tasks you could have. making it a hybrid with some non-basic is a common exercise in foolish and pointless destruction.

good languages borrow features from other languages, but good BASICs don't get taken over by them.

regards,

menn
« Last Edit: January 09, 2013, 06:02:16 AM by mn64 »

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #4 on: January 09, 2013, 05:59:14 AM »
BASIC, as I see it is a language, and like any language it can pick up new words and ideas as time evolves -- unless it's a DEAD language.    Compare it to ENGLISH and LATIN...

English is a living language, so we have terms in it now like computer, plasma tv, LCD monitor.  Those words didn't exist in the language a few hundred years ago -- at least I never saw them in any of the works of Shakespeare that I had to study in school.   As a living language, it's evolving, growing and expanding.

Compared to Latin, which doesn't have any of these terms in it.  Latin is a dead language, and it's stuck with the same capabilities that it's had for a thousand years.  It still has its uses, but you certainly can't use it to talk much electronics....

QB45 is a dead language.  It's not growing, expanding, or changing.  If people wants something that's confirmed constant, then stick with it.

QB64 is a living language, and as such it's going to grow, expand, and become MORE than it was before.

_MEM may not have been QB1.1 BASIC, but it IS QB64 BASIC now.  Function pointers, precompilers, and Underscore commands in general may not have been the language of BASIC back in 1960, but why can't they become part of the language now?   Just because it wasn't in the BASICs of the past, doesn't mean it's still not BASIC.

Tv, computer, microwave, car, jet....   These words and concepts were not part of the English language back when Shakespeare or Chaucer wrote, yet we still call them part of modern English.   

I say we move past the past, and let QB45 remain the dead language -- and expand ever upwards with new words, terms, and concepts with the living language that is QB64.  BASIC *is* what we say it is, and all this talk of "it wasn't like this before" is a counter-productive waste.  We've simulated the past with something like 98% compatibility with QB45.  It's now time to live and speak in the present, and prepare for the future.

As long as we don't break past compatibility, I'm all for expanding present capacity and utility.  It's why I love this project:  it's an honor and privilege to be here to help with the growth and direction of a living language.   

Just because something wasn't QB45 BASIC, doesn't mean it can't become QB64 BASIC....   

I may not have used function pointers in the past, but by golly, if it's offered I'll find a way to use them in the future.    Same with _MEM, _gl-whatever's, and all the other _underscore commands out there. 

Long LIVE QB64!!
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

mn64

  • Full Member
  • ***
  • Posts: 184
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #5 on: January 09, 2013, 06:06:45 AM »
Quote from: SMcNeill on January 09, 2013, 05:59:14 AM
BASIC, as I see it is a language, and like any language it can pick up new words and ideas as time evolves -- unless it's a DEAD language.    Compare it to ENGLISH and LATIN...

Tv, computer, microwave, car, jet....   These words and concepts were not part of the English language back when Shakespeare or Chaucer wrote, yet we still call them part of modern English.   

yeah steve, i'm all for new words and ideas. khakis, for example: that's arabic.

when michael finally suggests that english needs to start using tildes and umlauts and japanese grammar, i'm going to want to smack him in the face. and i like him a lot! (it's all hypothetical, no offense michael. i hope. p.s. michael is like twice my size and used to wrestle boars or something...)

your metaphor's got absolutely nothing to do with what i said. you posted it WAY faster than you could have gotten anything i was saying.

every ham-fisted non-basic evangelist that wants to rape BASIC immediately pulls out this "non-dead language" argument. i'm not saying the language shouldn't grow, i'm saying growth can happen thoughtfully, without cancer of the language.

and no, i know michael doesn't want to hurt BASIC. but lately he scares me a little with this stuff. i can't wait to see what oop implementation qb64 will use :|

Quote
Long LIVE QB64!!

this made me die a little. oh the memories you guys are bringing back with this...

BE CAREFUL!

i know galleon will be, but he has to deal with you people.
« Last Edit: January 09, 2013, 06:11:58 AM by mn64 »

SMcNeill

  • Hero Member
  • *****
  • Posts: 2414
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #6 on: January 09, 2013, 06:14:01 AM »
I get what you're saying.  I'm just saying just because we didn't or couldn't do something in the past is no reason to reject the growth of it now and in the future.   QB64 needs to evolve to stay competitive, and viable for future use.  I'm all for adding whatever commands Galleon thinks it needs to allow for that.

If he adds it, I'll learn to use it....   Nothing says anyone else has to though.  You're more than welcome to keep building a bicycle, but it'd be nice if QB64 could also build motorcycles as well.....

Vroom vroom! ;)
http://bit.ly/TextImage -- Library of QB64 code to manipulate text and images, as a BM library.
http://bit.ly/Color32 -- A set of color CONST for use in 32 bit mode, as a BI library.

http://bit.ly/DataToDrive - A set of routines to quickly and easily get data to and from the disk.  BI and BM files

mn64

  • Full Member
  • ***
  • Posts: 184
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #7 on: January 09, 2013, 06:27:39 AM »
Quote from: SMcNeill on January 09, 2013, 06:14:01 AM
I get what you're saying.  I'm just saying just because we didn't or couldn't do something in the past is no reason to reject the growth of it now and in the future.   
Vroom vroom! ;)

ok good. because i'm used to more derision and condescension about that, and galleon has always known better.

actually i think oop could help, but the chances are so small, because 95% of implementations aren't friendly except to oop levers. the exceptions are impressive, i still don't use them (they're optional or invisible.)

sorry about the antichrist remark. must remember, just because you see horns... i jumped the gun a little. i really appreciate you not being a jerk about this. *hattip*

Galleon

  • Administrator
  • Hero Member
  • *****
  • Posts: 4664
  • QB Forever
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #8 on: January 09, 2013, 06:27:44 AM »
I like this topic so much I stickied it.

My answer about pointers to functions is simple.
#1 It shouldn't look like C/C++, it should look BASIC
#2 It needs to be made safe. Notice how hard it is to get code using the _MEM system to crash? You really need to try very hard. That's because I didn't just add pointers to QB64, which would have been really easy, I did something far better which would allow the same sorts of operations but not crash with unproductive "GPF" messages when things go wrong.
#3 It needs to be understandable by people with little/no knowledge of 'pointers to functions'

As mentioned, there's pretty much nothing that can't be done already with a bit of DECLARE LIBRARY magic. In the libCurl program I'm writing I manage callbacks through a helper.h file.

I agree there needs to be a way to "discover" functions inside DLLs "on the fly", which is how most plugins work.
Something old... Something new... Something borrowed... Something blue...

mn64

  • Full Member
  • ***
  • Posts: 184
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #9 on: January 09, 2013, 06:38:28 AM »
Quote from: Galleon on January 09, 2013, 06:27:44 AM
#2 It needs to be made safe. Notice how hard it is to get code using the _MEM system to crash? You really need to try very hard. That's because I didn't just add pointers to QB64, which would have been really easy, I did something far better which would allow the same sorts of operations but not crash with unproductive "GPF" messages when things go wrong.
#3 It needs to be understandable by people with little/no knowledge of 'pointers to functions'

galleon, please let me know if you ever set up a p.o. box or something like that? paypal and the like won't stop me forever, but it will definitely slow me down more than the post will.

Clippy

  • Hero Member
  • *****
  • Posts: 16439
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #10 on: January 09, 2013, 07:22:51 AM »
Quote
I agree there needs to be a way to "discover" functions inside DLLs "on the fly", which is how most plugins work.

Discovering them is one thing, documenting them another. With all of the new GL functions might it not be better to just link to existing documentation? It appears that GL is nothing more than a hidden DECLARE LIBRARY procedure.

We never got all of the SDL functions working in QB64 as keywords let alone explain the overall concepts. Now we are using the function names verbatim. The difficulty will be trying to comprehend them all at once.
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

mn64

  • Full Member
  • ***
  • Posts: 184
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #11 on: January 09, 2013, 07:32:26 AM »
Quote from: Clippy on January 09, 2013, 07:22:51 AM
The difficulty will be trying to comprehend them all at once.

a task to be left to gl coders, surely. i don't worry about having to understand gl. i do worry that if it became common enough, graphics programs would be a lot more difficult to understand. then again, 3d programs are seldom easy.

Johny B.

  • Sr. Member
  • ****
  • Posts: 487
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #12 on: January 09, 2013, 08:21:28 AM »
Pointers do not always equal OOP. Personally, I'm not a big fan of C++/Java, and that is definitely not where QB64 should go. However, pointers would allow us to write (fully procedural) code that could interface with external libraries much easier. For imstance, I tried using gdbm (a database library in C) with DECLARE LIBRARY. In the end, I gave up because it was just too difficult to pass data between the two. With function pointers, you can have an array of them, and choose which one to call based on a number. An obvious application that comes to mind is a emulating a CPU (Gameboy  emulator, anyone?). Qbasic has always had pointers, but its attempts to hide the 'ugly details' only crippled their usage. I guess what I'm trying to say is that pointers are a really useful thing, and you shouldn't automatically associate them with really low level coding, or OOP.

As for the actual implementation, I envisage something like this: x = _OFFSET(a). This puts the address of a into x. The difference here is that a can be anything: a normal variable (including those with user-defined TYPEs, a function or a sub. Note that for getting the address of functions and suns, no extra syntax is needed, just the name. It does not make sense to get the address of the return value of a fumction, as it is stored in a cpu register (I think it's eax). x would be a variable of type _offset, as in the current system.

To pass this pointer to a linrary function, do exactly as you would now. Of course, you would have to use BYVAL. I don't know how to use the _mem commands, but you can pass this pointer to a _mem command, as if it was a _mem block. Note that in this case, they are smart pointers, which means they have a type and size associated with them.However, when passing to external routines, they are converted to dumb (C style) pointers. A pointer to a string will point to the string itself, not the QB64, data structure. Strings will not be NULL terminated.

To dereference a pointer in QB64, one simply does the following: y = _DEREF(x). Once again, it is a smart pointer, and QB64 will complain if y is not a compatible type. E.g: say x points to an jnteger. If y is incompatible, e.g, a string, it will result in a type mismatch error.

To use a function pointer, we simply use the pointer name as we would the original name. So, if x points to ABS(), we can do PRINT x(-3), which will print the absolute value of -3. Same idea with subs.

To use a function array, we do the following:
Code: [Select]
dim ar(1 to 5) as _offset 'declare the array
ar(1)  = _offset(f1)
ar(2)  = _offset(f2)   'and so on, where f1 and f2 are functions/subs
'...more assignments...
print ar(1)(2) 'print the return value of f1, which takes a numerical argument

I think that's all I had to say, but I'm typing this at some rediculous hour in the morning, so the whole thing may be completely screwed up. By the way, we need a better name for the derefrencing command (_DEREF).

Good night!

EDIT: Of course, dereferencing a smart pointer that doesn't point to a valid object will throw an illegal function call
"Time is an illusion; Lunchtime doubly so." - Douglas Adams

Clippy

  • Hero Member
  • *****
  • Posts: 16439
  • I LOVE π = 4 * ATN(1)    Use the QB64 WIKI >>>
    • Pete's Qbasic Site
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #13 on: January 09, 2013, 09:43:16 AM »
Personally I don't care where the information is located, I just want to be able to get it. I didn't even ask where exactly they made my car...  ;)

But I know where it is now... I hope...
QB64 WIKI: Main Page
Download Q-Basics Code Demo: Q-Basics.zip
Download QB64 BAT, IconAdder and VBS shortcuts: QB64BAT.zip
Download QB64 DLL files in a ZIP: Program64.zip

DSMan195276

  • Hero Member
  • *****
  • Posts: 1984
  • Yes
    • Email
Re: discussion: pointers to functions, and are they in the spirit of BASIC?
« Reply #14 on: January 22, 2013, 04:27:14 PM »
Personally, I think with the addition of _MEM, function pointers aren't amazingly far off as others have noted. For some usages, function pointers are huge because it allows you to specify a function to run on runtime without using it's name. I'm image most of you that posted on this page understand this from C/C++/etc. coding though.

I was thinking a syntax like this might work well while still keeping it pretty 'basic':

Code: [Select]
DIM k as _OFFSET
k = _ALIAS(function_name)
_ALIASCALL k (arg1, arg2, arg3)
'or for functions
k = _ALIASCALL(k, arg1, arg2, arg3)

I think it's a fairly simple syntax, though I'm open to changes, it's not what I'd call perfect.I had the idea of _ALIAS because there is currently an AILAS clause for DECLARE LIBRARY that allows you to map it to a new name. _ALIAS creates a function pointer to function_name and puts it in k, and then _ALIASCALL calls the sub/function to run it.

Personally I think using _OFFSET() and _DEREF() might be a bit confusing to what it's actually doing (Because if someone is only a BASIC programmer, they probably have no idea what dereferencing is.). It also creates some ambiguity between what exactly it is. function pointers and regular pointers are the same type of data, but a BASIC user probably won't know that. By having specific commands it doesn't really complicate anything but gets rid of the need to treat thing just as pointers.

AILAS I think is a fairly easy term for it, you're creating an 'ailas' to function_name and putting that in k. You don't even need to mention they're function pointers, for all intensive purposes they can act just like handles similar to an image or SND handle (They have to go in _OFFSET's, but that's a somewhat minor detail). I think, with this syntax, it also makes it hard to mistake a normal pointer for a function pointer which is good for BASIC as well as doesn't really need much run-time checking like _MEM since the IDE can check on compile-time whether or not the function-names are valid.

So any suggestions on the idea? I can already think of more then a few uses for these.

Matt
"Cast your cares on the Lord and he will sustain you; he will never let the righteous be shaken" -- Psalm 55:22
QB64 Linux Installer

  • Print