Morfik Pascal Subroutines and Scope

Morfik Pascal has the same subroutine constructs as all the major Pascal implementations available and then some more. Some additions were made to the Morfik Pascal language in order to fully support the underlying Morfik language semantics.


Types of Subroutines

In Morfik Pascal there are two fundamental types of subroutines: Procedures and Functions. The difference between a Procedure and a Function is whether or not the routine returns a value.

Procedures

Procedures are subroutines that, by definition, do not return values, (except via input parameters passed by reference, which is explained later). Since they do not return a value, procedures cannot be part of expressions.

The following is a short example of a Procedure:

Procedure Test;
Var 
  F2 : file of Integer;
Begin
    AssignFile(F1, 'c:\test.int');
    Rewrite(F1);
    Write(F1, 9);
    CloseFile(F1);
End;

Functions

Functions are subroutines that do return values. Because of this, functions can be used within expressions where you would normally use a literal value.

The following is a short example of a function:

Function GetTestString : String;
Begin
    Result := 'Test!';
End;

Returning Values

Returning values from a function can be done in two different ways: through the Result variable or by assigning a value to the name of the function itself.

In the previous example you can see the use of the Result variable which takes the following form:

  Result := <value>;


You can assign the value you want to return from a function to the function’s name, as if it was a variable. This takes the following form:

  FunctionName := <value>;


If you have chosen to use this method, you cannot read back the value assigned to the function name. This would be interpreted by the compiler as actually being a recursive call to the function. In order to get around this limitation, common practice is to create an intermediate variable which will hold the value until such time as you are ready to exit the function, keeping the value available for reading. In order to simplify and standardize the usage of this pattern, Morfik Pascal uses the Result variable. Assigning a value to the result variable is essentially the same as assigning it to the name of the function but at any time you can use Result in the right side of an expression, without initiating a recursive call.

Parameters

Passing parameters to subroutines is done through a list which is constructed in a very specific way.

Creating a Parameter List

A subroutine parameter list is very similar to a sequence of variable declarations. This can be observed in the following example.

 Procedure Test(Param1 : string; Param2 : integer);


This simple example shows a parameter list with two parameters of different types. Morfik Pascal has a number of modifiers which can be applied to parameters to change how they are handled by the compiler. The following is a sample of all possible forms of declaring parameters.

Procedure Test(pValueParameter1 : Integer, 
                       Const pConstParameter : Integer, 
                       Var   pVarParameter : Integer, 
                       Out   pOutParameter : Integer, 
                       Const pConstUntypedParamter, 
                       Var   pVarUntypedParameter, 
                       Out   pOutUntypedParameter)
Begin
End;


There are basically five different kinds of parameters:

1. By Value

2. Constant

3. By Reference

4. Output only

5. Untyped parameter

Parameters can be categorized in the following way:

  • Any parameter which does not have a Var, Const or Out modifier can be considered a parameter passed by value.
  • Any parameter which has no type definition can be considered as an untyped parameter.

Parameters Passed By Value

A parameter passed by value acts as a variable local to the subroutine to which it belongs. The parameter is initialized to the value passed to the subroutine and though it can be altered inside the routine, the new value will not persist after the code exits the subroutine.

Procedure ABC(Param1 : integer);
Begin
    Param1 := Param1 * 2;
End;


If no modifier is specified for a parameter it is presumed by the Morfik Pascal compiler to be a parameter passed by value.

Var
  I : integer;
Begin
    I := 2;
    ABC(I);
    CallOtherProc(I);


The value of variable "I" when the call to CallOtherProc is reached will be 2. The value of the original variable has not been altered since the ABC routine worked on a copy of the value held by the original value By value parameters can receive the result of any expression that yields a compatible value as can be seen in the following example.

  ABC ( (3+6) * 3-1 );

Constant Parameters

Constant parameters are very similar in usage to value parameters but they cannot be altered within the subroutine. The main purpose of constant parameters is to serve as insurance to the developer that when a parameter is not meant to be altered, it is not.


Note: In Morfik 07 the Morfik Pascal compiler will not immediately complain if you try to alter a constant parameter within a subroutine. When you do a full compile of the project, however, the backend platform compiler will complain.

