I hope this is not too much of a weird question but is there a way to get the names of the variable in a TYPE?
For example:
TYPE TList
apple
orange
potatoe
ENDTYPE
GLOBAL list as TList
list.apple = 8
list.orange = 5
list.potatoe = 12
DEBUG list.variable_name[0], 0, 0
Output: apple
No, I dont see it being possible....
Ok. :zzz:
For small platforms that would mean, that each variable also would have to store a string containing the name.
That would be some sort of meta programming language, which is usually only available for interpreted languages. The binary does not know of any names anymore. It's just a set of address numbers.
Not totally related but I keep using variables called "type" in glbasic... Always throws me off since I use them a lot in PHP and other languages :-)
TYPE is a keyword. Use typ, tp or kind instead?
Yes, I end up using typ instead but that is swedish and it feels a bit strange in programming :-)
I'm not sure what your specific needs are by looking at your example code, but a dictionary concept may help you.
(Apples, Oranges, and Potatoes? . . . it sounds like one awful recipe! :noggin:)
Here's a dictionary library I created, but have never used beyond simple testing.
Check the example usage at the end where I tried to apply it to your sample code.
BTW, just to clarify, does GLB have a 'null' concept for integer or float data types?
I've been using a 'BLANK' constant for my 'null' detection, but if you happened to use the value of 'BLANK' for a dictionary item, it could cause havoc.
ie. i'm trying to return a 'null' if a 'Get' call can't find the item.
CONSTANT BLANK% = -12345
TYPE TDictionaryItem
name$
value
ENDTYPE
TYPE TDictionary
table[] AS TDictionaryItem
FUNCTION Clear:
DIM self.table[0]
ENDFUNCTION
FUNCTION Add: name$, value
// If 'name$' already exists, call 'Set' instead
IF self.Exists(name$)
self.Set(name$, value)
RETURN
ENDIF
LOCAL item AS TDictionaryItem
item.name$ = name$
item.value = value
DIMPUSH self.table[], item
ENDFUNCTION
FUNCTION Get: name$, defaultValue=BLANK
LOCAL rv# = defaultValue
FOREACH item IN self.table[]
IF item.name$ = name$
rv = item.value
BREAK
ENDIF
NEXT
RETURN rv
ENDFUNCTION
FUNCTION Set%: name$, value
LOCAL hx%
// If the 'name$' doesn't exist in the table, call 'Add' instead
IF NOT self.Exists(name$)
self.Add(name$, value)
RETURN
ENDIF
FOREACH item IN self.table[]
IF item.name$ = name$
item.value = value
BREAK
ENDIF
NEXT
ENDFUNCTION
FUNCTION Exists%: name$
FOREACH item IN self.table[]
IF item.name$ = name$
RETURN TRUE
ENDIF
NEXT
RETURN FALSE
ENDFUNCTION
ENDTYPE
LOCAL dictionary AS TDictionary
dictionary.Clear()
dictionary.Add("apple", 8)
dictionary.Add("orange", 5)
dictionary.Add("potatoe", 12)
DEBUG "table name at pos 0: " + dictionary.table[0].name$ + "\n"
DEBUG "apple: " + dictionary.Get("apple") + "\n"
DEBUG "banana: " + dictionary.Get("banana") + "\n\n"
dictionary.Set("apple", 99)
DEBUG "apple: " + dictionary.Get("apple") + "\n"
dictionary.Add("apple", 77) // 'apple' aleardy exists, so library just 'Sets' the existing 'apple' to 77
DEBUG "apple: " + dictionary.Get("apple") + "\n\n"
DEBUG "pear: " + dictionary.Get("pear") + "\n"
dictionary.Set("pear", 44) // 'pear' doesn't already exist, so library 'Adds' it instead, and sets it to 44
DEBUG "pear: " + dictionary.Get("pear") + "\n"
Output:
table name at pos 0: apple
apple: 8
banana: -12345
apple: 99
apple: 77
pear: -12345
pear: 44
[Edit] The 'Add' and 'Set' seem to do the same thing (Add: If exists set it instead, Set: Add it if doesn't exist) but I kept them separate for the usage clarity, and in case you want to handle them differently by modifying the code. I just did it this way to make my game more robust so it wont mess up if I expect something to be in the library and it isn't. The 'proper' way to do the 'Add' would be to return FALSE if the item exists and TRUE if it doesn't, and 'Set' would return FALSE if the item doesn't exist, or else set the item and return TRUE.
Cheers for useful dictionary code although it is similar to how I manage data, that is to initialize values in an array. :P
The reason for metadata look up is because I like to use types just to store a lot of constants. ;)
This example demonstrates how I can efficiently import constants without initialization or function look-up. :rtfm:
// CONSTANT COLORS_RED = 0x0000ff // old way
TYPE _colors
none = -1
white = 0xffffff
black = 0x000000
red = 0x0000ff
green = 0x00ff00
blue = 0xff0000
ENDTYPE
main_colors()
FUNCTION main_colors:
LOCAL colors AS _colors
CLEARSCREEN colors.white
DRAWRECT 0, 0, 320, 15, colors.red
DRAWRECT 0, 20, 320, 15, colors.green
DRAWRECT 0, 40, 320, 15, colors.blue
SHOWSCREEN
MOUSEWAIT
ENDFUNCTION
This leads to a missing feature of GLB: enumerations
I have about a dozen places in my game where I would have used them.
They keep the code clean when used properly, plus allow you to limit inputs to functions by specifying an ENUM variable instead of a data type.
In C#:
enum Colours {
none = -1,
white = 0xffffff,
black = 0x000000,
red = 0x0000ff,
green = 0x00ff00,
blue = 0xff0000
}
rect_colour = Colours.red;
In GLB?:
ENUM Colours% // The '%' specifies that values in this enum are integer
none = -1
white = 0xffffff
black = 0x000000
red = 0x0000ff
green = 0x00ff00
blue = 0xff0000
ENDENUM
DRAWRECT 0, 0, 320, 15, Colours.red
// . . or in a function call
FUNCTION DrawRectange: x, y, w, h, colour AS Colours
IF colour = Colours.none THEN colour = Colours.white
DRAWRECT x, y, w, h, colour
ENDFUNCTION
BTW, I currently use the 'CONSTANT' method, your 'old way'.