Wiki source for ProPgProperties


Show raw source

{{fbdoc item="title" value="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.

**{{anchor name="BASIC|Basic properties"}}**
Declaring and using setter and getter properties.
**{{anchor name="INDEXED|Indexed properties"}}**
Properties with an additional parameter.

{{anchor name="BASIC"}}{{fbdoc item="section" value="Basic properties"}}

A property is declared similar to a [[ProPgMemberProcedures|member procedure]], except that the [[KeyPgProperty|Property]] keyword is used instead of ##[[KeyPgSub|Sub]]## or ##[[KeyPgFunction|Function]]##. For example, let's consider a window class for a windowing system or GUI library.

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties1.bas"}}%%(freebasic)
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:

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties2.bas"}}%%(freebasic)
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 [[KeyPgSub|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:

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties3.bas"}}%%(freebasic)
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 [[KeyPgFunction|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 [[ProPgMemberProcedures|method overloading]], it is possible to specify multiple setters, provided they have different parameter types:

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties4.bas"}}%%(freebasic)
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:

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties5-counter-example.bas"}}%%(freebasic)
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 [[CatPgOpAssignment|assigning]] and [[CatPgOpTypeclass|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:

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties-tui.bas"}}%%(freebasic)
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.

{{anchor name="INDEXED"}}{{fbdoc item="section" value="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:

{{fbdoc item="filename" value="examples/manual/proguide/udt/properties-indexed.bas"}}%%(freebasic)
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.

{{fbdoc item="back" value="CatPgProgrammer|Programmer's Guide"}}
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki



sf.net phatcode