Morfik Basic Subroutines and Scope

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


Types of Subroutines

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

Subs

Subs 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, Subs cannot be part of expressions.

The following is a short example of a Sub:

  Public Sub Test
    Dim F2 As file of Integer
 
    AssignFile(F1, "c:\test.int")
    Rewrite(F1)
    Write(F1, 9)
    CloseFile(F1)
  End Dub

Functions

Functions are subroutines which 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:

  Public function GetTestString As String
    Return "Test!"
  End Function

Returning Values

Returning values from a function can be done in three different ways, through the Return command, 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 return command which takes the following form:

  Return <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 Basic introduces the Result variable. Assigning a value to the result value 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. Usage of the Result variable takes the following form:

 Result = <value>

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.

public sub Test(Param1 As string, Param2 As integer)

This simple example shows a parameter list with two parameters of different types. Morfik Basic 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.

  Public Sub Test(      pValueParameter1 As Integer, _
                  ByVal pValueParameter2 As Integer, _
                  Const pConstParameter  As Integer, _
                  ByRef pVarParameter    As Integer, _
                  Out   pOutParameter    As Integer, _
                  Const pConstUntypedParamter      , _
                  ByRef pVarUntypedParameter       , _
                  Out   pOutUntypedParameter         _
                 )
  End Sub

There are basically five different kinds of parameters:

1. By Value

2. Constant

3. By Reference

4. Output only

5. Un-typed parameter

Parameters can be categorized in the following way:

  • Any parameter which does not have a ByRef, Const or Out modifier can be considered a parameter passed by value.
  • Any parameter which has no type definition can be considered as an un-typed 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.

  Public Sub ABC(Param1 As integer)
    Param1 = Param1 * 2
  End Sub

Parameters passed by value can be explicitly marked as such by using the ByVal modifier. If no modifier is specified for a parameter it is presumed by the Morfik Basic compiler that it is a parameter passed by value.

  Dim I As integer
 
  I = 2
  ABC(I)
  CallOtherSub(I)

The value of the I variable when the call to CallOtherSub 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 Basic 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 ByRef 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:

  Public Sub ABC(ByRef Param1 As integer)
    Param1 = Param1 * 2
  End Sub

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.

  Dim I As integer
 
  I = 2
  ABC(I)
  CallOtherSub(I)

The value of variable I when the call to CallOtherSub 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 ByRef 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.

Un-Typed 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 un-typed parameters can only be declared as ByRef, Const or Out. Morfik Basic does not allow for By Value un-typed parameters.

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

Note: An un-typed 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 achieved by using different overloaded versions of a Sub 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 Basic 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:

  Public Function IntToStr(AnInteger As Integer) As 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.

    public javascript Sub Go()
    /*!
      alert('programming in javascript is fun!');
     */


Notice that the body of JavaScript code is actually contained within a multi-line comment, within your Morfik Basic 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.

    Public javascript Sub Go(mymessage As string)
    /*!
      alert(mymessage);
    */
Note: The inline JavaScript code is not checked by the Morfik Basic 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 Basic 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. The following is an example of how to use subroutine overloading.

  Public Overloads function toString(AnInt As Integer) As String
    Return IntToStr(AnInt)  
  End Function
 
  public overloads function toString(AFloat As Double) As String
    Return FloatToStr(AFloat)
  End Function
Note: The addition of Overloading capabilities to the underlying Morfik semantic structure, which is the basis for Morfik Basic , 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 Basic fully supports nesting subroutines within one another. This is a Morfik specific addition to the Basic language which can be used to better organize your code. 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 Basic.

    Public sub Test1(Param1 As Integer)
        'Nested data type declaration
        Type PInteger Ref Integer
 
        'Nested subroutine
        Sub Test2(Param2 As String)
            ShowMessage(Param2)
        End Sub
 
        Dim P As PInteger
 
        P = Ref Param1
        Test2(IntToStr(Deref P))
    End Sub

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 Basic.

Subroutine Scope

Subroutines 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 a module as private 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 a module as public are visible within 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 Basic.

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

Listing 1 – Possible Scopes in Morfik Basic

Namespace MyModule  'Module/Public Scope
 
/**
  MyInt is available within this module and in any module 
  that imports this module. (Public Scope)
*/
Public Dim MyInt As integer
 
/**
  AnotherInt is available only within this module since it
  is declared private. (Module Scope)
*/
Private Dim AnotherInt As Integer
 
Public Class AClass  '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 As Integer
 
    /**
       Method OuterFunc defines a new scope
    */
    Function OuterFunc As 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.
    */
    Dim MyInt As Integer
 
      Function NestedFunc As 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.
      */
      Dim  MyInt As Integer
 
      End Function
 
    End Function
 
End Class
 
/**
  GlobalSub is available within this module and in any module 
  that imports this module.
*/
Public Sub GlobalSub 'Function/Sub Scope
/**
  Sub level MyInt is available only within this Sub.  Within the
  Sub it hides the Module scope variable of the same name.
  (Public Scope)_
*/
Dim MyInt As integer
 
End Sub
 
/**
  InternalSub is available only within this module since it 
  is declared private.
  (Module Scope)
*/
Private Sub InternalSub 'Function/Sub Scope
 
End Sub
 
End Namespace

Wrapping it up

Morfik Basic 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