Functions in TYPES

Previous topic - Next topic

fuzzy70

The first time I came across types was in BlitzBasic & once I had worked out how & when to use them it made certain tasks easier to manage.

Now having moved over to GLB I have the option of having functions in types which I am having trouble working out where & how I could use them. I have adjusted to they way GLB uses types & even arrays of types but what I need is an example of what use functions are in types & the benefits.

I do not need any code examples, although could be useful if it helps the explanation, but just some general description of usage etc.

Thanks

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

Ruidesco

It is all a matter of perspective, whether you see your game components as just arrays and bunches of variables or as delimited entities.
For example (probably not the best) you could have a Player type that included all of the player related functionality, such as input reading, player character manipulation and so on.

Slydog

#2
Functions in TYPEs allow you to make your code more English like (insert your language here!).
They allow you to perform functions on your TYPE instances, and keep the logic behind the scenes.
The functions can access the TYPE's member variables and other functions using the 'self' keyword, which gives the functions access to only that instance's data. 
This almost mimics classes as used in other languages (but without other OOP features).

Here's a TYPE I created to handle files and make them easier to work with:
Code (glbasic) Select
CONSTANT FILE_MODE_APPEND = -1
CONSTANT FILE_MODE_WRITE = 0
CONSTANT FILE_MODE_READ = 1

CONSTANT EOF$ = "<EOF>"

TYPE TFile
fh% // File Handle
name$ // File Name
data$ // File Contents
eof% // File is at end?

// Reads entire file into 'self.data$'.  Closes file when finished.
// 'name$' > Optional.  Will use previously set 'self.name$' if blank.
// Returns > [TRUE if succeed | FALSE if fail]
FUNCTION Get%: name$=""
IF name$ <> "" THEN self.name$ = name$
self.data$ = ""
LOCAL line$ = ""
IF self.Open(FILE_MODE_READ)
WHILE ENDOFFILE(self.fh) = FALSE
READLINE self.fh, line$
INC self.data$, line$
WEND
CLOSEFILE self.fh
ELSE
LOG(">FIL:{TFile.Get$      } *** Error Getting File: [" + self.name$ + "] ***")
RETURN FALSE
ENDIF
self.Close()
RETURN TRUE
ENDFUNCTION

// Reads the next line in an already opened file.  Closes file when end is reached.
// Returns > [line data if succeed | 'EOF$' if fail]
FUNCTION GetLine$:
LOCAL line$
IF ENDOFFILE(self.fh)
line$ = EOF$
self.eof = TRUE
self.Close()
ELSE
self.eof = FALSE
READLINE self.fh, line$
ENDIF
RETURN line$
ENDFUNCTION

// Writes 'self.data$' to file
// 'name$' > Optional.  Will use previously set 'self.name$' if blank.
// Returns > [TRUE if succeed | FALSE if fail]
FUNCTION Write%: name$=""
IF name$ <> "" THEN self.name$ = name$
IF self.Open(FILE_MODE_WRITE)
WRITESTR self.fh, self.data$
ELSE
LOG(">FIL:{TFile.Write$    } *** Error Writting File: [" + self.name$ + "] ***")
RETURN FALSE
ENDIF
self.Close()
RETURN TRUE
ENDFUNCTION

// Appends string to end of file.
// 'extra$'> Data to append
// 'name$' > Optional.  Will use previously set 'self.name$' if blank.
// Returns > [TRUE if succeed | FALSE if fail]
FUNCTION Append%: extra$, name$=""
IF name$ <> "" THEN self.name$ = name$
IF self.Open(FILE_MODE_APPEND)
INC self.data$, extra$
WRITESTR self.fh, extra$
ELSE
LOG(">FIL:{TFile.Append$   } *** Error Appending File: [" + extra$ + "] ***")
RETURN FALSE
ENDIF
self.Close()
RETURN TRUE
ENDFUNCTION

