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, v As Integer)
      Declare Property value(index As String, v As Integer)
      Declare Property value(index As Integer, v As String)
      Declare Property value(index As String, v 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, v As Integer)
      This.data_(index) = v
   End Property

   Property IntArray.value(index As String, v As Integer)
      This.data_(CInt(index)) = v
   End Property

   Property IntArray.value(index As Integer, v As String)
      This.data_(index) = CInt(v)
   End Property

   Property IntArray.value(index As String, v As String)
      This.data_(CInt(index)) = CInt(v)
   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.

