Page 1 of 2 12 LastLast
Results 1 to 25 of 41

Thread: A lot About Lape..

  1. #1
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default A lot About Lape..


    Welcome to my first Lape-Tutorial to help everyone since most of the new Simba scripts will be using it anyway..


    I don't know that much so far so I'll just help out with what I know and hope that everyone understands it and can help others out.



    Default Parameters and Function overloading


    There isn't much to say here but here goes. Imagine you wanted to write a function that can have a default parameter. In other words, a parameter that the user does not HAVE to specify but they could if they wanted. You have two options.

    The first option is to overload the function as follows so that it has two separate signatures:

    Overloads:
    Simba Code:
    Procedure Meh(a, b: Integer);
    begin
      writeln('Function Meh with 2 parameters a, b. C does not exist so assume 0.');
    end;

    Procedure Meh(a, b, c: Integer); overload;
    begin
      writeln('Function Meh with 3 parameters: a, b, c. User must specify C.');
    end;

    Now if you notice, these two functions have the same name and both return nothing (void). However, they have a different signature. By that, I mean they have different parameters. Thus they are different functions. In order for the Lape interpreter to accept two functions or procedures with the same name, you must add the "overload" keyword at the end of the declaration of the function doing the overloading. It is safe to add overload for both functions but it's a waste of time. The first function is considered the base function and any function after it with the same name but different signature is called an overload function.

    To use the above functions, the user can simply do:

    Simba Code:
    begin
      Meh(1, 2);    //Calls the first function.
      Meh(1, 2, 3); //Calls the second function.
    end.

    Overloading can also be done with different types and parameters:
    Simba Code:
    Procedure Meh(a, b: Integer);
    begin
      writeln('Function Meh with 2 parameters a, b. C does not exist so assume 0.');
    end;

    Procedure Meh(a, b, c: Integer); overload;
    begin
      writeln('Function Meh with 3 parameters: a, b, c. User must specify C.');
    end;

    Procedure Meh(Area: TBox); overload;
    begin
      writeln('Function With TBox as parameter instead');
    end;

    Procedure Meh(a, b: Integer; c: TBox); overload;
    begin
      writeln('Two int paramters and 1 tbox.');
    end;


    Default Parameters:
    There are times when function overloading is more than enough, but there's no need to have two functions just to emit the last parameter. In such times, we can use something called "Default Parameters". Default parameters are different from function overloading in that you get to specify the parameter being used as default. In the previous example, we saw that the user has to enter a value for parameter C or else it'd be emitted by calling the first function which doesn't have C.
    With default parameters, you can have the best of both worlds and still specify what value C should be if the user enters nothing.

    Take the following for example:

    Simba Code:
    procedure Foo(a, b: Integer; C: Integer = 3);
    begin
      writeln(C);
    end;

    We see that Foo is a procedure that takes 3 parameters. The first two aka "a" and "b" must be entered by the user no matter what. Parameter C is special in that it is a default parameter. It is "optional". The user can either enter a value or just only enter a and b. If the user enters a value, that value is used instead of the value we put for C. If the user enters nothing, it uses the value we entered.

    Example:
    Simba Code:
    procedure Foo(a, b: Integer; C: Integer = 3);
    begin
      writeln(C);
    end;

    begin
      Foo(1, 2);    //This will print 3 because 3 is the default value and we only entered a value for a and b.
      Foo(1, 2, 9); //This will print 9 because we entered a third value and it "overrides" the default value.
    end.

    You can also have multiple default parameters:
    Simba Code:
    procedure Foo(a, b: Integer; C: Integer = 2; D: Integer = 3);
    begin
      writeln(C);
      writeln(D);
    end;

    begin
      Foo(1, 2);       //Prints 2 and 3.
      Foo(1, 2, 4);    //Prints 4 and 3.
      Foo(1, 2, 4, 9); //Prints 4 and 9. Notice that you cannot enter A, B, D. It always goes in order of A, B, C, D.
    end.

    Or all parameters optional:
    Simba Code:
    procedure Foo(a, b, c: Integer = 2);
    begin
      writeln(c);
    end;

    begin
      Foo();
      Foo(1);
      Foo(1, 2);
      Foo(1, 2, 3);
    end.

    As you can see above. If the user enters nothing, it uses the value the developer/scripter set as default. However, if the user enters a value, it will use the user's value instead. As you can see for yourselves, only one function is created and that the last parameter has priority of being optional over all other parameters before it. In other words, parameters before it has to be entered before you can enter the last one. You cannot skip inputting parameters as shown previously.


    Downsides and Abuse:
    There comes a time when users abuse and misuse default parameters in combination with function overloads. Take the following for example:

    Simba Code:
    procedure Foo(a, b: Integer; c: Integer = 2);
    begin
      writeln(c);
    end;

    procedure Foo(a, b, c: Integer); overload;
    begin
      writeln(c);
    end;

    begin
      Foo(1, 2);     //Calls first Foo.
      Foo(1, 2, 3);  //ERROR! Which one should it call?
    end.

    As shown above, the first function always has priority over all others because it is known as the "base" function. Thus the first call to foo calls the first foo function and prints 2. However, the second call to Foo produces an error. But WHY?! Here's the thing. The reason the first call succeeded is because it matched the signature the user specified in the function call.
    Thus it never had to look for an overload. However, if it finds two functions with the same name and signature, it will get confused on which one the user is talking about. For example, the First function has 3 parameters with the last being optional. The second function has 3 parameters with none being optional.

    However, the first function already covers the second one as well. Both have three of the same type of parameters and both have the same name, thus both are the same function. The error you now get is:

    Progress Report:
    Exception in Script: Don't know which overloaded method to call with params (Int32, Int32, Int32) at line 12, column 3


    Be careful when using optional parameters and overloading of a particular function. Other than that, use it to your heart's content.



    Type Extension:

    Remember in Pascal script when you had to write a function to do a certain task for you. For example, to Insert a string into another string, you'd have to call a function to do that and clog up your scripts? Well type-extension allows you to use a type as though it were a class.

    Take for example this pascal script example:
    Simba Code:
    procedure InsertIntoString(var StrToModify: String; StringToInsert: String);
    begin
      StrToModify := StrToModify + StringToInsert;
    end;

    var
      B: String;
    begin
      InsertIntoString(B, 'Hello World');
    end.


    And this Lape Example:
    Simba Code:
    Procedure String.Insert(StrToInsert: String);
    Begin
      Self := Self + StrToInsert;
    End;

    var
      B: String;
    begin
      B.Insert('Hello World');
      writeln(B);
    end.

    Notice anything cool? Pretty neat huh? Well you can do this for quite a lot of different types. You can do it for records, existing simba types like string, integer, arrays, etc.. Imagine doing Array.erase(0); and it'll erase the first index in the array.. OR
    Array.find(1); and it searches the whole array to find a value and return the index.
    Such a thing can be done as follows:

    Simba Code:
    function TIntegerArray.find(ValueToFind: Integer): Integer;
    var
      I: Integer;
    begin
      For I := 0 To High(Self) do
        if (Self[I] = ValueToFind) then
        begin
          Result := I;
          Exit;
        end;
      Result := -1;
    end;

    var
      TIA: TIntegerArray;
    begin
      TIA := [1, 2, 7, 4, 5];
      writeln(TIA.Find(7));
    end.

    As you can see, the above will search the whole TIntegerArray to find the value 7 and then prints the index at which it was found (2). Type extensions introduces object oriented programming into scripting!



    Variable Initialization:

    In most languages, we can initialize variables upon declaration. This way, we never forget what value they start with. Also, we avoid having to depend on the compiler initializing them to some default value.

    For example, most users would say that the default value for a pointer is null or nil or 0. This is NOT ALWAYS true. Sometimes, they default value of an integer or pointer is some random value or random location in memory. Thus users always give them a value before use so as to prevent problems later down the line.


    In Pascal-Script, we do the following:
    Simba Code:
    var
      I: Integer;  //Sets default value of 0 in Simba.
      Str: String; //Sets default value of '' in Simba.
    begin
      I := 2;  //Assignment within the body of the function. Overwrites the default value. Thus a value has been set twice.
      Str := 'Hello World';  //Assignment to Str within the body of the function.
      writeln(I);
      writeln(Str);
    end.

    Lape introduces variable initialization as shown in the following example:
    Simba Code:
    var
      I: Integer = 2; //Integer.
      Str: String = 'Hello World';  //String.
      TIA: TIntegerArray = [1, 2, 3, 4];  //Dynamic Array.
      TIA2: array[0..4] of integer = [1, 2, 3, 4, 5]; //Constant Array.
    begin
      writeln(I);     //Prints 2.
      writeln(Str);   //Prints Hello World.
      writeln(TIA);   //Prints 1, 2, 3, 4.
      writeln(TIA2);  //Prints 1, 2, 3, 4, 5.
    end.

    As you can see above, the pascal version is longer and does assignment twice. However, the Lape version does an assignment to I only once (at least I think so due to this being the nature of C++ class initialization). I also have a firm belief that it only assigns once since it assigns at compile time. However, there is no need to do an assignment within the body of the function and the variable can be used immediately.

    There is one thing to note about variable initialization. Only constant expressions are allowed. For example, you cannot do:
    Simba Code:
    var
      I: Integer = BitmapFromString(512, 512, '');
    begin
      writeln(I);
    end.

    It simply will not compile because BitmapFromString is a function call and variable initialization is done at compile time whereas BitmapFromString is a run-time function. Lape also does not evaluate or have constexpr functions as C++ does and thus this is not possible.



    Records and Inheritance:

    Imagine you have an object in the real world such as a "Vehicle". Now we all know there can be many types of vehicles. Examples: Cars, Trucks, Motorcycles, Bikes, etc.. They are all a form of transportation and they all share some characteristics in common.
    For example, all of the above listed vehicles may shared "wheels" because they all have wheels and they all have a "name". They may or may not have "doors".

    These things listed in quotes are all known as properties. Wheels, Names, Doors are all properties of a vehicle.
    To represent such a hierarchy in any programming language, we introduce something known as inheritance. All sub-classes known better as "children" share the same properties as their parent category "vehicle".

    Such a hierarchy may be represented as follows:
    Simba Code:
    type Vehicle = record
      Name: String;
      Wheels: Integer;
      Doors: Integer;
      Seats: Integer;
    end;

    type Car = record(Vehicle)
      Automatic: Boolean;
      MaxSpeed: Integer;
    end;

    type Truck = record(Vehicle)
      OffRoad: Boolean;
      FourWheelDrive: Boolean;
      MaxSpeed: Integer;
    end;

    var
      V: Vehicle = ['Vehicle', 4, 2, 4];
      C: Car = ['Car', 4, 2, 4, true, 700];
      T: Truck = ['Truck', 4, 2, 4, true, true, 400];
    begin
      writeln(V);
      writeln(C);
      writeln(T);
    end;

    When you print the above, it prints:
    Progress Report:
    {NAME = Vehicle, WHEELS = 4, DOORS = 2, SEATS = 4}
    {NAME = Car, WHEELS = 4, DOORS = 2, SEATS = 4, AUTOMATIC = True, MAXSPEED = 700}
    {NAME = Truck, WHEELS = 4, DOORS = 2, SEATS = 4, OFFROAD = True, FOURWHEELDRIVE = True, MAXSPEED = 400}


    As you can see, Vehicle is the parent class. It is at the top of the hierarchy. The Car and Truck as "Types Of" vehicles.

    Relationships:
    To be more clear, we call these relationships. Vehicle is the parent and Car and Truck are the children. Brother and Sister where the Vehicle is Mother.
    In programming terms, we call this relationship the "Is-A" relationship.
    Take the following for example:

    Simba Code:
    type Vehicle = record
      Name: String;        //Vehicle "Has-A" name.
      Wheels: Integer;     //Vehicle "Has" wheels.
      Doors: Integer;      //Vehicle "Has" doors.
      Seats: Integer;      //Vehicle "Has" Seats.
    end;

    type Car = record(Vehicle)  //Car "Is-A" vehicle. Thus a car has everything vehicle has + more.
      Automatic: Boolean;       //Car "Has" automatic or manual mode.
      MaxSpeed: Integer;        //Car "Has" max speed.
    end;

    type Truck = record(Vehicle) //Truck "Is-A" vehicle. Thus a truck has everything a vehicle has + more.
      OffRoad: Boolean;          //Truck "Has" offroad type.
      FourWheelDrive: Boolean;   //Truck "Has" four-wheel drive.
      MaxSpeed: Integer;         //Truck "Has" Max Speed.
    end;

    var
      V: Vehicle = ['Vehicle', 4, 2, 4];  //Initialize Vehicle if we wanted to.
      C: Car = ['Car', 4, 2, 4, true, 700];  //When initializing Car, we must initialize all its parent properties too.
      T: Truck = ['Truck', 4, 2, 4, true, true, 400]; //Initializing truck is the same as initializing car. All parent properties too.
    begin
      writeln(V);
      writeln(C);
      writeln(T);
    end;


    As you can see, a truck and a car "Is-A" vehicle but they both "Has/Has-A" their properties.
    A truck and a car "Is" both vehicle but a car is NOT a truck. They only share their parent properties!
    Those are the only two types of relationships when it comes to inheritance. As explained in the comments, since a car has everything a vehicle has, you must thus initialize all the parent properties of the car structure when declaring it.

    It can also be written like:
    Simba Code:
    var
      V: Vehicle;
      C: Car;
      T: Truck;
    begin
      //Assign to each 'member' of the vehicle structure. Vehicle structure is know as the 'Base' class.
      V.Name := 'Vehicle';
      V.Doors := 4;
      V.Seats := 2;
      V.Wheels := 4;

      //Assign to each 'member' of the car structure. Car structure is known as the 'Derived' class.
      C.Name := 'Car';  //member is inherited from the vehicle parent structure.
      C.Doors := 2;     //member is inherited from the vehicle parent structure.
      C.Seats := 4;     //member is inherited from the vehicle parent structure.
      C.Wheels := 4;    //member is inherited from the vehicle parent structure.
      C.Automatic := true;
      C.MaxSpeed := 700;

      //Assign to each 'member' of the truck structure using short-hand assignment. Truck structure is known as the 'Derived' class.
      T := ['Truck', 4, 2, 4, true, true, 400];

      writeln(V);
      writeln(C);
      writeln(T);
    end;



    Pointers, Addresses, References, Bytes:


    References:
    How many of you remember using the "var" keyword in Pascal-Script to modify a variable passed to a function?
    Under the hood, the var keyword really says "Pass-By-Reference" this variable such that the function can modify it.

    Example:
    Simba Code:
    Procedure ModifyInt(var I: Integer);   //Pass I by reference..
    begin
      I := 10;  //Modifies the value of I so that I is now 10. Anything that happens to I, affects the parameter I.
    end;

    Procedure FailModifyInt(I: Integer);  //Pass I by value..
    Begin
      I := 15; //Only modifies a copy of I. Thus changes to the parameter I never happen outside this function.
    End;

    var
      I: Integer = 5;
    begin
      writeln(I);         //prints 5.
      ModifyInt(I);       //Changes value of I.
      writeln(I);         //Prints 10.
      FailModifyInt(I);   //Failure..
      writeln(I);         //Still Prints 10.
    end.

    As you can see, I was passed by reference to the first function and thus it was modified. However, the second function passes it by value and only modifies a copy of I. So how does this var keyword really operate.

    Var is a keyword that says, pass the address of this variable to the function such that any modifications the function does, affects the data at that address. Since variable I is at that address, any changes at that address, changes the value of I.
    Here's the thing though, a REFERENCE can NEVER be NULL. In other words, a reference must be a variable!

    Thus the following is invalid code:
    Simba Code:
    Procedure ModifyInt(var I: Integer);   //Pass I by reference..
    begin
      I := 10;  //Modifies the value of I so that I is now 10. Anything that happens to I, affects the parameter I.
    end;

    var
      I: Integer = 5;
    begin
      ModifyInt(0);  //ERROR! 0 is not a variable! The address of "0" does not exist.
      ModifyInt(I);  //Give the function the address of variable I. Aka the location of variable I in memory.
    end.

    Now we know that var is used to declare variables and to pass variables by reference to a function, let us check out the next operator.



    Address-Of:
    The Address-Of operator aka the @ sign, gets the address of a variable or member of a structure or even the address of a function. So far, in pascal-script, we've used it to only get the address of functions so that we can a function to another function such as shown below:

    Simba Code:
    Procedure Caller(Callee: Procedure(Number: Integer));
    begin
      Callee(416); //Call the Callee function.
    end;

    Procedure CallMeMaybe(Number: Integer);
    Begin
      writeln('Calling Carlie Rae-Jepsen: ' + ToStr(Number));
    End;

    begin
      Caller(@CallMeMaybe); //Pass the address of "CallMeMaybe" to "Caller"
    end.

    However, this is not the only use of the address-of operator (@). You can also grab the address of a variable as shown below:
    Simba Code:
    var
      I: Integer;
    begin
      I := 1502525235;
      writeln(@I);     //Prints:  "I"::0x7D58700 (1502525235)
    end.

    As you can see above, "I" was located at the memory address represented in hexadecimal-->(0x7D58700). The value at that address is the value of I-->(1502525235). Thus, if we modify what is at that address, we will change the value of I. To do this, read on to the next section.


    Pointers to Types and Dereferencing:

    To create a pointer to a variable, we first need to get the address of the variable. We then assign the address of that variable to some pointer. What is a pointer you ask? A pointer is a variable which holds the address/memory location of another variable, structure or type. Do you see the irony there? Since a pointer is a variable as well, we can have pointers to pointers and pointers to pointers to pointers and so on..

    However, we'll leave that for another time and move on. To declare a pointer to a type, we use the following syntax:
    Simba Code:
    type PInt = ^Integer;  //we declare a type call PInt. It is a pointer to an integer.

    var
      I, J: Integer;
      Ptr: PInt;      //A variable called Ptr which is a pointer to an int.
      Ptr2: ^Integer; //A variable called Ptr2 which is a pointer to an int as well.
    begin
      Ptr := @I;     //Ptr now holds the address of I.
      Ptr2 := @J;    //Ptr2 now holds the address of J.
      writeln(Ptr);  //prints: "I"::0x7F601C0 (0).
      writeln(@I);   //prints the same as above :D

      writeln(Ptr2); //prints: "J"::0x7F601E0 (0).
      writeln(@J);   //prints the same as above.
    end.

    As you can see above, the pointers can only hold the address of some variable, function, or structure. We use the address-of operator to get such information. Now you may notice that we have used the ^ operator followed by some data-type to declare a pointer of such type.

    Example:
    Simba Code:
    ^Byte;    //Pointer to a byte.
    ^Integer; //Pointer to an int.
    ^Single;  //Pointer to a floating point type. Aka same as ^Extended.
    ^Vehicle; //Pointer to a vehicle structure.
    ^Car;     //Pointer to a car structure.

    So on and so forth.
    Now how do we get the value of what is being pointed at? In other words, how can we get the value stored at the address the pointer is holding? Well, the weird thing is.. It's the same operator. Take a look at the following:

    Simba Code:
    var
      I: Integer = 150;
      J: Integer = 200;
      Ptr: ^Integer;  //^ followed by Type. Thus pointer to integer.
    begin
      Ptr := @I;    //Ptr now holds the address of I.
      J := Ptr^;    //Pointer followed by ^.

      writeln(J); //Prints the value of I. Prints 150 instead of 250.
    end.

    Notices that to get the value the pointer points at, we do "Pointer^" and to declare a pointer we do "^Pointer". Yes. I know it looks similar but keep this in mind all the time! "Pointer^" means to dereference and get the value of it. Whereas "^Pointer" means to declare a pointer of some type.
    Here is a little exercise. Try and figure out how the following works without running it. Then run it and see if it you got it right.

    Test:
    Simba Code:
    type
      PInt = ^Integer;
      PPInt = ^PInt;

    var
      I, J: Integer;
      Ptr: PInt;
      Ptr2: PPint;

    begin
      I := 700;
      J := 5000;

      Ptr := @I;
      Ptr^ := 300;
      Ptr := @J;
      Ptr2 := @Ptr;
      Ptr2^^ := 100;

      writeln(I);  //What is the value of I?
      writeln(J);  //What is the value of J?
    end;



    Pointers, Arrays, Bytes:

    Now if you are comfortable with pointers and modifying variables using them, it is time to learn how a pointer and an array work together to achieve specific tasks such as modifying an array or swapping the values of an array, etc..

    The first task is to understand how pointers operate and their different variable sizes. A pointer on 32-bit operating systems are always 4 bytes in size and on 64-bit systems, they are 8-bytes in size. A byte is the smallest usable amount of memory that a computer has.

    Progress Report:
    4 bits = 1 byte.
    1 byte = 1 char.
    2 bytes = 1 word/short-int.
    4 bytes = 1 integer/double-word/dword.
    8 bytes = 1 int64/long-int/qword.


    Yes that's right. Every integer is 4-bytes long and every character is 1-byte.

    Now why should we know this? Well, when doing pointer arithmetic such as iterating a pointer (moving it to the next memory address), we need to know how much to increase it to get to the next desirable cell.

    For example, see the following:
    Simba Code:
    var
      Ptr: ^Char;
      I: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1, 2, 3, 4, 5];
      Ptr := @TIA;

      For I := 0 To High(TIA) do
      begin
        writeln(Ptr^);  //What do you think it prints?
        Inc(Ptr);
      end;
    end;

    See we just assigned a pointer of "char" type to an array of integers. An integer is 4 bytes in size but a char is 1. Thus we are only printing the first byte in each integer. The above will print some random garbage to your screen. It isn't random at all because I know how the assembly registers works but for now, lets just leave it as "random garbage". In order to print all the values in the array, we must use a 4-byte pointer or increase the pointer by 4 every loop.

    So lets try creating a pointer to an int then as follows:
    Simba Code:
    type PInt = ^Integer;

    var
      Ptr: PInt;
      I, J: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1, 2, 3, 4, 5];
      Ptr := @TIA;

      For I := 0 To High(TIA) do
      begin
        writeln(Ptr^);  //What do you think it prints?
        Inc(Ptr);
      end;
    end;

    Now what does it print? It of course, prints the values of the array. But why? Well the reason it now prints the value of the array is because Inc(Ptr) increases the Pointer by 1. Since the pointer is an int pointer, it has really increased by 4 bytes.

    Thus the above is the same as using a char pointer like so:

    Simba Code:
    type PInt = ^Integer;

    var
      Ptr: PChar;
      I, J: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1, 2, 3, 4, 5];
      Ptr := @TIA;

      For I := 0 To High(TIA) do
      begin
        writeln(PInt(Ptr)^);  //Cast our Char Pointer to an Int Pointer and dereference it. Aka get the value it points at.
        Ptr := Ptr + 4;       //Increase the char pointer by 4 bytes.
      end;
    end;



    Size-Of with Pointers; RawPointers:


    Now let us say that you aren't sure what architecture the user is using.. In other words, you're not sure whether they are using x32 or x64 bit operating systems. Then how do you know whether to increase the pointer by 4 bytes or by 8? Well, introducing the sizeof operator/macro:

    Simba Code:
    type PInt = ^Integer;

    var
      Ptr: PChar;
      I, J: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1, 2, 3, 4, 5];
      Ptr := @TIA;   //Can point to an integer-array.

      For I := 0 To High(TIA) do
      begin
        writeln(PInt(Ptr)^);
        Ptr := Ptr + sizeof(Integer);  //Increase the pointer by the sizeof(integer) in bytes.. An Integer is 4 bytes so sizeof(Integer) is 4.
      end;
    end;

    As you can see above, using sizeof(DataType) is much safer to figure out how much to increase the pointer by. The above will still print all the values in the array and at the same time introduces pointer-safety. If you ever forget what the size of any data-type is, you can do:

    Simba Code:
    writeln(sizeof(DataTypeHere)); //prints the size of a data-type in bytes.

    Now what is a raw-pointer? A raw pointer is a pointer that has no size or type. Wtf? How? Well, in C++, this is known as a void pointer. It is not 4 byte, not 2 bytes, not 8, nothing.. To get the value of a raw pointer, you need to cast it to a pointer with a specific type. To declare a raw-pointer, we do the following:

    Simba Code:
    var
      I: Integer;
      Ptr: Pointer;  //Declares a raw pointer ;)
      TIA: array[0..5] of integer;
      TCA: array[0..5] of char;
    begin
      TIA := [1, 2, 3, 4, 5, 6];
      TCA := ['a', 'b', 'c', 'd', 'e', 'f'];
      Ptr := @TIA;

      For I := 0 To High(TIA) do
      begin
        writeln(Integer(Ptr^));        //Cast our raw-pointer to an integer pointer and get the value at that address and print it.
        Ptr := Ptr + sizeof(Integer);  //we are iterating an integer array. So we increase our raw pointer by sizeof(Integer);
      end;


      Ptr := @TCA;  //Notice that the raw-pointer can point to any data-type.

      For I := 0 To High(TCA) do
      begin
        writeln(char(Ptr^));        //Cast our raw-pointer to an char pointer and get the value at that address and print it.
        Ptr := Ptr + sizeof(char);  //we are iterating a char array. So we increase our raw pointer by sizeof(char);
      end;
    end;



    Pointers to structures and arithmetic:

    Pointers to structures utilize the sizeof operator/macro and pointer-data size quite a lot. See the following on how to print the entire struct below:
    Simba Code:
    type Struct = record
      X: Integer;
      Y: Word;
      Z: Integer;
    end;


    var
      Ptr: Pointer;
      S: Struct = [100, 500, 255];
    begin
      Ptr := @S;

      writeln(Integer(Ptr^));   //Print S.X;
      Ptr := Ptr + sizeof(Integer); //Move onto the next data member.

      writeln(Word(Ptr^));     //Print S.Y;
      Ptr := Ptr + sizeof(Word);  //Move onto the next data member.

      writeln(Integer(Ptr^));  //Print S.Z;
      Ptr := Ptr + sizeof(Integer);  //Not needed because we already printed the last member.
    end;

    Notice that we have declared a pointer to the Struct. The pointer holds the address of S. To print the values of S, we move the pointer to the memory location of each data member and then print it. But this is quite tedious isn't it?

    Well here is another pointer arithmetic trick. Not only can we add pointers and sizes, we can also subtract, multiply, and divide them. We can also use member offsets. For example:

    Let us assume that S is located at 0. If that is true, then S.X is located at 0 bytes from S's address. S.Y is located at 4 from S's address and S.Z is located at 6 bytes from S's address.

    Simba Code:
    type Struct = record
      X: Integer;  //0 bytes away from Struct.
      Y: Word;     //4 bytes away from Struct; aka sizeof(X).
      Z: Integer;  //6 bytes away from Struct; aka sizeof(X) + sizeof(Y).
    end;


    var
      Ptr: Pointer;
      S: Struct = [100, 500, 255];
    begin
      Ptr := @S;

      writeln(Integer(Ptr^));  //Prints S.X
      writeln(Word((Ptr + 4)^)); //Prints S.Y
      writeln(Integer((Ptr + 6)^)); //Prints S.Z
    end;


    Another example of pointer arithmetic is the following:
    Simba Code:
    type Struct = record
      X: Integer;
      Y: Word;
      Z: Integer;
    end;


    var
      Ptr: Pointer;
      SA: array[0..3] of Struct;
      I: Integer;
    begin
      SA[0] := [100, 200, 300];
      SA[1] := [400, 500, 600];
      SA[2] := [700, 800, 900];
      SA[3] := [1000, 1100, 1200];

      Ptr := @SA;

      For I := 0 To High(SA) do
      begin
        writeln('SA[' + ToStr(I) + ']: ');
        writeln(Integer(Ptr^));
        writeln(Word((Ptr + 4)^));
        writeln(Integer((Ptr + 6)^));
        writeln('');
        Ptr := Ptr + sizeof(Struct);  //increment by the sizeof(Struct) aka.. sizeof(Integer) + sizeof(Word) + sizeof(Integer).. aka 10.
      end;
    end;

    Now lets say you wanted to print only every 3rd value in the following, you'd do:
    Simba Code:
    var
      TIA: Array[0..23] of integer;
      I: Integer;
      Ptr: Pointer;
    begin
      TIA := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];
      Ptr := @TIA;

      while (Ptr < @TIA[23]) do
      begin
        writeln(Integer(Ptr^));
        Ptr := Ptr + sizeof(Integer) * 3;
      end;
    end;


    Simulating Polymorphism:

    Polymorphism is the concept of having values of different types use a single data-type/interface for handling. Confused? Well remember the vehicle, car, truck example previously shown? If we wanted to create an array of all types of vehicles, how could we do such a thing?

    The following code will give you errors:
    Simba Code:
    type Vehicle = record
      Name: String;
      Wheels: Integer;
      Doors: Integer;
      Seats: Integer;
    end;

    type Car = record(Vehicle)
      Automatic: Boolean;
      MaxSpeed: Integer;
    end;

    type Truck = record(Vehicle)
      OffRoad: Boolean;
      FourWheelDrive: Boolean;
      MaxSpeed: Integer;
    end;

    type
      PVehicle = ^Vehicle;

    var
      V: Vehicle = ['Vehicle', 4, 2, 4];
      C: Car = ['Car', 4, 2, 4, true, 700];
      T: Truck = ['Truck', 4, 2, 4, true, true, 400];

      VA: Array[0..2] of Vehicle;
    begin
      VA[0] := C;  //Even though a car is a vehicle, we cannot assign it to a vehicle array. This would introduce a problem known as "slicing". Lape stops this by not allowing you to do it.
      VA[1] := T;  //Same thing here.
    end;

    So how can we create an array that can hold ALL types of vehicles? The answer is polymorphism through pointers. Since Car and Truck are both "Vehicles" and are children of the vehicle structure, we can create a pointer to both a car and a truck and store it in an array of vehicle:

    The following code is 100% valid and polymorphic (closest to at least):
    Simba Code:
    type Vehicle = record
      Name: String;
      Wheels: Integer;
      Doors: Integer;
      Seats: Integer;
    end;

    type Car = record(Vehicle)
      Automatic: Boolean;
      MaxSpeed: Integer;
    end;

    type Truck = record(Vehicle)
      OffRoad: Boolean;
      FourWheelDrive: Boolean;
      MaxSpeed: Integer;
    end;

    type
      PVehicle = ^Vehicle;

    var
      V: Vehicle = ['Vehicle', 4, 2, 4];
      C: Car = ['Car', 4, 2, 4, true, 700];
      T: Truck = ['Truck', 4, 2, 4, true, true, 400];

      VA: Array[0..2] of PVehicle;
      PV, PV2: PVehicle;
    begin
      VA[0] := @C;
      VA[1] := @T;
      PV := @C;
      PV2 := @T;
     
      writeln(PV^);
      writeln(PV2^);
      writeln(VA[0]^);
      writeln(VA[1]^);
    end;

    As you can see, we just created an array of Pointers to Vehicle type. Since all pointers are the same size (4 bytes on x32 and 8 bytes on x64), we can simply store the address of each vehicle type into any pointer. This is known as a polymorphic array. An array of parent holding pointers to children. You can also see that a pointer to the vehicle type can hold the address of a child type. Thus we can now print out that array and it'll print all the children. Useful for holding an array of "anything" or array of children basically. This can be done with all data-types. Polymorphism has many uses and is a very powerful tool! Unfortunately Lape does not have "typeof" to tell which type a pointer is.. But that is ok we can still use polymorphism simulation and many pointer features.

    Cool huh?
    Last edited by Brandon; 07-26-2013 at 04:56 PM.
    I am Ggzz..
    Hackintosher

  2. #2
    Join Date
    Dec 2007
    Posts
    2,112
    Mentioned
    71 Post(s)
    Quoted
    580 Post(s)

    Default

    So sexy, will read when I get home, was actually in dire need of a lape tutorial

  3. #3
    Join Date
    May 2007
    Location
    England
    Posts
    4,140
    Mentioned
    11 Post(s)
    Quoted
    266 Post(s)

    Default

    Love it. Awesome tut Brandon, very well written and very informative. More rep for you.
    <3

    Quote Originally Posted by Eminem
    I don't care if you're black, white, straight, bisexual, gay, lesbian, short, tall, fat, skinny, rich or poor. If you're nice to me, I'll be nice to you. Simple as that.

  4. #4
    Join Date
    Sep 2010
    Posts
    5,762
    Mentioned
    136 Post(s)
    Quoted
    2739 Post(s)

    Default

    Thanks, but a question about the records, so your saying I could do like a record like a user can add as many custom objects as they want like:

    Simba Code:
    customObject[0].color
    customObject[0].hue
    customObject[0].sat
    customObject[0].tol
    customObject[0].width
    customObject[0].Height

    customObject[1].color
    customObject[1].hue
    customObject[1].sat
    customObject[1].tol
    customObject[1].width
    customObject[1].Height

  5. #5
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by Officer Barbrady View Post
    Thanks, but a question about the records, so your saying I could do like a record like a user can add as many custom objects as they want like:

    Simba Code:
    customObject[0].color
    customObject[0].hue
    customObject[0].sat
    customObject[0].tol
    customObject[0].width
    customObject[0].Height

    customObject[1].color
    customObject[1].hue
    customObject[1].sat
    customObject[1].tol
    customObject[1].width
    customObject[1].Height
    Yes. The above code you have there is an array of records
    I am Ggzz..
    Hackintosher

  6. #6
    Join Date
    Jun 2008
    Location
    United States
    Posts
    818
    Mentioned
    60 Post(s)
    Quoted
    90 Post(s)

    Default

    Quote Originally Posted by Officer Barbrady View Post
    Thanks, but a question about the records, so your saying I could do like a record like a user can add as many custom objects as they want like:
    -snip-
    You could do this with PascalScript as well, i.e. this isn't a feature brought around by Lape.
    [10/14/13:19:03] <BenLand100> this is special relatively, just cleverly disguised with yachts

  7. #7
    Join Date
    May 2012
    Location
    Wisconsin, USA
    Posts
    105
    Mentioned
    1 Post(s)
    Quoted
    47 Post(s)

    Default

    In truth @Brandon, one of the hardest things I find to deal with in PascalScript is the lack of these features that are usable in nearly every other scripting and programming language I know. So, my question is: How do I write a script using Lape rather than PS? Is there an example of how to set one up?

  8. #8
    Join Date
    Feb 2012
    Location
    Wonderland
    Posts
    1,988
    Mentioned
    41 Post(s)
    Quoted
    272 Post(s)

    Default

    First off, thank you very much for the tutorial on some Lape features; very valuable for those entering the lape side of scripts.

    Also, I'm pleased to better understand the syntax as you've illustrated above too! For instance, I didn't know about the records inheritance feature (i.e. using parenthesis to inherit from a parent type, as well as declaring a variable and initializing it with data members in the order they appear [ex. str, int, etc.]) until after reading this tutorial.

    A follow up question I have is: Are records able to be declared in a local function or must that be kept to the global level?

    As always, I am very thankful to your contributions @Brandon, and always seem to learn new things from you!

    Cheers as Always,
    Le Jingle!

  9. #9
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by loragnor View Post
    In truth @Brandon, one of the hardest things I find to deal with in PascalScript is the lack of these features that are usable in nearly every other scripting and programming language I know. So, my question is: How do I write a script using Lape rather than PS? Is there an example of how to set one up?

    Open Simba, open the "script" menu at the top and choose interpreter. Select Lape. Simba 1.0 might be needed for some of these features.



    Quote Originally Posted by Le Jingle View Post
    First off, thank you very much for the tutorial on some Lape features; very valuable for those entering the lape side of scripts.

    Also, I'm pleased to better understand the syntax as you've illustrated above too! For instance, I didn't know about the records inheritance feature (i.e. using parenthesis to inherit from a parent type, as well as declaring a variable and initializing it with data members in the order they appear [ex. str, int, etc.]) until after reading this tutorial.

    A follow up question I have is: Are records able to be declared in a local function or must that be kept to the global level?

    As always, I am very thankful to your contributions @Brandon, and always seem to learn new things from you!

    Cheers as Always,
    Le Jingle!

    There are limits to it such as global scope of records:
    Simba Code:
    type G = record  //valid.
      M: Integer;
    end;

    procedure Foo;
    begin
      type F = record  //invalid.
        M: Integer;
      end;
    end;
    I am Ggzz..
    Hackintosher

  10. #10
    Join Date
    Feb 2006
    Location
    Helsinki, Finland
    Posts
    1,395
    Mentioned
    30 Post(s)
    Quoted
    107 Post(s)

    Default

    @Brandon, sir, you are awesome.
    Really useful tutorial - especially for the future of Simba!

    Nice work, I really wish I could hand over some reputation points to you now...

    -Jani

  11. #11
    Join Date
    Sep 2006
    Posts
    6,089
    Mentioned
    77 Post(s)
    Quoted
    43 Post(s)

    Default

    Looking good!

    A few things:

    Simba Code:
    var
      I: Integer := BitmapFromString(512, 512, ''); //use := instead of = for delayed initialization
    begin
      writeln(I);
    end.
    Use := for delayed initialization. The variable will now be initialized at the start of the script.

    Simba Code:
    procedure Foo(a, b, c: Integer = 2);
    begin
      writeln(c);
    end;

    begin
      Foo();
      Foo(1);
      Foo(1, 2);
      Foo(1, 2, 3);
      Foo(1, , 3); //Empty second parameter
    end.
    Leave a parameter empty if you want to use the default value. This also works for record initialization.

    Simba Code:
    type PInt = ^Integer;

    var
      Ptr: PInt;
      I, J: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1..5]; //Fancy array initialization
      Ptr := @TIA;

      //Access pointer as array
      For I := 0 To High(TIA) do
        writeln(Ptr[i]^);

      //No need for i if you do not use it
      For 0 To High(TIA) do
      begin
        writeln(Ptr^);
        Inc(Ptr);
      end;  
    end;
    Pointers can be accessed as arrays too and for-loops do not need a variable.

    Very useful though, I hope this helps a lot of people!
    Last edited by nielsie95; 07-27-2013 at 12:39 PM.
    Hup Holland Hup!

  12. #12
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by nielsie95 View Post
    Looking good!

    A few things:

    Simba Code:
    var
      I: Integer := BitmapFromString(512, 512, ''); //use := instead of = for delayed initialization
    begin
      writeln(I);
    end.
    Use := for delayed initialization. The variable will now be initialized at the start of the script.

    Simba Code:
    procedure Foo(a, b, c: Integer = 2);
    begin
      writeln(c);
    end;

    begin
      Foo();
      Foo(1);
      Foo(1, 2);
      Foo(1, 2, 3);
      Foo(1, , 3); //Empty second parameter
    end.
    Leave a parameter empty if you want to use the default value. This also works for record initialization.

    Simba Code:
    type PInt = ^Integer;

    var
      Ptr: PInt;
      I, J: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1..5]; //Fancy array initialization
      Ptr := @TIA;

      //Access pointer as array
      For I := 0 To High(TIA) do
        writeln(Ptr[i]^);

      //No need for i if you do not use it
      For 0 To High(TIA) do
      begin
        writeln(Ptr^);
        Inc(Ptr);
      end;  
    end;
    Pointers can be accessed as arrays too and for-loops do not need a variable.

    Very useful though, I hope this helps a lot of people!
    Ahh! Ill add these to the op when I get home. I knew about the for loop not needing a variable but I thought that was a glitch :S so I left it out lol.
    Didn't know you could skip parameters either so that it uses the default or that it had delayed initialization. Ill add these with explanations.

    Thanx!
    I am Ggzz..
    Hackintosher

  13. #13
    Join Date
    Aug 2007
    Location
    Colorado
    Posts
    7,421
    Mentioned
    268 Post(s)
    Quoted
    1442 Post(s)

    Default

    This is a really great tutorial and essential for the upcoming release of SRL-6. I'm still very unfamiliar with Lape so when I need to start getting the feel of it this is the first place I'll be looking for answers. Thanks a million Brandon!

    Current projects:
    [ AeroGuardians (GotR minigame), Motherlode Miner, Blast furnace ]

    "I won't fall in your gravity. Open your eyes,
    you're the Earth and I'm the sky..."


  14. #14
    Join Date
    Nov 2011
    Posts
    1,268
    Mentioned
    17 Post(s)
    Quoted
    217 Post(s)

    Default

    Why doesn't StrToInt work on Lape?

    Exception in Script: Expected variable of type "AnsiString", got "record [0]array of AnsiString; [4]array of record [0]Int32; [4]Int32; [8]Int32; [12]Int32; end; [8]array of Int32; end" at line 120, column 28

    Simba Code:
    Writeln(S[0]);
    Writeln(SS[0]);
    Result := Round((StrToInt(S[0])/StrToInt(SS[0]))*100);

    This is S[0] and SS[0]:

    Writeln(S[0]) => {TEXT = [4191], AREAS = [{X1 = 628, Y1 = 605, X2 = 652, Y2 = 613}], COLOURS = [16777215]}
    Writeln(SS[0]) => {TEXT = [6765], AREAS = [{X1 = 657, Y1 = 605, X2 = 683, Y2 = 613}], COLOURS = [16777215]}

    Technically I want to know how to divide '4191' by '6765' in Lape.

    I think I need to just include the text, something like S[0].TEXT instead

    Simba Code:
    Result := Round((StrToInt(S[0].Text)/StrToInt(SS[0].Text))*100);

    It still doesn't work.

    Simba Code:
    Result := Round((StrToInt(S[0].Text) div StrToInt(SS[0].Text))*100);

    It doesn't work either.

    Simba Code:
    Result := Round((StrToInt('4881') div StrToInt('6765'))*100);

    That works but the result is 0...
    Last edited by DemiseScythe; 07-28-2013 at 01:49 AM.

  15. #15
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by DemiseScythe View Post
    Why doesn't StrToInt work on Lape?

    Exception in Script: Expected variable of type "AnsiString", got "record [0]array of AnsiString; [4]array of record [0]Int32; [4]Int32; [8]Int32; [12]Int32; end; [8]array of Int32; end" at line 120, column 28

    You cannot do that :l
    StrToInt only accepts strings and converts them to integers.

    You'd have to do:

    Simba Code:
    StrToInt(S[0].Text[0]) / StrToInt(SS[0].Text[0]) //or w/e..
    Last edited by Brandon; 07-28-2013 at 02:02 AM.
    I am Ggzz..
    Hackintosher

  16. #16
    Join Date
    Jan 2008
    Location
    10° north of Hell
    Posts
    2,035
    Mentioned
    65 Post(s)
    Quoted
    164 Post(s)

    Default

    Just a note, records aren't restricted to global declarations, methods can have type, constant, variable and even other methods declared.

    Simba Code:
    function a(): string;
      function b(): string;
      begin
        Result := '2';
      end;
    type
      TTest = record
        d: string;
      end;
    const
      c = '3';
    var
      Test: TTest = ['4'];
    begin
      Result := '1' + b() + c + Test.d;
    end;

    begin
      WriteLn(a()); //1234
    end.

    Dg's Small Procedures | IRC Quotes
    Thank Wishlah for my nice new avatar!
    Quote Originally Posted by IRC
    [22:12:05] <Dgby714> Im agnostic
    [22:12:36] <Blumblebee> :O ...you can read minds

  17. #17
    Join Date
    Aug 2013
    Posts
    41
    Mentioned
    0 Post(s)
    Quoted
    16 Post(s)

    Default

    most complete guide on Lape I've seen!

    One question though; is it not possible to dereference pointers to types? If so, that would be a much easier way of pulling out the values in an instance of a type from its pointer.

  18. #18
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by stata View Post
    most complete guide on Lape I've seen!

    One question though; is it not possible to dereference pointers to types? If so, that would be a much easier way of pulling out the values in an instance of a type from its pointer.


    I'm not sure what you mean but the OP contains a lot of examples on dereferencing.. One specific example that contains a comment about de-referencing is:

    Simba Code:
    type PInt = ^Integer;

    var
      Ptr: PChar;
      I, J: Integer;
      TIA: array[0..4] of integer;
    begin
      TIA := [1, 2, 3, 4, 5];
      Ptr := @TIA;

      For I := 0 To High(TIA) do
      begin
        writeln(PInt(Ptr)^);  //Cast our Char Pointer to an Int Pointer and dereference it. Aka get the value it points at.
        Ptr := Ptr + 4;       //Increase the char pointer by 4 bytes.
      end;
    end;
    I am Ggzz..
    Hackintosher

  19. #19
    Join Date
    Aug 2013
    Posts
    41
    Mentioned
    0 Post(s)
    Quoted
    16 Post(s)

    Default

    derefrencing type pointers, as in you have a type, and the pointer is a pointer of that type. Isn't the example you've given just aliasing the integer pointers? I don't get the point of that.

    although now that I've given the OP another look, I do see that you've derefrenced a Vehicle pointer

    is there a shortcut to derefrencing a type pointer and then getting one of its elements like so


    type MyType = record
    element1: Integer;
    element2: Short;
    end;

    var
    MyTypePointer: ^MyType;

    begin
    writeln((MyTypePointer^).element1);
    end

    like in C, this would be MyTypePointer->element1
    Last edited by stata; 08-29-2013 at 11:56 PM.

  20. #20
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    The point of the example was to show the difference in bytes between the two..

    If a char pointer points to an int type, then it only points to 1 byte out of the 4. However, casting the char pointer to an int pointer allows it to point to the int itself and not the individual bytes of that int. The example was simply showing that an int is 4 bytes (aka chars) and the right pointer should be used to retrieve values unless you want to do the math manually. It's easier to just cast or alias the pointer to the type pointed to.

    Simba Code:
    type foo = record
      I: Integer;
    end;

    var
      Something: Foo;
      Ptr: ^Foo;
    begin
      Something.I := 10;
      Ptr := @Something //Put a semi-colon here.. The simba tags for this forum is broken and if I put it here, it instead does a "Mention".
      writeln(Ptr^.I); //same as (Ptr^).I;
    end.

    I believe you are trying to do this? Which I thought was on the OP. Guess not =(
    Last edited by Brandon; 08-30-2013 at 12:14 AM.
    I am Ggzz..
    Hackintosher

  21. #21
    Join Date
    Aug 2013
    Posts
    41
    Mentioned
    0 Post(s)
    Quoted
    16 Post(s)

    Default

    Yup, that's what I wanted (and pretty much what I wrote except w/o parentheses lol)

    Alright, that clarifies things a lot man.

    One more question. If I pass an array to a procedure like so...


    procedure bob(a: TPointArray);
    begin
    nonsense;
    end;

    var
    MyTPA: TPointArray;

    begin
    bob(MyTPA);
    end;


    So here, am I sending bob the pointer to the TPA, or is bob gonna create a copy of my TPA and mess with the copy?
    Also, is this the case for other kinds of arrays (constant length, etc)?

    Also, if I was passing a string (which is not exactly a char array?), am I sending bob the pointer to the string?

    Basically, is pass by reference the default for arrays/strings like it is in C and I think Java
    Last edited by stata; 08-30-2013 at 12:26 AM.

  22. #22
    Join Date
    Jan 2007
    Posts
    8,876
    Mentioned
    123 Post(s)
    Quoted
    327 Post(s)

    Default

    Quote Originally Posted by stata View Post
    Yup, that's what I wanted (and pretty much what I wrote except w/o parentheses lol)

    Alright, that clarifies things a lot man.

    One more question. If I pass an array to a procedure like so...


    procedure bob(a: TPointArray);
    begin
    nonsense;
    end;

    var
    MyTPA: TPointArray;

    begin
    bob(MyTPA);
    end;


    So here, am I sending bob the pointer to the TPA, or is bob gonna create a copy of my TPA and mess with the copy?
    Also, is this the case for other kinds of arrays (constant length, etc)?

    Also, if I was passing a string (which is not exactly a char array?), am I sending bob the pointer to the string?

    Basically, is pass by reference the default for arrays/strings like it is in C and I think Java
    There are multiple methods of declaration:
    Simba Code:
    procedure bob(a: TPointArray); // Call-by-value (default)
    procedure bob(var a: TPointArray); // Call-by-reference
    procedure bob(const a: TPointArray); // Bob has a pointer to the original variable

    There are also other methods like "in", "out" and others, but I think you'll be just fine with the above three for now

  23. #23
    Join Date
    Aug 2013
    Posts
    41
    Mentioned
    0 Post(s)
    Quoted
    16 Post(s)

    Default

    Quote Originally Posted by Zyt3x View Post
    There are multiple methods of declaration:
    Simba Code:
    procedure bob(a: TPointArray); // Call-by-value (default)
    procedure bob(var a: TPointArray); // Call-by-reference
    procedure bob(const a: TPointArray); // Bob has a pointer to the original variable

    There are also other methods like "in", "out" and others, but I think you'll be just fine with the above three for now
    obviously there are multiple methods of declaration... that's why I'm asking

    that last declaration confuses me. Is that the same as this
    procedure bob(a: ^TPointArray);

    seems like an odd way to send a pointer, particularly since it seems to imply that "a" cannot be changed by the procedure

    and do "in" and "out" work as they did in PS? I'm aware of those...
    Last edited by stata; 09-01-2013 at 06:08 PM.

  24. #24
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by stata View Post
    that last declaration confuses me. Is that the same as this
    procedure bob(a: ^TPointArray);

    seems like an odd way to send a pointer, particularly since it seems to imply that "a" cannot be changed by the procedure

    and do "in" and "out" work as they did in PS? I'm aware of those...

    Uhh I don't think that const is a pointer. In fact, in C and many C-style languages, a const parameter is useless because either way the function will make a copy of the parameter passed and work on that.

    Basically the equivalent of doing:

    C Code:
    void func(const int I)
    {
      //work with that copy of I here..
    }

    void func(int I)
    {
      //work with the copy of I here..
    }

    Either way, it is still a copy with or without the const. So his first and last declarations seem to be the same to me :S Your example:

    Simba Code:
    Procedure Foo(a: ^TIntegerArray);
    begin
      //work with pointer "a" here..
    end;

    var
      a: TIntegerArray;
    begin
      a := [1, 2];
      Foo(@a);
    end.

    seems to be right afaik. Unless lape defined the usage of the keyword const wrong or added such a feature, I think that the third declaration Zytex posted is also pass by value.

    Simba Code:
    type Dog = record
      Speak: String;
    end;

    procedure foo(const D: Dog);
    begin
      writeln(D);
      //D.Speak := 'Meow';
    end;

    procedure bar(D: Dog);
    begin
      writeln(@D);
      D.Speak := 'Meow';
    end;

    procedure meh(var D: Dog);
    begin
      writeln(@D);
      D.Speak := 'Meow';
    end;

    procedure bleh(D: ^Dog);
    begin
      writeln(D);
      D^.Speak := 'Woof';
    end;


    var
      D: Dog;
    begin
      D.Speak := 'Woof';

      foo(D);
      bar(D);
      meh(D);
      bleh(@D);
      writeln(D);
    end.
    Last edited by Brandon; 09-01-2013 at 06:40 PM.
    I am Ggzz..
    Hackintosher

  25. #25
    Join Date
    Aug 2013
    Posts
    41
    Mentioned
    0 Post(s)
    Quoted
    16 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Uhh I don't think that const is a pointer. In fact, in C and many C-style languages, a const parameter is useless because either way the function will make a copy of the parameter passed and work on that.

    Basically the equivalent of doing:

    C Code:
    void func(const int I)
    {
      //work with that copy of I here..
    }

    void func(int I)
    {
      //work with the copy of I here..
    }

    Either way, it is still a copy with or without the const. So his first and last declarations seem to be the same to me :S Your example:

    Simba Code:
    Procedure Foo(a: ^TIntegerArray);
    begin
      //work with pointer "a" here..
    end;

    var
      a: TIntegerArray;
    begin
      a := [1, 2];
      Foo(@a);
    end.

    seems to be right afaik. Unless lape defined the usage of the keyword const wrong, I think that the third example is also pass by value.
    Makes sense to me, thanks again

Page 1 of 2 12 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •