Functions within structures

From Remeis-Wiki
Jump to navigation Jump to search
functions within structures

Please note: this tutorial is a modified copy of the object-oriented programming part of the slxfig tutorial.

Fields within a structure can hold any type of a variable. In particular, if a field is a reference to a function, this function can be used to operate on the host structure. Imagine a structure defining a car with its plate and a current place:

variable acar = struct {
  plate = "GX 304-1",
  place = "Bamberg"
};

The following function takes a given car structure and sets the place to a new one:

define drive_car(car, dest) {
  vmessage("%s drives from %s to %s", car.plate, car.place, dest);
  car.place = dest;
}

slsh> drive_car(acar, "Erlangen"); GX 304-1 drives from Bamberg to Erlangen


It would be much easier, if the car-structure contains a drive-function itself. This is done by a field pointing to the previously defined function:

variable acar = struct {
  plate = "GX 304-1",
  place = "Bamberg",
  drive = &drive_car  % <-- this value is a reference (Ref_Type) to the function drive_car
};

If the function is now called directly via the structure's field

acar.drive("Erlangen");

the structure is automatically passed as first argument to the defined function.


Technical details about how this works

If a field of a structure, which is a reference to a function, is accessed, the structure itself is pushed onto the stack first. Right after that, the parameters given to the function are pushed onto the stack also. To get the passed parameters and the structure within the function, the objects have to be pulled from the stack. This can be done, e.g., by simply defining the functions parameter accordingly as done above: define drive_car(car, dest) This pulls the given parameter "dest" from the stack first (because it is pushed onto it last) and at least pulls the structure from the stack into the variable "car".

Summarized:

car.drive("Erlangen");
  --> S-Lang pushes the structure "car" onto the stack
  --> S-Lang pushes the string "Erlangen" onto the stack
  --> S-Lang calls drive_car
  --> drive_car pulls the string "Erlangen" from the stack and assignes it to "dest"
  --> drive_car pulls the structure "car" from the stack and assignes it to "car"

But be aware, that the _NARGS variable holding the passed number of arguments does not count the structure on the stack! In the above example, _NARGS = 1

This statement is not true any more, see example below (We do not now what has changed!):

private define vsm_fkt(){

  vmessage("_NARGS = %d",_NARGS);
  _print_stack();
  variable vsm, arg1, arg2;

  switch(_NARGS)
  { case 2: (vsm,arg1) = ();
    set_struct_field( vsm, "field1", arg1 );
  }
  { case 3: (vsm,arg1,arg2)=();
    set_struct_field( vsm, "field1", arg1 );
    set_struct_field( vsm, "field2", arg2 );
  }
}

define vsm_init(){
  return struct{
    field1 = 1,
    field2 = 2,
    fkt    = &vsm_fkt
  };
}

variable v = vsm_init();
v.fkt("A");
v.fkt("B","C");