Parameters Passed By Reference

Parameters passed by reference, using the Var modifier, should be used whenever a subroutine needs to return a modified value for one or more of its parameters. By reference parameters can only be called with the use of variables since any literal expression is evaluated to a value and would not be addressable in memory to have its content changed.

Usage of by reference parameter within a subroutine is exactly like that of a by value parameter, except that the value of the variable which was passed as a parameter will be altered once the execution of the routine concludes. The following is an example of passing a parameter by reference:

Procedure ABC(var Param1 : integer);
Begin
    Param1 := Param1 * 2;
End;


In this case if we applied the same code that we used to review the workings of by value parameters we would have a different result.

Var 
    I : integer;
Begin
    I := 2;
    ABC(I);
    CallOtherProc(I);


The value of variable "I" when the call to CallOtherProc is made will actually be 4, since inside the subroutine the value of 2 was multiplied by two and that result was returned in the parameter declared with the Var modifier.

Output-Only Parameters

Output-only parameters are specifically for returning more than one value from a subroutine. For returning a single value the norm is to just use a function. When there is a need to return more than one value from a subroutine, multiple output-only parameters should be used. Output-only parameters are declared using the Out modifier. Any value the subroutine receives in an Out parameter is discarded.

Untyped Parameters

When a parameter does not have a predefined data type it can receive any variable or constant, it cannot receive a literal value, though, as untyped parameters can only be declared as Var, Const or Out. Morfik Pascal does not allow for By Value un-typed parameters.

Untyped parameters are passed as memory addresses and it is up to the developer to know how to handle them within the subroutine.


Note: An untyped parameter can be used as a way of being able to pass parameters of different types to a subroutine. In many situations the same results can be achieved by using different overloaded versions of a Procedure or Function. Though there are situations where you could not accommodate all the necessary data types with overloaded functions, their usage offers the added benefit of additional type checking.
For more information see Overloading Subroutines later in this chapter.

External Subroutines

External subroutines can be brought into your Morfik Pascal universe from the Browser or the intermediate code level on the server side of your application. External subroutines are declared with the assistance of compiler metadata attributes. The following is an example how a server side external routine can be imported into your code:

Function IntToStr(AnInteger : integer) : string; 
['external=systemext.pas']

JavaScript Subroutines

Sometimes, if you are experienced in using JavaScript, you might want to do some experimenting with JavaScript code in your Morfik application. It is possible to include inline JavaScript code on the browser side of your application through the use of JavaScript subroutines. The following is an example of how to create an inline JavaScript subroutine in your application.

Procedure Go(); javascript;
(*!
alert('programming in javascript is fun!');
*)


Notice that the body of JavaScript code is actually contained within a multi-line comment, within your Morfik Pascal code. The JavaScript modifier in the subroutine’s declaration instructs the compiler to look for the comment containing the JavaScript language code, right after the subroutine’s header.

You can also use parameters with your inline JavaScript subroutines. In the next example you can see the same routine from the previous example, but using a parameter for the string which is shown, instead of a string literal.

Procedure Go(mymessage : string); javascript;
(*!
alert(mymessage);
*)


Note: The inline JavaScript code is not checked by the Morfik Pascal compiler so it is entirely up to the developer to make sure that the code is correct or runtime errors might occur.

Overloading Subroutines

In Morfik Pascal it is possible to have several different subroutines with the same name, as long as they have different parameter lists. This is called Overloading and can be really useful. Overloaded subroutines must be marked with the overload modifier. The following is an example of how to use subroutine overloading.

Function toString(AnInt : Integer) : String; Overload;
Begin
    Result := IntToStr(AnInt);
End;
 
Function toString(AFloat : Double) : String; Overload;
Begin
    Result := FloatToStr(AFloat);
End;


Note: The addition of Overloading capabilities to the underlying Morfik semantic structure, which is the basis for Morfik Pascal, was done at the end of the product development cycle, for Morfik 07. This means that this feature is not exploited to its full potential by the Morfik Framework itself.
In future releases of Morfik you will, probably, see this feature being more widely used.

Nested Subroutines and Data Types

