Home   Help Search Login Register  

Author Topic: Functions: some remarks and hacks  (Read 536 times)

0 Members and 1 Guest are viewing this topic.

Arrouan

  • Guest
Functions: some remarks and hacks
« on: 26 Jun 2003, 02:10:04 »
This small article will teach you how to easily embed functions
by declaring functions as String variables within a function

0. Intro
Last week i delved into the functionality of ofp functions
in order to check whether synchronization within a function was possible
with the use of so-called semaphores. Unfortunately, it was not.
I discovered, though some interesting features, concerning function syntax:

1. When to use semi colons (";")

Semi-colons are used in programming languages to delimit statements.
Statements are the smallest atomic entities within a function or method,
which hold relevant information

eg. private {_variable1, _variable2};

In ofp, however, semi-colons seem to be used in a quite different way than in
a programming language like Java:

1.1. code blocks (between curly brackets) like while ... do, if ... then ... else
structures have to be delimited by a semi-colon if you want stuff to be processsed
by your function after the code block.

eg.
while {} do {
 ...  };
hint "Stuff after a code block";


1.2. statements returning values are NOT to be ended with a semi-colon!
apparently the compiler returns the value of "the last statement" (as is stated in
the BIS documentation) make sure this statement is never delimited.
In the case it is delimited, the stuff behind the semi-colon -nothing-, will be returned,
and you will get a value that looks like a list of all possible data types ...

eg.
suppose you want to return a value from an if/else structure:

this will not work
if (_variable1 < _variable2) then {
 0; }
else {
 1;}


this will work
if (_variable1 < _variable2) then {
 0} // no semi-colon
else {
 1} // no semi-colon


1.3. My hypothesis: ofp functions work with a stack,
When a function returns, it returns the top of the function stack.
A position in the function stack is delimited by a semi-colon BUT,  in order not to have
an empty stack with a resulting stackEmpty error there is always a first
element which should not be delimited. The consequence is, when you
delimit a statement, you actually push a new statement, containing nothing
onto the stack. The stack top remains empty until you push a new statement
on it. This explains why a returning value should not be delimited ...

CONCLUSION: the semi-colon is not really a delimiter in the sense that it ends
statements: instead, it marks the beginning of a new stack position

2. Embedded functions
After having learnt these stack-related  things, I thought it had to be possible
to take advantage of this feature: in theory each subroutine (function)
has a call returning the top of a function stack (being either noting, or a value)
and each subroutine F2 is pushed on the stack of routine F1 (which I will call the
mother function).
In order to be able to call embedded functions you should have a stack structure
like this:
Top | F1b | F2 | F1a
with F1a + F1b = F1

2.1. Preprocessing files
It worked for preprocessed files. Try something like this:
preprocess a function F2 and call it from a function F1. It will work

file F2.sqf will retun the value 10
/* begin F2*/
10
/* end */

file F1.sqf will call F2 correctly

/* begin F1*/
_F2 = preprocessFile "F2.sqf";
hint format ["The embedded function F2 returns value %1",  [] call _F2];
/* end */


2.2. Declaring functions as a string variable
But here comes the most exciting part: knowing that functions are pushed on stacks,
and knowing that string variables can be declared both by hyphens ("") and curly
brackets, and knowing that you can load the contents of a file both with the commands
preprocessFile and loadFile, taking a string as an argument, you can infer that a function itself
is nothing more than a String which is processed into a stack structure.
So I tried this:

file script.sqs
;begin of a script file
_function = preprocessFile {function.sqf}
_result =
  • call _function[/i]
    hint _result

    file function.sqf
    /* begin */

    _variable1 = _this select 0;

    _method1 = {
      _variable1 = _this select 0;
      _variable1
    };

    _variable1 + [1] call _method1

    /* end */


    Explanation:
    1. I call _function from a script with argument 0 in a file script.sqs
    0 will be passed as the first _this select 0 and will be stored in the first _variable1
    2. I declare a new function, called _method1, as a String (remember that a String can be
    declared both with hyphens an dcurly brackets). I delimit this declaration (since it is an
    element of _function and it is not the return statement.
    3. The syntax of String variable _method1 is completely similar to the syntax of
    a non-embedded function: this means: delimiters for non-returning statements and
    no delimiter for returning statements.
    4. Note however that I used twice the same variables: _this select 0 and _variable1
    both in _function and in _method1. Since functions are pushed on stacks _method1
    only should have acces to its own _variable1 and _this select 0.
    5. I ran the function and to my surprise (and expectation) it worked ...

    3. Possibilities
    You now can reuse code even more efficiently: suppose you need an operation
    within a function several times. All you have to do is declare a new function as a String,
    before you use it (ofp compilation is still line-by-line) and call it when you need it ...

    4. Some remarks
    4.1. Do not use tabs to indent your code: it doesn't work
    4.2. Commenst and newlines work fine
    4.3. If enough people are interested I will re-explain this matter in an article

Rubble_Maker

  • Guest
Re:Functions: some remarks and hacks
« Reply #1 on: 29 Jun 2003, 23:14:39 »
Thanks for the good info, this is very interesting really.

Did you find out what the difference between "loadFile" and "preProcessFile" really is? Both can be used to load functions. Yet I had no luck trying to use the PreProcessFile command to work when called from an addon, but it might be my fault.

Offline Dinger

  • Contributing Member
  • **
  • where's the ultra-theoretical mega-scripting forum
Re:Functions: some remarks and hacks
« Reply #2 on: 30 Jun 2003, 02:43:16 »
our best explanation is that files loaded from an addon are already "preprocessed",m and therefore you have to loadfile.

the difference is that preprocessfile parses out /* comments and parses in #defines
.
Dinger/Cfit

Arrouan

  • Guest
Re:Functions: some remarks and hacks
« Reply #3 on: 03 Jul 2003, 20:59:23 »
A working example of al this is now available in the functions section (MoveOut) ...