Checking Type() is case sensitive - undocumented?

I’ve noticed that when I check the Type of a variable, it’s case sensitive (at least for String/roString). Example:

IF Type(id) = "String" OR Type(id) = "roString" ' Could be either one, depending on custom id or not. ' Otherwise id must be a dummy temp blocker while a diff Mon is moving toward sq
	moveMon(TRUE, sy.mr[id], y, x, y2, x2, r2, rm, aa, sy, mAA, cAA) ' Sends tele as TRUE, Mon as sy.mr[id]
ELSE ? "moveAllMon(): At y" y ", x" x ", rm" rm ", trying to be moved: " Type(id) ' It's unlikely a teleCheck() occurs for sq Mon is stepping to, but could happen if tele just turned on
END IF

If I don’t capitalize the S in String and roString, it will miss it and think it doesn’t match!

I haven’t noticed whether this is also true for Integer/roInteger, Array, etc

Type() returns a string. Directly comparing two strings is always case-sensitive. If you want it to be case-insensitive, you’ll need to make sure the case is the same on both sides using UCase or LCase.

For example:

If LCase(Type(id)) = "string" Or UCase(Type(id)) = "ROSTRING" Then
...

Okay, that’s helpful to know.

Maybe section 3.7.9 “Comparison Operators” under the strings side for =, could include “true if strings A and B are identical (case sensitive)”

“Komag” wrote:
Okay, that’s helpful to know.

Maybe section 3.7.9 “Comparison Operators” under the strings side for =, could include “true if strings A and B are identical (case sensitive)”
I’m honestly not sure that’s necessary. I guess it couldn’t hurt, but I can’t think of any programming languages that have case-insensitive direct string comparisons.

I’m sure you’re right. I’ve never programmed before, I don’t know any languages (BrightScript is my first!) (except for a tiny touch of Lua last year for a mod project for Legend of Grimrock)

best bet is to use lcase to wrap any string comparisons where case might be an issue or where you have been up for 48 hours programming and might not remember the proper case for something ( is it roUrlEvent or roURLEvent…‘yawn’ i’ll just lcase it… )

if lcase(type(myvariable))=“roarray”

if lcase(type(msg))=“rourlevent”

  • Joel

hmm, “rourlevent” sounds like Rourl Event, some sort of lion roar :mrgreen:

Thanks for the tips! :slightly_smiling_face:

“RokuJoel” wrote:
best bet is to use lcase to wrap any string comparisons
If only someone else had suggested that… :wink:

Lol.

Oops.

  • Joel

Personally i recommend doing the type check with *getInterface(val, "ifString") <> invalid* instead. It’s shorter and faster (just ran some tests - at least 2x faster in general, can be 7x faster if type(val)=“roString” in particular).

Best however will be to define a test function for that and use it. That way code is most readable and fn can be updated in the future (or switch between the three different approaches in this thread). Here is mine:

function isString(val):
    return getInterface(val, "ifString") <> invalid
end function

“EnTerr” wrote:
Personally i recommend doing the type check with *getInterface(val, "ifString") <> invalid* instead. It’s shorter and faster (just ran some tests - at least 2x faster in general, can be 7x faster if type(val)=“roString” in particular).

Best however will be to define a test function for that and use it. That way code is most readable and fn can be updated in the future (or switch between the three different approaches in this thread). Here is mine:

function isString(val):
    return getInterface(val, "ifString") <> invalid
end function

Since the original post was about case sensitivity, it’s worth noting that this method is case-insensitive.

“TheEndless” wrote:
Since the original post was about case sensitivity, it’s worth noting that this method is case-insensitive.
You mean the function getInterface() is case-insensitive regarding its 2nd argument? That it is, yes - can call with “iFstRing”.

“EnTerr” wrote:
Personally i recommend doing the type check with *getInterface(val, "ifString") <> invalid* instead. It’s shorter and faster (just ran some tests - at least 2x faster in general, can be 7x faster if type(val)=“roString” in particular).

Best however will be to define a test function for that and use it. That way code is most readable and fn can be updated in the future (or switch between the three different approaches in this thread). Here is mine:

function isString(val):
    return getInterface(val, "ifString") <> invalid
end function

But would calling the function lose some of the snappiness? I mean if this is done many times per second, wouldn’t it be faster to keep it direct, just use *getInterface(val, "ifString") <> invalid*? I have a LOT of functions, and I’m beginning to wonder if the game has to do a big search through all the functions to find the one with the right name and whether that takes time, sort of like looking up a key/value pair in an AA with . operator.

EDIT - This will work to check that it’s either a String or a roString?

“Komag” wrote:
EDIT - This will work to check that it’s either a String or a roString?
Yes. It will work with all* string types in B/S.

But would calling the function lose some of the snappiness? I mean if this is done many times per second, wouldn’t it be faster to keep it direct, just use *getInterface(val, "ifString") <> invalid*? I have a LOT of functions, and I’m beginning to wonder if the game has to do a big search through all the functions to find the one with the right name and whether that takes time, sort of like looking up a key/value pair in an AA with . operator.
No on “big search”. Tiny penalty for calling a global function (function myFun() ...) or local function (localVar = function()... end function: ...: localVar(..)). No runtime lookup by name is needed, it was done during compilation.

The convenience of having a type-check function greatly outweighs the small slowdown - easy to read, you can change implementation, less risk of typos (like proper capitalization, har-har). To put it in perspective, even as a function call isString(id), it is still faster than LCase(Type(id)) = "string" Or UCase(Type(id)) = "ROSTRING" . BUt are TheEndless and RokuJoel - two BrS-experienced developers - losing sleep over that check code speed? No - and neither should you.

