Member Procedures

FreeBASIC

Member Procedures
 
Procedures with full access to members of a Type or Class.

Declaration and definition
Declaring and defining member procedures.
Usage
Calling member procedures.
The hidden parameter, This
Implicit access to the instance with which non-static member procedures are called.
Access rights
Referring to other members in member procedures.
Overloading
Declaring two or more member procedures with the same name.
Static member procedures
Differences from non-static member procedures.

The term 'member procedure' refers to both static and non-static member procedures, unless otherwise noted.

Declaration and definition

Member procedures are declared much like normal module-level procedures except that they are declared within, and defined outside, a Type or Class definition [1].

When defining member procedures, the procedure name is prefixed with the name of the Type or Class and the member access operator (Operator . (Member Access)). It is an error to define a member procedure without a matching declaration in the Type or Class definition.

The following example declares and defines a Sub and Function member procedure:

'' foo1.bi

Type foo
    Declare Sub f (As Integer)
    Declare Function g As Integer

    i As Integer
End Type

Sub foo.f (n As Integer)
    Print n
End Sub

Function foo.g As Integer
    Return 420
End Function


Usage

Member procedures are referred to just like member data, that is, their name is prefixed with the name of an object instance and the member access operator (Operator . (Member Access)) [2].

The following example, using the code from the last example, calls Sub and Function member procedures:

'' ... foo with non-static members as before ...
#include once "foo1.bi"

Dim bar As foo
bar.f(bar.g())



The hidden parameter, This

Member procedures actually have an additional parameter than what they are declared with [3]. When they are called, using the name of an instance and Operator . (Member Access), a reference to that instance is passed along with any other arguments in the call, allowing the member procedure direct access to the instance.

The additional parameter added by the compiler is called This, and since it's a reference, any modifications to This are actually modifications to the instance that was passed to the member procedure when it was called. You can use This just like any other variable, ie., pass it to procedures taking a object of the same type, call other member procedures and access member data using Operator . (Member Access), etc.

Most of the time, however, using This explicitly is unnecessary; member procedures can refer to other members of the instance which they are passed directly by name, without having to qualify it with This and Operator . (Member Access). The only times when you need to qualify member names with This is when the member name is hidden, for example, by a parameter or local variable. In these situations, qualifying the member name is the only way to refer to these hidden member names.

Note:
To access duplicated symbols defined outside the Type, use:
.SomeSymbol (or ..SomeSymbol if inside a With..End With block).

The following example uses the This keyword to refer to member data whose name is hidden by a parameter and local variable:

Type foo
    Declare Sub f (i As Integer)
    Declare Sub g ()

    i As Integer = 420
End Type

Sub foo.f (i As Integer)
    '' A parameter hides T.i, so it needs to be qualified to be used:
    Print this.i
End Sub

Sub foo.g ()
    '' A local variable hides T.i, so it needs to be qualified to be used:
    Dim i As Integer
    Print this.i
End Sub


Access rights

Unlike normal module-level procedures, member procedures have full access rights to the members of the Type or Class they are declared in; they can refer to the public, protected and private members of a Type or Class.

Overloading

A member procedure can be declared to have the same name as another member procedure, provided the parameters are different, either in number or in type. This is referred to as overloading.

Only the parameters are used to determine if a procedure declaration is a valid overload. For example, a Type or Class could have static and non-static member procedures with the same name, or Sub and Function member procedures with the same name

Unlike a module-level procedure, which needs to specify the Overload clause in the declaration to allow overloading it, a member procedure is overloadable by default, and does not need the Overload clause.

Type T
    Declare Sub f
    
    '' Different number of parameters:
    Declare Sub f (As Integer)
    
    '' Different type of parameters:
    Declare Sub f (ByRef As String)
    
    '' Again, parameters are different:
    Declare Function f (As UByte) As Integer
    
    '' following three members would cause an error,
    '' number of parameters and/or types do not differ:

    '' Declare Function f As Integer
    '' Declare Function f (As UByte) As String
    '' Declare Static Function f (As UByte) As Integer

    '' ...
    somedata As Any Ptr
End Type


Static member procedures

Static member procedures are declared and defined much in the same way as non-static member procedures, with the Static keyword preceding the declaration and definition.

Member procedures defined using the Static keyword must be declared with the Static keyword in the Type or Class definition, or a compiler error will occur. Like non-static member procedures, it is an error to define a static member procedure without a matching declaration in the Type or Class definition.

Do not confuse this with procedure definitions that specify static storage for their variables and objects by appending the Static keyword to the procedure header. The Static keyword can be used in both contexts, however; static member procedures can be defined with static variable and object storage.

The following example declares two static member procedures, the first of which also has static variable and object storage. Note that the Static keyword is optional in the member procedure definition:

'' foo2.bi

Type foo
    Declare Static Sub f (As Integer)
    Declare Static Function g As Integer

    i As Integer
End Type

Static Sub foo.f (n As Integer) Static
    Print n
End Sub
    
Function foo.g As Integer
    Return 420
End Function


Static member procedures can be called like non-static member procedures, qualifying the name of the procedure with the name of an instance and the member access operator (Operator . (Member Access)).

They can also be called by qualifying the procedure name with the name of the Type or Class they were declared in and the member access operator (Operator . (Member Access)). In other words, an instance is not required in order to call static-member procedures.

The following example, using the code from the last example, uses both ways to call static member procedures:

'' ... foo with static members as before ...
#include once "foo2.bi"

Dim bar As foo
bar.f(foo.g())


Unlike non-static member procedures, which are declared with an extra This parameter, static member procedures do not get passed an instance when called. Because of this, static member procedures can only refer to constants, enumerations, other static members (data or procedures), etc., without qualifying their names. Static member procedures can still refer to non-static members when qualified with an instance, for example: a parameter or local variable.

The following example refers to a non-static member from a static procedure:

Type foo
    Declare Static Sub f (ByRef As foo)

    i As Integer
End Type

Sub foo.f (ByRef self As foo)
    '' Ok, self is an instance of foo:
    Print self.i

    '' would cause error
    '' cannot access non-static members, no foo instance:
    '' Print i
End Sub


[1] In the future, member procedures may be able to be defined within the Type or Class definition.
[2] Static member procedures do not require an object instance in order to be called.
[3] Static member procedures do not have this extra parameter added by the compiler, and so cannot access the object instance from which it was called with.