Morfik Pascal fully supports nesting subroutines within one another. You can also have nested data types, i.e. data types which are declared within a subroutine. The following example shows how the syntax for these two features is implemented in Morfik Pascal.

Procedure Test1(Param1 : integer);
//Nested data type declaration
Type 
    PInteger = ^integer;
 
     //Nested subroutine
     Procedure Test2(Param2 : String);
     Begin
         ShowMessage(Param2);
     End;
 
Var
     P : Pinteger;
Begin
    P := Param1^;
    Test2(IntToStr(P^));
End;

Scope Rules

A reference to an identifier, within an application, must happen within that identifier’s declaration scope. The following are the main scope definition rules for Morfik Pascal.

Subroutine (Function/Procedure) Scope

Subroutine scope is defined by the boundaries of the subroutine itself. Any variables, data types, and nested subroutines it declares will be visible only from within that subroutine. A nested subroutine will have access to any identifier declared prior to its declaration, within the surrounding subroutine.

A nested subroutine can define an identifier with the same name of an identifier declared in the subroutine in which it is nested. The innermost variable will then hide the outermost one.

Class Scope

An identifier declared within a class is visible to all members of the class and its descendants. This scope included instance variables, methods and properties. The Subroutine Scope rules apply to all method declarations.

Module Scope

Identifiers (variables, data types, subroutines, classes) declared in the implementation section of a module are visible within the module in which they are declared. They will be visible to any subroutines and classes declared within the same module.

Public Scope

Identifiers (variables, data types, subroutines, classes) declared in the interface section of a module are visible within the module in which they are declared and in any module that imports that module. They will be visible to any subroutines and classes declared within the same module and within the modules that have imported the module in which they are declared.

This is the broadest scope level in Morfik Pascal.

In Listing 1 you can see examples of all the possible scope levels in Morfik Pascal.

Listing 1 – Possible Scopes in Morfik Pascal

Unit MyModule;  // Module/Public Scope
 
Interface  // Whatever is defined in the interface has public scope
(**
  MyInt is available within this module and in any module 
  that imports this module, since it is declared in the interface 
  section. (Public Scope)
*)
var
  MyInt : integer;
 
Type 
  AClass = class  // Class Scope
    (**
      Class level MyInt is available only within this class since 
      it is declared private.  Within the class it hides the module
      scope MyInt
    *)
    Private 
      MyInt : integer;
 
    (**
       Method OuterFunc defines a new scope
    *)
    Public
     Function AClass.OuterFunc : String;  //Method Scope
 
  End;  // class definition
 
(**
  GlobalProc is available within this module and in any module 
  that imports this module because it is declared in the interface
  section..
*)
Procedure GlobalProc;  //Function/Procedure Scope
 
Implementation
 
(**
  AnotherInt is available only within this module since it
  is declared in the implementation section. (Module Scope)
*)
Var 
  AnotherInt : integer;
 
    (**
       Method OuterFunc defines a new scope
    *)
Function OuterFunc : String;  //Method Scope
  (**
    Method level MyInt is available only within this method.
    Within the method it hides the Module and Class 
    scope variables of the same name.
  *)
Var
  MyInt : integer;
 
  Function NestedFunc : String; //Nested Function Scope
    (**
      Nested function level MyInt is available only within this
      function.  Within the function it hides the Module, Class
      and method scope variables of the same name.
    *)
Var
  MyInt : integer;
  Begin  //Body of the nested function
  End;
 
Begin  //Body of the outer function
End;
 
 
(**
  GlobalProc is available within this module and in any module 
  that imports this module because it was previously declared in
  the interface section.
*)
Procedure GlobalProc;  //Function/Procedure Scope
(**
  Procedure level MyInt is available only within this Procedure
  Within the Procedure it hides the Module scope variable of 
  the same name.   (Public Scope)
*)
Var
  MyInt : integer;
Begin
End;
 
(**
  InternalProc is available only within this module since it 
  is declared only in the implementation secion. (Module Scope)
*)
Procedure InternalProc;  // Function/Procedure Scope
Begin
End;
 
End.

Wrapping it up

Morfik Pascal offers a powerful array of features from which to build your application. These include extensive support for subroutines including overloading and nesting.


Related Topics

See Also

Back to top