(*) all 6 of them, let me flourish some arcane knowledge here :laughing:

Thanks! I appreciate the insights, good to know that calling functions is fast. I’ll change my Type() checks.

What about roArray, roBoolean, and Integer and roInteger?

I’m assuming:
getInterface(val, “ifArray”) <> invalid
getInterface(val, “ifBoolean”) <> invalid
getInterface(val, “ifInt”) <> invalid

?

The section about GetInterface is not clear to me yet:

7.3 GetInterface(object as Object, ifname as String) as Interface
Each BrightScript Component has one or more interfaces. This function returns a value of type “Interface”.
Note that generally BrightScript Components allow you to skip the interface specification. In which case, the appropriate interface within the object is used. This works as long as the function names within the interfaces are unique.

“Komag” wrote:
What about roArray, roBoolean, and Integer and roInteger?

I’m assuming:
getInterface(val, “ifArray”) <> invalid
getInterface(val, “ifBoolean”) <> invalid
getInterface(val, “ifInt”) <> invalid
Generally speaking, yes, but I’ve apparently run into at least one occasion where the interface check didn’t work as expected, resulting in me having these utility functions:

Function IsBoolean(value As Dynamic) As Boolean
    Return GetInterface(value, "ifBoolean") <> invalid
End Function

Function IsInteger(value As Dynamic) As Boolean
    Return 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 (GetInterface(value, "ifFloat") <> invalid Or (Type(value) = "roFloat" Or Type(value) = "Float"))
End Function

Function IsDouble(value As Dynamic) As Boolean
    Return (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 GetInterface(value, "ifList") <> invalid
End Function

Function IsArray(value As Dynamic) As Boolean
    Return GetInterface(value, "ifArray") <> invalid
End Function

Function IsAssociativeArray(value As Dynamic) As Boolean
    Return GetInterface(value, "ifAssociativeArray") <> invalid
End Function

Function IsString(value As Dynamic) As Boolean
    Return GetInterface(value, "ifString") <> invalid
End Function

Function IsDateTime(value As Dynamic) As Boolean
    Return (GetInterface(value, "ifDateTime") <> invalid Or Type(value) = "roDateTime")
End Function

Function IsXmlElement(value As Dynamic) As Boolean
    Return GetInterface(value, "ifXMLElement") <> invalid
End Function

Function IsFunction(value As Dynamic) As Boolean
    Return GetInterface(value, "ifFunction") <> invalid
End Function

Function IsHttpAgent(value As Dynamic) As Boolean
    Return GetInterface(value, "ifHttpAgent") <> invalid
End Function

Note that roDateTime, in particular, doesn’t appear to actually implement the ifDateTime interface… not sure what that’s all about.

“TheEndless” wrote:
Generally speaking, yes, but I’ve apparently run into at least one occasion where the interface check didn’t work as expected, resulting in me having these utility functions:
The way you check in isFloat() and isDouble() might be a case of wearing both belt and suspenders (which you have been observed to, occasionally :face_with_tongue: ).
Your isInteger() logic is more interesting and i wonder why. Was it that you suspected some other type may be coerced into integer by GetInterface?

Note that roDateTime, in particular, doesn’t appear to actually implement the ifDateTime interface… not sure what that’s all about.
The newly hatched FindMemberFunction (thanks… RokuKC?) to the rescue:

BrightScript Debugger> ? FindMemberFunction(CreateObject("roDateTime"), "asSeconds")
<Interface: ifRoDateTime>

Aha! Seems the interface currently is named ifRoDateTime and not ifDateTime. I wouldn’t put both my eggs in ifRoDateTime’s basket though - naming seems to be a bug that RokuCo may fix and bring in line with teh documentation.

“EnTerr” wrote:
Your isInteger() logic is more interesting and i wonder why. Was it that you suspected some other type may be coerced into integer by GetInterface?
I believe this is exactly it, because one of the roXXXEvents (don’t recall which) implements the ifInt interface, which caused an IsInteger() check to return True, which while technically correct I suppose, is not what I was after.

“EnTerr” wrote:

“Komag” wrote:
EDIT - This will work to check that it’s either a String or a roString?
Yes. It will work with all* string types in B/S.

Note that there are components other than String / roString that implement the ifString interface.

This may be academic in your case, but if your intent is to truly identify string objects that have regular string object behavior I would advise doing the lcase(type(x)) = “string” etc. comparison as TheEndless demonstrated.

Similarly for ifInt et al.

“RokuKC” wrote:
Note that there are components other than String / roString that implement the ifString interface.

This may be academic in your case, but if your intent is to truly identify string objects that have regular string object behavior I would advise doing the lcase(type(x)) = “string” etc. comparison as TheEndless demonstrated.

Similarly for ifInt et al.
Mmmm, good point.
I see roPath does ifString but who does ifInt (but roInt)?

Personally per my Python exposure i am fan of “duck typing” (“if it walks like a duck and swims like a duck and quacks like a duck, i call that [type] a duck”). In other words if the type can perform the duties of a String, for all practical purposes it is a string. Which i can probably check if the value can/has ifStringOps, to be more precise.

It would be very, very rare (methinks) that someone will ever need the real type(val) - and then they’d probably want to check type(val, 3) too.

PS. ultimateley, the advantage of DIY “isString()” is it can be fine tuned to one’s needs