EnTerr
Roku Guru
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-08-2014
07:10 PM
How to check variable type, "the right way"
I just realized there is a better way to check the type of a variable (or expression, in general), than to check the string returned by `type()` - and that is to try `getInterface(var, <interface-needed>)`. I don't think i invented this wheel, since a search found it in one code example, although without explanation or justification in the documentation - nor in the forums. But much more often i have seen snippets like `... type(var) = "String" or type(var) = "roString" ...`. So here goes discussion on it.
Sometimes you get a structure that might contain mix of strings, numbers, booleans (say from JSON/XML parse)- and it is not clear which is what, so need to peek and act accordingly. You can do "type(expr)" and that returns the type as a string. String may vary, based on whether the value is boxed or not (e.g. "Boolean" vs "roBoolean", "String" vs "roString", "Float" vs "roFloat"). It gets egregious in the case of integers, where it may be "Integer", "roInt" or "roInteger" - and seems that at some point the return of boxed value was "roInteger" but later changed to "roInt", yet there are still corner cases where "roInteger" pops out. The thought of text returned changing bothers me.
The alternative approach is: ask the value if it supports particular interface we need, e.g. `getInterface(42, "roInt")`. If it returns something valid (non-invalid), it is the type we want. We can write thin wrappers around that and turn it to utility functions like so:
The use is kinda obvious but here is example:
There are some odds and ends to discuss, like performance (which is faster? should test) and there not being ifInvalid (there are 2 type()s, "Invalid" and "roInvalid").
Sometimes you get a structure that might contain mix of strings, numbers, booleans (say from JSON/XML parse)- and it is not clear which is what, so need to peek and act accordingly. You can do "type(expr)" and that returns the type as a string. String may vary, based on whether the value is boxed or not (e.g. "Boolean" vs "roBoolean", "String" vs "roString", "Float" vs "roFloat"). It gets egregious in the case of integers, where it may be "Integer", "roInt" or "roInteger" - and seems that at some point the return of boxed value was "roInteger" but later changed to "roInt", yet there are still corner cases where "roInteger" pops out. The thought of text returned changing bothers me.
The alternative approach is: ask the value if it supports particular interface we need, e.g. `getInterface(42, "roInt")`. If it returns something valid (non-invalid), it is the type we want. We can write thin wrappers around that and turn it to utility functions like so:
function isString(x):The check is so short, it does not really need to be pulled to function but if one want to have leeway to change their mind later (i.e. "i want to use type()=string here").
return getInterface(x, "ifString") <> invalid
end function
function isInteger(x):
return getInterface(x, "ifInt") <> invalid
end function
function isFloat(x):
return getInterface(x, "ifFloat") <> invalid
end function
function isDouble(x):
return getInterface(x, "ifDouble") <> invalid
end function
function isBoolean(x):
return getInterface(x, "ifBoolean") <> invalid
end function
The use is kinda obvious but here is example:
BrightScript Debugger> ? isBoolean(false), isBoolean(7 < 1), isBoolean(5)
true true false
BrightScript Debugger> ? isFloat(1.2), isFloat(5#), isFloat("5")
true false false
BrightScript Debugger> ? isString(""), isString(invalid)
true false
There are some odds and ends to discuss, like performance (which is faster? should test) and there not being ifInvalid (there are 2 type()s, "Invalid" and "roInvalid").
2 REPLIES 2

TheEndless
Channel Surfer
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-08-2014
09:04 PM
Re: How to check variable type, "the right way"
I don't think it's safe to check for just the interface, as there are other types that may implement the interface, but not be the base type. roUniversalControlEvent comes to mind, as it implements the ifInt interface for some reason. Also an roDateTime, inexplicably, returns invalid for "ifDateTime". Here are the type checks I have in my code:
FWIW, the web server SDK example (http://sourceforge.net/projects/rokusdk ... server.zip) has a Types.brs file that includes a similar method for type checking.
Function IsXmlElement(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifXMLElement") <> invalid
End Function
Function IsFunction(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifFunction") <> invalid
End Function
Function IsBoolean(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifBoolean") <> invalid
End Function
Function IsInteger(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifInt") <> invalid And (Type(value) = "roInt" Or Type(value) = "roInteger" Or Type(value) = "Integer")
End Function
Function IsFloat(value As Dynamic) As Boolean
Return IsValid(value) And (GetInterface(value, "ifFloat") <> invalid Or (Type(value) = "roFloat" Or Type(value) = "Float"))
End Function
Function IsDouble(value As Dynamic) As Boolean
Return IsValid(value) And (GetInterface(value, "ifDouble") <> invalid Or (Type(value) = "roDouble" Or Type(value) = "roIntrinsicDouble" Or Type(value) = "Double"))
End Function
Function IsList(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifList") <> invalid
End Function
Function IsArray(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifArray") <> invalid
End Function
Function IsAssociativeArray(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifAssociativeArray") <> invalid
End Function
Function IsString(value As Dynamic) As Boolean
Return IsValid(value) And GetInterface(value, "ifString") <> invalid
End Function
Function IsDateTime(value As Dynamic) As Boolean
Return IsValid(value) And (GetInterface(value, "ifDateTime") <> invalid Or Type(value) = "roDateTime")
End Function
Function IsValid(value As Dynamic) As Boolean
Return Type(value) <> "<uninitialized>" And value <> invalid
End Function
FWIW, the web server SDK example (http://sourceforge.net/projects/rokusdk ... server.zip) has a Types.brs file that includes a similar method for type checking.
My Channels: http://roku.permanence.com - Twitter: @TheEndlessDev
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
Instant Watch Browser (NetflixIWB), Aquarium Screensaver (AQUARIUM), Clever Clocks Screensaver (CLEVERCLOCKS), iTunes Podcasts (ITPC), My Channels (MYCHANNELS)
EnTerr
Roku Guru
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
03-09-2014
03:11 AM
Re: How to check variable type, "the right way"
"TheEndless" wrote:
I don't think it's safe to check for just the interface, as there are other types that may implement the interface, but not be the base type. roUniversalControlEvent comes to mind, as it implements the ifInt interface for some reason. Also an roDateTime, inexplicably, returns invalid for "ifDateTime".
Since i am fan of duck typing, this behavior of roUniversalControlEvent does not bother me a bit: it walks like a duck (implements "ifInt") and quacks like a duck (implements "ifIntOps"), therefore for all practical purposes it is a duck. The way i see it, i ask "isInteger()" because i am planning to do something integer-y to it, not because i want to verify what its "type()" name is - in that sense roUniversalControlEvent is an int: any operation i can do on int i can do on it too.
But if you think otherwise, i have some counter-examples for your functions too: roXmlList is an ifList, roList is an ifArray, roPath is an ifString. Me, i am fine with isArray(roList) = true etc, since if i ask roList to do something array-ey, it will.
Also i wouldn't do isValid() check first - i think using un-initialized variable should make those functions bomb with an error message because almost certainly that's program error and should not be let to slip quietly (OTOH, invalid works fine with getInterface, no worries there). I understand having different opinion on this one though.
getInterface(roDateTime, "ifDateTime") failing - that is a bug, since documentation says roDateTime implements ifDateTime. Have you contacted the proper authorities about that?