Functions/Subs

<< Click to Display Table of Contents >>

Navigation:  ThinBASIC Core Language > Script structure >

Functions/Subs

 

Functions and Subs are the same in thinBasic, so here use the two terms as synonyms.

Subs are just functions not returning any value.

 

Function Procedures

 

A Function procedure is a series of thinBasic statements enclosed by the FUNCTION and END FUNCTION statements.

 

A Function procedure is similar to a Sub procedure in other languages, but can also return a value.

 

A Function procedure can take arguments (constants, variables, or expressions that are passed to it by a calling procedure). If a Function procedure has no arguments, its Function statement must include an empty set of parentheses.

 

A Function returns a value by assigning a value to FUNCTION keyword in one or more statements of the procedure. The return type of a Function is always automatically converted to the function return type.

 

Function declaration:

 

Function FunctionName [([arguments])] [As Type [PTR]]

 

 [Local variable list]

 [Dim variable list]

 

 {statements}

 [Function = ReturnValue]

 {statements}

 [Exit Function]

 {statements}

 

End Function

 

In the following example, the Celsius function calculates degrees Celsius from degrees Fahrenheit. When the function is called from the ConvertTemp Sub procedure, a variable containing the argument value is passed to the function. The result of the calculation is returned to the calling procedure and displayed in a message box.

 

Function Celsius(fDegrees As Number) As Number

Function = (fDegrees - 32) * 5 / 9

End Function

 

If a function is specified without any AS clause (so no indication about what type of data the function is returning), AS LONG is assumed by default.

 

Getting data into a function: parameters

 

Data is passed to functions using parameters.

Parameters serve as placeholders for the data you want to pass into your procedure. You can name your parameters anything that is valid as a variable name.

When you create a procedure, parentheses must be included after the name of the procedure. Any parameter is placed inside these parentheses, separated by commas.

 

In the following example, InVal is a placeholder for the value being passed into the Factorial function for factorial calculation:

 

Function Factorial(InVal As Number) As Number

Dim Count As Long

Dim RetVal As Long

 

 RetVal = 1

For Count = 2 To InVal

   RetVal = RetVal * Count

Next

 

Function = RetVal

 

End Function

 

Normally, thinBasic passes parameters to a Function by copy (BYCOPY). It means that a copy of the passed data will be created locally inside the function and any change to the local data will not effect the original data.

Parameters can also be passed by reference (BYREF). In this way, the address of the variable is passed and the function has to look at that address to get the value of the parameter. Passing parameters by reference will not make a copy of the original data but a reference to the original data will be created and any change to local function parameter will effect also original variable.

 

The passing parameter method is specified by appending a clause in front of the parameter name. For example:

 

FUNCTION Test(A AS INTEGER)         '---Integer passed by copy, default one

FUNCTION Test(BYVAL A AS INTEGER)   '---Integer passed by copy, explicitly

FUNCTION Test(BYCOPY A AS INTEGER) '---Integer passed by copy, explicitly

FUNCTION Test(BYREF A AS INTEGER)   '---Integer passed by reference

 

Parameters can be declared OPTIONAL. This will instruct thinBasic that, when the function will be called one or more parameters may be missed.

Parameters declared as OPTIONAL will be in any case created inside the function but if missed during function calling, default data will be assigned.

OPTIONAL keyword can be used for every parameter. Once used, all parameter following the first declared as OPTIONAL will be OPTIONAL by default.

 

'---First parameter if not optional

'---Second parameter is optional

FUNCTION Test(MyFirstVar AS INTEGER, OPTIONAL MySecondVar AS LONG)

 

'---First parameter if not optional

'---Second parameter is optional

'---Third parameter will be optional by default

FUNCTION Test(MyFirstVar AS INTEGER, OPTIONAL MySecondVar AS LONG, MyThirdVar AS EXT)

 

Parameters type can be omitted. In this case BYVAL ... AS LONG will be assumed.

For example:

Function AddMessage( _

                     hDlg    As Long  , _

                     Message As String, _

                     lObject As String, _

            Optional Details As String, _

                     P1, P2, P3)

Variable type for parameters P1, P2, P3 is not defined. thinBasic will assume:

BYVAL P1 as LONG

BYVAL P1 as LONG

BYVAL P1 as LONG

 

ByCopy is an alias of ByVal

 

Passing UDT data structure to a function.

 

UDT (User Defined Types) can be passed to a function both ByRef or ByVal.

UDT arrays can only be passed ByRef.

 

When it is not know what UDT type can be passed at script time but only at RunTime a special pseudo data type called AnyType can be used. Function will determine the passed UDT type at runtime.

 

Example, a recursive QuickSort function that can sort any UDT array type:

