Dynamic type

In a variable declaration or function parameter, you can declare the type as the type Dynamic. The Dynamic type permits any type of object to be assigned to that variable. The fully qualified name is dynamic.Dynamic. At first glance, this might be similar to using the Object type, which is the base class of all reference types. However, there are important differences.

By declaring the Dynamic type for the variable or function argument, you can programmatically access any property or method without requiring compile-time confirmation of its existence. For example, get the Name or Age property from an object even if it does not exist at compile time. In contrast, if you use the Object type, the Gosu compiler validates any property or method on the Object class itself, which does not have many properties or methods.

On its own, the dynamic feature can be used for dynamic programming styles where property names and method names may not be known at compile type. To dynamically get properties, set properties, and invoke methods, you can optionally implement special methods on the target class directly on the declaring class or with a Gosu enhancement.

Warning: Use dynamic language features judiciously because misuse can hide errors that the Gosu editor cannot catch at compile type. For example, if you misspell a property or method name, there is no compiler error but run time errors can occur.

The following table lists the special methods you may implement on classes who objects are accessed by variables declared with the dynamic.Dynamic type. In the following table, the term UNHANDLED refers to value gw.lang.reflect.IPlaceholder.UNHANDLED.

Dynamic type method name

Description

$getProperty

Gets a property by its name specified as an argument. If the property is unknown, return the value UNHANDLED. If you return UNHANDLED, Gosu calls the $getMissingProperty method, which must exist or Gosu throws an exception.

$getMissingProperty

Similar to $getProperty, but Gosu only calls this method if the type does not explicitly declare the property.

Gosu calls this method if some code sets a property and either of the following is true:

  • The $getProperty method is absent and the property is not defined explicitly on the class
  • The $getProperty method exists and it returned UNHANDLED.

$setProperty

Sets a property by its name specified as an argument, with the value in the second argument. If the property is unknown, return the value UNHANDLED. If you return UNHANDLED, Gosu calls the $setMissingProperty method, which must exist or Gosu throws an exception.

$setMissingProperty

Similar to $setProperty, but Gosu only calls this method if the type does not explicitly declare the property.

Gosu calls this method if some code sets a property and either of the following is true:

  • The $setProperty method is absent and the property is not defined explicitly on the class
  • The $setProperty method exists and it returned UNHANDLED.

$invokeMethod

Invokes a method by its name specified as an argument, with the parameter list in the second argument as an array of Object instances. If the method is unknown or the arguments have the wrong number or types, return the value UNHANDLED. If you return UNHANDLED, Gosu calls the $invokeMissingMethod method, which must exist or Gosu throws an exception.

$invokeMissingMethod

Similar to $invokeMethod, but Gosu only calls this method if the type does not explicitly declare the method.

Gosu calls this method if some code invokes a method and either of the following is true:

  • The $invokeMethod method is absent and the method with matching argument number and types is not defined explicitly on the class
  • The $invokeMethod method exists and it returned UNHANDLED.

The following example defines a simple object with a dynamic property getter method. In the example, the $getProperty method handles two property names explicitly, and then returns UNHANDLED for any other property names. Note that for the unhandled property name, Gosu automatically calls the $getMissingProperty method.

In real-world code, the $getProperty method might get the value from a java.util.Map, from a related subobject, from a calculation, or even from an external system:

package doc.example

uses gw.lang.reflect.IPlaceholder
uses dynamic.Dynamic

class DynamicGetter {

  // Handle any property name. Dynamically return
  // values for two values, and return UNHANDLED for others
  public function $getProperty(fieldName: String): Object {
    print("$getProperty called with field: " + fieldName)

    if (fieldName == "StreetAddress") {
      return "123 Main Street"
    } else if (fieldName == "FirstName") {
      return "John"
    } else {
      return IPlaceholder.UNHANDLED
    }
  }

  // Handle any unhandled requests for missing property names
  public function $getMissingProperty(fieldName: String): Object {
    print("$getMissingProperty called with field: " + fieldName)
    return ("fakeValue")
  }
}

The following code uses the dynamic object and gets a property from it:

uses doc.example.DynamicGetter
uses dynamic.Dynamic

var obj : Dynamic = new DynamicGetter()

print("---")
print("Dynamically get a known property...")
print("RESULT = " + obj.StreetAddress)

print("---")
print("Dynamically get a missing property...")
print("RESULT = " + obj.OtherField)

This code prints the following:

---
Dynamically get a known property...
$getProperty called with field: StreetAddress
RESULT = 123 Main Street
---
Dynamically get a missing property...
$getProperty called with field: OtherField
$getMissingProperty called with field: OtherField
RESULT = fakeValue

The dynamic type works well with the IExpando interface and Expando objects. Use these objects together to create dynamic property getters and setters and store data in a java.util.Map object.

See also