Properties
Properties are a special mix of member variable and member procedure. They provide a way to set or retrieve values of an object, through normal looking assignments or member accesses, but also let the object perform actions if it needs to update itself.
Basic properties
Declaring and using setter and getter properties.
Indexed properties
Properties with an additional parameter.
Basic properties
A property is declared similar to a member procedure, except that the Property keyword is used instead of `Sub` or `Function`. For example, let's consider a window class for a windowing system or GUI library.
`
Type Window
Private:
As String title_
End Type
Dim As Window w
`
In order to set the window's title, a setter property can be added:
`
Type Window
Declare Property title(ByRef s As String)
Private:
As String title_
End Type
Property Window.title(ByRef s As String)
this.title_ = s
End Property
Dim As Window w
w.title = "My Window"
`
It is very similar to a member Sub, as it takes a parameter and updates the object to the new state based on the parameter. However, the syntax for sending this parameter is a basic assignment, not a function call. By assigning the new value to the `title` property, the property procedure will automatically be called with the given new value, and can update the window to reflect the change. It is up to the object how to represent the property state internally.
By design, properties can only be assigned one value at a time, and as a result the property procedure can not have more than one parameter.
After setting the window title, it should also be possible to retrieve it. Here is how to add a getter property:
`
Type Window
'' setter
Declare Property title(ByRef s As String)
'' getter
Declare Property title() As String
Private:
As String title_
End Type
'' setter
Property Window.title(ByRef s As String)
this.title_ = s
End Property
'' getter
Property Window.title() As String
Return this.title_
End Property
Dim As Window w
w.title = "My Window"
Print w.title
`
The getter is very similar to a Function. It is supposed to return the current value of the property, and it allows the current value to be calculated from other internal values, if needed. Note that both setter and getter use the same identifier, indicating they handle the same property.
Just like method overloading, it is possible to specify multiple setters, provided they have different parameter types:
`
Type Window
Declare Property title(ByRef s As String)
Declare Property title(ByVal i As Integer)
Declare Property title() As String
Private:
As String title_
End Type
Property Window.title(ByRef s As String)
this.title_ = s
End Property
Property Window.title(ByVal i As Integer)
this.title_ = "Number: " & i
End Property
Property Window.title() As String
Return this.title_
End Property
Dim As Window w
w.title = "My Window"
Print w.title
w.title = 5
Print w.title
`
In comparison to this example of properties, here is similar code that does not use properties:
`
Type Window
Declare Sub set_title(ByRef s As String)
Declare Sub set_title(ByVal i As Integer)
Declare Function get_title() As String
Private:
As String title
End Type
Sub Window.set_title(ByRef s As String)
this.title = s
End Sub
Sub Window.set_title(ByVal i As Integer)
this.title = "Number: " & i
End Sub
Function Window.get_title() As String
Return this.title
End Function
Dim As Window w
w.set_title("My Window")
Print w.get_title()
w.set_title(5)
Print w.get_title()
`
The code is basically the same, only the syntax is different. Properties are specifically designed to combine the setter/getter concept and the language's normal way of literally assigning and accessing values to a class' member variables. It is up to the programmers to decide which way they prefer.
Here is an example demonstrating a text user interface window class allowing to set position and title using properties:
`
Namespace tui
Type Point
Dim As Integer x, y
End Type
Type char
Dim As UByte value
Dim As UByte Color
End Type
Type Window
'' public
Declare Constructor _
( _
x As Integer = 1, y As Integer = 1, _
w As Integer = 20, h As Integer = 5, _
title As ZString Ptr = 0 _
)
Declare Destructor
Declare Sub show
'' title property
Declare Property title As String
Declare Property title( new_title As String )
'' position properties
Declare Property x As Integer
Declare Property x( new_x As Integer )
Declare Property y As Integer
Declare Property y( new_y As Integer )
Private:
Declare Sub redraw
Declare Sub remove
Declare Sub drawtitle
Dim As String p_title
Dim As Point Pos
Dim As Point siz
End Type
Constructor Window _
( _
x_ As Integer, y_ As Integer, _
w_ As Integer, h_ As Integer, _
title_ As ZString Ptr _
)
pos.x = x_
pos.y = y_
siz.x = w_
siz.y = h_
If( title_ = 0 ) Then
title_ = @"untitled"
End If
p_title = *title_
End Constructor
Destructor Window
Color 7, 0
Cls
End Destructor
Property window.title As String
title = p_title
End Property
Property window.title( new_title As String )
p_title = new_title
drawtitle
End Property
Property window.x As Integer
Return pos.x
End Property
Property window.x( new_x As Integer )
remove
pos.x = new_x
redraw
End Property
Property window.y As Integer
Property = pos.y
End Property
Property window.y( new_y As Integer )
remove
pos.y = new_y
redraw
End Property
Sub window.show
redraw
End Sub
Sub window.drawtitle
Locate pos.y, pos.x
Color 15, 1
Print Space( siz.x );
Locate pos.y, pos.x + (siz.x \ 2) - (Len( p_title ) \ 2)
Print p_title;
End Sub
Sub window.remove
Color 0, 0
Var sp = Space( siz.x )
For i As Integer = pos.y To pos.y + siz.y - 1
Locate i, pos.x
Print sp;
Next
End Sub
Sub window.redraw
drawtitle
Color 8, 7
Var sp = Space( siz.x )
For i As Integer = pos.y + 1 To pos.y + siz.y - 1
Locate i, pos.x
Print sp;
Next
End Sub
End Namespace
Dim win As tui.window = tui.window( 3, 5, 50, 15 )
win.show
Sleep 500
win.title = "Window 1"
Sleep 250
win.x = win.x + 10
Sleep 250
win.title = "Window 2"
Sleep 250
win.y = win.y - 2
Sleep 250
Locate 25, 1
Color 7, 0
Print "Press any key...";
Sleep
`
Note how updating the window's position or title automatically causes the window to be redrawn.
Indexed properties
Properties can have an additional parameter that is called an `index` (currently only one additional parameter is allowed). The index is specified in parentheses behind the property's name, as if the property was an array (with only one dimension). For example:
`
Type IntArray
'' setters
Declare Property value(index As Integer, value As Integer)
Declare Property value(index As String, value As Integer)
Declare Property value(index As Integer, value As String)
Declare Property value(index As String, value As String)
'' getters
Declare Property value(index As Integer) As Integer
Declare Property value(index As String) As Integer
Private:
Dim As Integer data_(0 To 9)
End Type
Property IntArray.value(index As Integer) As Integer
Return this.data_(index)
End Property
Property IntArray.value(index As String) As Integer
Return this.data_(CInt(index))
End Property
Property IntArray.value(index As Integer, value As Integer)
this.data_(index) = value
End Property
Property IntArray.value(index As String, value As Integer)
this.data_(CInt(index)) = value
End Property
Property IntArray.value(index As Integer, value As String)
this.data_(index) = CInt(value)
End Property
Property IntArray.value(index As String, value As String)
this.data_(CInt(index)) = CInt(value)
End Property
Dim a As IntArray
a.value(0) = 1234
a.value("1") = 5678
a.value(2) = "-1234"
a.value("3") = "-5678"
Print a.value(0)
Print a.value("1")
Print a.value(2)
Print a.value("3")
Sleep
`
This simulates an integer array that can be assigned strings, and even be indexed with strings. See KeyPgProperty for another example.