Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
EnTerr
Roku Guru

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:
function isString(x):
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 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").

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").
0 Kudos
2 REPLIES 2
TheEndless
Channel Surfer

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:
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)
EnTerr
Roku Guru

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?
0 Kudos