Comparing types by using reflection

You can compare the types of two objects in several ways.

You can use the equality (==) operator to test types. However, the equality operator is almost always inappropriate because it returns true only for exact type matches. This operator returns false if one type is a subtype of the other or if the types are in different packages.

Use the sourceType.Type.isAssignableFrom(destinationType) method to determine whether types are compatible for assignment. This method considers the possibility of subtypes, such as subclasses, which the equality operator does not. The method determines if the destination type argument is either the same as, or a superclass or superinterface of the source type. The sourceType.Type.isAssignableFrom(destinationType) method examines only the supertypes of the source type. Although Gosu statements can assign a value of one unrelated type to another by using coercion, the isAssignableFrom method always returns false if coercion of the data is necessary. For example, although Gosu can use coercion to convert boolean to String or String to boolean, using those types with the isAssignableFrom method returns false.

Gosu provides a variant of the functionality that tests assignability with the Gosu typeis operator. The operator typeis operates between an object and a type. The method type.Type.isAssignableFrom(...) operates between a type and another type.

For example, paste the following code into the Gosu Scratchpad.

var str: String = "hello" // Explicit declaration of "String" is optional, but is shown for clarity
var objString: Object = "hello"
var objDouble: Object = 2.345
var bool: Boolean = true

print("Typeof str: " + (typeof str).Name)
print("Typeof objString: " + (typeof objString).Name)
print("Typeof objDouble: " + (typeof objDouble).Name)

// The following line would be a compile error! String is not a subtype or supertype of Boolean.
// tempTypeIs = (bool typeis String)

print("String typeis Object: " + (str typeis Object) )

// Notice the different run time behavior of these two lines,
// Note that both objString and obj3 are Object at compile time,
// but have different run-time types
print("Object objString typeis String: " + (objString typeis String) )
print("Object objDouble typeis String: " + (objDouble typeis String) )
print("Boolean assignable from String: " + (typeof str).isAssignableFrom((typeof bool)))
print("String assignable from Boolean: " + (typeof bool).isAssignableFrom((typeof str)))
print("Object assignable from String: " + ((Object).Type.isAssignableFrom( String )) )
print("String assignable from Object: " + ((String).Type.isAssignableFrom( Object )) )

// For typical use cases, DO NOT compare types with the == operator
// Using == to compare types returns false if one is a subtype.
// Instead, typically it is best to use the 'typeis' operator
print("Compare a string to object using ==: " + ( (typeof str) == Object ) )

This code prints the following output.

Typeof str: java.lang.String
Typeof objString: java.lang.String
Typeof objDouble: java.lang.Double
String typeis Object: true
Object objString typeis String: true
Object objDouble typeis String: false
Boolean assignable from String: false
String assignable from Boolean: false
Object assignable from String: true
String assignable from Object: false
Compare a string to object using ==: false