Using Extended Types

Previous topic - Next topic

MrTAToad

With the imminent release of V8, I thought it might be an idea to have a discussion on extended types. 

As you all know types can be used to group variables into an abstract object to make it easier to manipulate information for a specific purpose - instead of having the variables defined all around the place...

It is therefore a logical step to be able to group functions into a type - this allows functions to be created to the specific type and to allow easy manipulation of its variables.  It keeps things tidy, aid easier code re-use and help debugging too.  Extended types are just TYPE's with functions in them.

Extended types could be described as being like a C++ class, but with some differences :


  • Each type has to have unique function names
  • No private or protected variables or functions - this mean any function (both within and outside a type) can call a function (or variables) within a type

Self
This command is needed to access the variables within a type - without this you could get some strange and complicated compiler errors.

Name Defining
As GLBasic will not allow types to use duplicate function names, I find it best to distinguish between standard types and extended types by proceeding the function name with a small 't' for standard type or a capital 'T' for a type with functions.  The type name is then used following by the function name, with the two seperated by an underscore '_'

Function and Variable Access
As functions and variables can be directly accessed, it would be best not to do so, and instead have helper functions.  There are many advantages of doing this : easier to debug, put all validation code into one place and the knowledge that you wont be causing extra problems.

Constructor and Destructor
As there isn't the ability to call a function when the type is created or destroyed, the former can be done by calling a function (I usually append Initialise to the prefix) just after the function is defined.

The Types
A standard type could be :

Code (glbasic) Select

TYPE tSomething
    a%
    b
    c$
ENDTYPE


whilst an extended type can be defined as :

Code (glbasic) Select
TYPE TDot
value
FUNCTION TDot_Initialise%:
self.value=123.45
ENDFUNCTION
ENDTYPE

TYPE TSomething
a%
b
c$
dot AS TDot

FUNCTION TSomething_Initialise AS TDot:
dot.TDot_Initialise()
RETURN self.dot
ENDFUNCTION
ENDTYPE

LOCAL some AS TSomething
LOCAL _dot AS TDot

_dot=some.TSomething_Initialise()
DEBUG _dot.value


This example returns the TDot extended type as created in the TSomething class

When defining parameters for functions, be aware the the variables aren't in the local space (yet :) ), so something like :

Code (glbasic) Select
TYPE TDot
value
FUNCTION TDot_Initialise%:x%,y%
self.value=x%*y%*1.2
ENDFUNCTION
ENDTYPE

TYPE TSomething
a%
b
c$
dot AS TDot

FUNCTION TSomething_Initialise AS TDot:x%,y%
dot.TDot_Initialise()
RETURN self.dot
ENDFUNCTION
ENDTYPE

GLOBAL x%,y%
LOCAL some AS TSomething
LOCAL _dot AS TDot

_dot=some.TSomething_Initialise(1,2)
DEBUG _dot.value


will produce the following warnings :

Quote
"Test.gbas"(20) warning : variable already exists : x
"Test.gbas"(20) warning : variable already exists : y

This shows that you can modify a passed type :

Code (glbasic) Select
TYPE TDot
value
FUNCTION TDot_Initialise%:x%,y%
self.value=x%*y%*1.2
ENDFUNCTION

FUNCTION TDot_Display%:
DEBUG self.value+"\n"
ENDFUNCTION
ENDTYPE

TYPE TSomething
a%
b
c$
dot AS TDot

FUNCTION TSomething_Initialise:d AS TDot
self.dot=d

self.dot.TDot_Initialise%(1,2)
self.dot.TDot_Display()

d.TDot_Initialise(6,7)
ENDFUNCTION
ENDTYPE

GLOBAL x%,y%
LOCAL some AS TSomething
LOCAL _dot AS TDot

_dot.TDot_Initialise(2,3)
_dot.TDot_Display()

some.TSomething_Initialise(_dot)
_dot.TDot_Display()


And, of course, they can be in arrays.  This is handy for, say, multiplay games, as you wont need to pass things like player indexes to functions :

Code (glbasic) Select
TYPE TDot
value
FUNCTION TDot_Initialise%:x%,y%
self.value=x%*y%*1.2
ENDFUNCTION

FUNCTION TDot_Display%:
DEBUG self.value+"\n"
ENDFUNCTION
ENDTYPE

TYPE TSomething
a%
b
c$
dot AS TDot

FUNCTION TSomething_Initialise:d AS TDot
self.dot=d

self.dot.TDot_Initialise%(1,2)
self.dot.TDot_Display()

d.TDot_Initialise(6,7)
d.TDot_Display()
ENDFUNCTION
ENDTYPE

GLOBAL x%,y%
LOCAL some[] AS TSomething
LOCAL _dot AS TDot

DIM some[65]
some[0].TSomething_Initialise(_dot)


ADDRESSOF
ADDRESSOF can't be used with a function in an extended type.   This shouldn't matter as all the function would be doing is comparing the contents of two normal types.

Multiple Files
With V8.050 upwards, types can be created in one file and used in another.

Hatonastick

Thanks for posting this explanation as it clears up one or two questions I had.
Mat. 5: 14 - 16

Android: Toshiba Thrive Tablet (3.2), Samsung Galaxy Tab 2 (4.1.2).
Netbook: Samsung N150+ Netbook (Win 7 32-bit + Ubuntu 11.10).
Desktop: Intel i5 Desktop with NVIDIA GeForce GTX 460 (Win 8.1 64-bit).

Slydog

QuoteWith V8.050 upwards, types can be created in one file and used in another.

But can a type defined in one file access another type defined in another file?
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Hatonastick

Quote from: Slydog on 2010-Jul-26
QuoteWith V8.050 upwards, types can be created in one file and used in another.

But can a type defined in one file access another type defined in another file?
Only way to find out is to try it. :)
Mat. 5: 14 - 16

Android: Toshiba Thrive Tablet (3.2), Samsung Galaxy Tab 2 (4.1.2).
Netbook: Samsung N150+ Netbook (Win 7 32-bit + Ubuntu 11.10).
Desktop: Intel i5 Desktop with NVIDIA GeForce GTX 460 (Win 8.1 64-bit).

Ian Price

These appear to be like "Methods" in BlitzMax - these were invaluable OOP routines for me, back when I used BMax.

Nice examples MrTaToad :)
I came. I saw. I played.

MrTAToad

QuoteBut can a type defined in one file access another type defined in another file?
No, you can't.

With this in source "test2" :

Code (glbasic) Select
GLOBAL moo%

TYPE B
b
g AS Tg

FUNCTION foo: a%
DEBUG "Here\n"
self.g.Tg_moo()
ENDFUNCTION
ENDTYPE


and this in source "test3" :

Code (glbasic) Select
TYPE Tg
FUNCTION Tg_moo%:
ENDFUNCTION
ENDTYPE


You get "error : call to undefined function : B__g.Tg_moo".  Forward access to extended types is only granted from the main program file and main program.  To get around this you would need to define a local variable (with the extended type) and pass it to the required one.

MrTAToad

#6
In 8.054, TYPES in source files can now access TYPEs defined in other files.

In 8.064, function names dont have to be different from functions in other types