[futurebasic] scripting/back engines/passing params

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : October 2000 : Group Archive : Group : All Groups

From: jonathan <jonnnathan@...>
Date: Wed, 25 Oct 2000 11:45:07 +0200
dear all

[intro: this gnome was recently awakened in a rip-van-winkle [hereafter
referred to as 'rvw'] manner from his peaceful slumbers - well peaceful to
you, there were a lot of strange folks in my dreamings but that isn't a
story for here. one of the consequences of this renaissance was musings over
old projects, and having time in the paris métro to think about things...
this means that the following will be hard on mumblings and soft on code, in
the vein of similar ramblings that i have posted over the years. executive
summary: activate the summary mode, they may be some interesting stuff in
the flotsum and jetsum.]

in the past i have posted remarks on separating projects into a backend and
a frontend and preparing for scripting, none of these came to much... i have
also mentioned techniques for returning more than one params/results from a
called function, to greater (personal) success, as well as list interest.
recently i delved into a path that should allow me (and perhaps others) to
approach both of these objectives.

why a backend/frontend approach?
although the obvious flippant reply is 'why not?' [followed of course by,
'because it's there!'], there are valid reasons for wanting to build an app
in this way:
- having the part of the app that 'does the work' being implemented as a
server, either locally or distant
- forcing yourself to pass coherent messages from a front to a back (and
hopefully, back again) allows for a simple mechanism to either 'capture
those events' (and thus allow recording) or 'send those events from
somewhere other than your front end' (and thus allow your app to be
script-driven)
So once you have a mechanism in place it is just a question of 'massaging'
apple events to your own message protocol, in order to script the
application.

for the purposes of the current (paper) project, i have defined what i want
the app to do in terms of a simple language: INIT, OPEN, SAVE, NEWn, LINK,
DUMP, COMP, ADDn...
some of these statements need no params (ie. INIT, which just prepares the
memory for what is to come), others are more complicated affairs (ie. LINK
[#REF1, #REF2, #VALUE]).
Up to now I have always treated this as a worse case situation - if the
maximum number of params to pass is, for example, 5 then i always pass 5
params, even if they are all empty.

oops. i feel you getting lost already, so i'll backtrack and include some
code to wake you up.

i create the back engine by having a FN through which all info passes, so
conceptually the FB code is divided up as follows:

EVENTLOOP & HANDLERS (deals with user input)
    ^
    |
    v
THE 'MIDDLE' FN (a bottleneck)
    ^
    |
    v
THE BACK END (deals with data)

In my head I see the app as being hourglass shaped. Ideally the back end
should not deal with anything visual, just massaging my data structures; the
front-end also has the responsability of reading those structures (no
writing though without going through the middle) and presenting the info on
screen, this is in my mind a necessary part of user input.

so the MIDDLE FN receives the commands:

CLEAR LOCAL
LOCAL FN doMiddle(theCommand%,theParam1&,theParam2&,theParam3&,theParam4&,
theParam5&)
DIM myResult%

 SELECT theCommand%
  CASE _theCommand1: myResult%= FN doSomething1(theParam1&)
  CASE _theCommand2: myResult%= FN doSomething2(theParam1&,theParam2&)
  [etc.]
 END SELECT
END FN = myResult%

[public apology: if this looks very FBIIish, this is normal, it is part of
the rwv effect.]
[an aside: I have found that it makes my code easier to read if I prefix all
info that comes from outside the function with 'the' and all local variables
get dimmed prefixed with 'my'; then at a glance i can see where anything
originated if/when things get sticky.]

Of course, usually you doesn't bother putting in such a bottleneck, you call
the 'FN doSomething1', 'FN doSomething2' functions directly as needed. but
here, if you receive your Apple Events, you can then wrap them up nicely and
send them to 'FN doMiddle' who will not be able to tell that the info that
it is receiving didn't come from the user.
Those who have seen my posts concerning 'returning results' know that it is
possible to pass quite a bit of information even in a simple '%', so this
hasn't been a blocking point up to now.

What has always struck me as wasteful was having to pass 'n' params, even if
i didn't need them. Were i programming in assembler, i would just put the
params on the stack, then the 'command' and call the function, and then when
arriving in the FN just grab the command, which would be on top and which
would inform me of how far back to roll the stack for the expected number of
params. Well FBII passed its params in that way anyway so attempting this
created a level of confusion that jiggled many a FN, and with PPC and
faster, register based params, this is a no-no anyway.

So it finally occurred to me to use a string to pass the info, this means
that my function now looks like this:

CLEAR LOCAL
LOCAL FN doMiddle( theCommand%, theString$)
DIM myResult%

 SELECT theCommand%
  CASE _theCommand1: myResult%= FN doSomething1(theString$)
  CASE _theCommand2: myResult%= FN doSomething2(theString$)
  [etc.]
 END SELECT
END FN = myResult%

So in the case of the command 'LINK' that I presented earlier, the code
calling would look like:

'...
myString$ ="1234,1254,3"
myResult% =FN doMiddle( _LINK, myString$)
'...
And it even crossed my mind that by passing the address of the string,
rather than the string itself, it would be possible to return completely
arbitrary data, in the space reserved for the string!
It is probably best to DIM the string as being 255 chars long, and use a
specific char unused in the data, to delimite the different params, as well
as the end of data, in order to be sure to have enough room to return a
really long reply (ie that the string doesn't get truncated somewhere in
space), but this seems a very slight inconvenience in comparaison to the
flexibility that this method provides.
'...
myString$ ="1234"+CHR$(9)+"1254"+CHR$(9)+"3"+CHR$(0)+SPACE$(255-12)
myResult% =FN doMiddle( _LINK, @myString$)
'...
I would also point out that using 4 letter commands allows me to create
commands and constants that have the same value:
_LINK=_"LINK"
which is a very convenient shorthand, and also provides something small
enough to fit neatly in a register!

Those of you who have also played around with Apple Events will also
recognise more than a passing similarity between this and the AE
building/passing mechanism.

In the second part (coming soon), I propose to discuss the implications of
separating frontend and backend in a MacDraw type app, to help you get the
feel for things, but first i would like you reactions on this post.

:-j