'------------------------------------------------------------------------------

' Generic function used to sort any UDT by any UDT field name

' Function takes advance of 

'   - new pseudo type AnyUdt that means that UDT is determined at runtime

'   - new feature that allows to determine UDT element name at runtime

'     including its name between () after the point

'------------------------------------------------------------------------------

function AnyUdt_QSort(byref t1() as AnyType, firstIndex as long, lastIndex as long, sFieldName as String)

  local low         as long

  local high        as long

  local pivotValue  like typeof(t1(1).(sFieldName)) '<---Same type as the UDT element passed by name

  local tTemp       like typeof(t1)                 '<---Same type as UDT passed at Runtime

 

  low = firstIndex

  high = lastIndex

  pivotValue = T1((firstIndex + lastIndex) / 2).(sFieldName) '---UDT element name is determined at runtime

 

  Repeat

 

    While T1(low).(sFieldName) < pivotValue '---UDT element name is determined at runtime

      low += 1

    Wend

 

    While T1(high).(sFieldName) > pivotValue '---UDT element name is determined at runtime

      high -= 1

    Wend

 

    If low <= high then

      '---SWAP

        tTemp     = T1(low)

        T1(low)   = T1(high)

        T1(high)  = tTemp

      '---

      low += 1

      high -= 1

    End If

 

  Until low > high

 

  If firstIndex < high then

    AnyUdt_QSort(T1, firstIndex, high, sFieldName)

  End If

 

  If low < lastIndex then

    AnyUdt_QSort(T1, low, lastIndex, sFieldName)

  End If

End function

 

Variadic parameters

Sometimes it is not possible to know in advance how many parameters can be passed into a sub/function.

ThinBASIC solve this problem adding the so called "variadic" parameters: just indicate a parameter as an array with the ANY keyword inside round brackets.

So: parameter name followed by "(", followed by "Any", followed by ")".

Here an example:

 

Function Variadic1(FirstVariadicParam(AnyAs Ext, sBuffers(AnyAs StringAs Long

  PrintL "From inside " & Function_Name

  PrintL "Variadic parameter 'FirstVariadicParam' number of elements:"UBound(FirstVariadicParam)

  PrintL "Variadic parameter 'sBuffers' number of elements:"UBound(sBuffers)

  PrintL "----------------------------------------------------------------------------"

 

  PrintL "Listing all values of 'FirstVariadicParam':"

  For lCount As Long = 1 To UBound(FirstVariadicParam)

    PrintL " - Element", lCount, "has value of", FirstVariadicParam(lCount)

  Next 

  PrintL

  

  Function = UBound(FirstVariadicParam)

 

End Function

 

and later on call the function in this way, that is surround the values of a variadic parameter in round brackets:

 

'---Because first and second parameters are variadic, pass any number of numeric/string expressions inside round brackets

PrintL "Function exit value", Variadic1( (123, 456, 789, Sin(Rnd), Cos(Rnd)), ("ABCDE""---Z---") )

 

 

Up to 32 parameters can be passed to subs/functions.

 

Getting data out of a function

 

To get data out of a function, you have direct or indirect way. Here they are.

 

Direct way

 

There are 3 possible direct ways to return a value from a function:

1.assign your value or expression to the Function keyword before function ends

2.assign your value or expression to the name of the function you are inside before function ends

3.use Return followed by the value or expression you want to return before function ends

 

For example, the following function calculates the total number of bytes of all files inside a directory. To return the total number of bytes, the calculated value is assigned to Function keyword before function ends.

 

USES "FILE"     'Tell thinBasic you want to use "FILE" module

USES "LL"       'Tell thinBasic you want to use "LL" module (Linked List module)

 

Function TotalFileSize(lDir As String) As Quad

Local Count     As Long

Local FileName As String

Local pList     As Long

Local nItems   As Long

Local TotSize   As Quad

 

 pList = Dir_List(lDir, "*.*", %FILE_NORMAL Or %FILE_HIDDEN Or _

                               %FILE_SYSTEM Or %FILE_ADDPATH)

 nItems = LL_Count(pList)

 

If nItems > 0 Then

  For Count = 1 To nItems

     FileName = LL_GetItem(pList, Count)

     TotSize = TotSize + File_Size(FileName)

  Next

End If

 

   '---Here the 3 possible ways to return the value

   Function = TotSize        '---Method 1

   TotalFileSize = TotSize   '---Method 2

   Return TotSize            '---Method 3

 

  End Function

 

Indirect way

 

An indirect way to return data from a function is to pass one or more parameter using BYREF option in from of parameter name.

BYREF means you want to pass a reference of a variable instead of the value of the variables.

Changes made inside a function to parameters passed BYREF will change the value of the referenced variable.