// Opens file for procesing.
// 'mode%' > [FILE_MODE_APPEND | FILE_MODE_WRITE | FILE_MODE_READ]
// 'name$' > Optional.  Will use previously set 'self.name$' if blank.
// Returns > [TRUE if succeed | FALSE if fail]
FUNCTION Open%: mode%, name$=""
IF name$ <> "" THEN self.name$ = name$
self.fh = GENFILE()
self.eof = FALSE
IF OPENFILE(self.fh, self.name$, mode) = FALSE
LOG(">FIL:{TFile.Open      } *** Error Opening File: [" + self.name$ + "] ***")
self.eof = TRUE
RETURN FALSE
ENDIF
RETURN TRUE
ENDFUNCTION

// Closes file to further processing
FUNCTION Close%:
IF self.fh >= 0 THEN CLOSEFILE self.fh
self.fh = -1
self.eof = TRUE
ENDFUNCTION

// Checks if file exists
// Returns > [TRUE if exists | FALSE if doesn't]
FUNCTION Exists%:
RETURN DOESFILEEXIST(self.name$)
ENDFUNCTION

// Returns file name portion from a longer file path
// eg. For a 'self.name$' of [C:/Programs/GLBasic/glbasic.exe] will return [glbasic.exe]
// 'slash$' > Optional.  Folder Seperator.  Use if your path uses '\' instead. Uses '/' as default
FUNCTION GetName$: slash$="/"
LOCAL slash%
slash = REVINSTR(self.name$, slash$)
IF slash <=0 THEN RETURN self.name$
RETURN MID$(self.name$, slash+1)
ENDFUNCTION

ENDTYPE


Here's some code that uses this TYPE:
It allows me to use simplified and TYPE specific commands such as 'file.Get()' instead of either having to manage opening and reading files each time you need to, or creating a generic function to do the same such as 'fileContents$ = GetFile(fn$)'.
Code (glbasic) Select
LOCAL file AS TFile
LOCAL fn$ = "scores.dat"

IF NOT file.Open(FILE_MODE_READ, fn$) // Open font's '.fnt' file
RETURN FALSE // Exit and return 'FALSE' if can't open
ENDIF


REPEAT
line$ = file.GetLine$()
. . .
UNTIL file.eof
file.Close()

// Or writing to a file . . .
file.name$ = "scores.dat"
IF NOT file.Exists() THEN RETURN FALSE // Uses file.name$ and returns false if it doesn't exist
file.data$ = "SLYDOG, 12345\nKITTY, 23456\n"
file.Write()
file.Append("FUZZY70, 34567\n")
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Falstaff

I've combined functions in types along with function prototypes to hack in some OOP-like functionality into my game's menu system. Even if we don't get to enjoy the true benefits of OOP (ie inheritance, polymorphism, and encapsulation), we can still 'fake' it to a certain degree.

What I've done is to create a Menu Type, which stores information about the menu, and has a DrawMenu function, which sort of acts like a 'base class method'. It simply draws the menu background, along with whatever buttons are in the menu.

I then have a few function pointers in my Menu Type, that are there so I can optionally 'override' the base DrawMenu function. In one sense it's an ugly hack, because I still have to have my menu code spread out among several other places.. so it's not really encapsulated at all.. but it does let me easily create a new menu, and optionally leave it to draw itself, or code custom drawing routines. I do the same for the logic code, I have a base "RunMenu" function which processes clicks for all the buttons in the menu.. and then a var which can be set to a function prototype to define custom logic code.

So it's a very primitive example of inheritance. I've been thinking about gathering some of my engine design implementation like this and posting it as a little gift to the community..

fuzzy70

Your example makes sense to me Ruidesco  :)

Your example Slydog definitely explains the possible usage of functions in types more than I could have thought of.

Ocean, what you said makes good sense as well, the words "inheritance" & "polymorphism " are the main reason I gave up with C++ as have been unable to find an example that I understood. Luckily thanks to languages like GLB, C++ has taken a backseat & less of a importance to me.

Falstaff, I can see the uses of the Menu Type you mentioned & can understand how that would work.

While I do not have anything at present that would benefit from using functions in types I can safely say I will in the near future, a couple of ideas are floating around my mind now that could possibly make use of the functionality they provide.

Thank you all very much for your help, thats another part of GLB understood better now  :D

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)