Dynamic

Dynamic variables


Disclaimer: Dynamic variables are often necessary to ensure interoperability with third party or platform dependent libraries, or for very specific cases where dynamic variables are absolutely required. Their use is not encouraged for normal use, as their behavior differs between targets.

When you want to get some dynamically typed behavior and break free from the type system, you can use the Dynamic type which can be used in place of any type without any compile-time type-checking:

    var x : Dynamic = "";
    x = true;
    x = 1.744;
    x = {};
    x.foo = 'bar';
    x = new Array();

When a variable is marked "Dynamic" the compiler does not ensure that types are followed for a given variable. This means that it is possible to switch from referencing one type of object to another. Also, any assignment, field assignment, or index access will succeed at compile time.

At run time however, different targets may not recognize or even allow certain operations on certain variables. For instance, on the flash9 (AVM2 target) a dynamic variable is assigned a value, such as an integer or boolean an exception will be thrown. On less strict platforms (such as javascript) an error may not be thrown, but the value will not be saved.

var x:Dynamic = 4;
x.foo = "Bar";

//flash9:  ReferenceError: Error #1056: Cannot create property foo on Number.

//JS: foo.x = null;

Having an object 'implement Dynamic', allowing fields to be added/removed at runtime, is quite a different concept. See 'Implementing Dynamic' below.

Trying to modify the fields of a flash9 MovieClip instance will work (since it itself implements a Dynamic type), but modifying the fields of a flash9 Sprite class will cause a run time reference error:

// flash9
var m:Dynamic = new flash.display.MovieClip();
m.foo = "Bar";
trace(m.foo); // value is saved 
var s:Dynamic = new flash.display.Sprite();
s.foo = "Bar"; // ReferenceError!

In short, "Dynamic" variables never check for type by the compiler, whether they are assigned in a method body, or as a method argument. But, they still will observe run-time type restrictions that are in place for a given target, and may cause run-time errors.

An untyped variable is of type Unknown and not Dynamic. That is, an untyped variable does not have a type until it is determined by type inference. A Dynamic variable has a specific type: an any type.

Parameterized Dynamic Variables

Adding a parameter to a Dynamic type allows arbitrary access and assignment to any field as long as it is the same type as the parameter. For instance, Dynamic<String> allows access or assignment to any field, as long as these accesses accept or produce String types. This is useful to encode Hashtables where items are accessed using dot syntax:

    var att : Dynamic<String> = xml.attributes;
    att.name = "Nicolas";
    att.age = "26";
    // ...

or
    var foo : Dynamic<String> = cast {};
    foo.name = "Nicolas";

Implementing Dynamic

Any class can also implement Dynamic with or without a type parameter. In the first case, the class fields are typed when they exist, otherwise they have a dynamic type:

class C implements Dynamic<Int> {
    public var name : String;
    public var address : String;
}
// ...
var c = new C();
var n : String = c.name; // ok
var a : String = c.address; // ok
var i : Int = c.phone; // ok : use Dynamic
var c : String = c.country; // ERROR
// c.country is an Int because of Dynamic<Int>

Dynamic behavior is inherited by subclasses. When several classes are implementing different Dynamic types in a class hierarchy, the last Dynamic definition is used.

In the case of accessing an undefined property on an object which implements Dynamic the function "resolve" will be called. This function is called with one parameter, the property attempted to be accessed, and can return any value.

Type Casting

You can cast from one type to another by using the cast keyword.

     var a : A = ....
     var b : B = cast(a,B);

This will either return the value a with the type B if a is an instance of B or it will throw an exception "Class cast error".

Untyped

One other way to do dynamic things is to use the untyped keyword. When an expression is untyped, no type-check will be done so you can execute many dynamic operations at once:

    untyped { a["hello"] = 0; }

Be careful to use untyped expressions only when you really need them and when you know what you're doing.

Unsafe Cast

The untyped keyword provides great flexibility at the cost of allowing potentially invalid syntax on the right side of the untyped keyword. It also allows for an unsafe cast which is similar to the standard cast except that no type is specified. That means that the cast call will not result in any runtime check, but will allow you to "lose" one type.

    var y : B = cast 0;

An unsafe cast is similar to storing a value in a temporary Dynamic variable :

    var tmp : Dynamic = 0;
    var y : B = tmp;

Dynamic Methods

In Haxe, you can declare methods to be dynamic. These can be replaced at runtime to provide advices. Let me explain, what happens under the hood. The following Haxe code:

public function f1(a : A) : B { /*body*/ }
public dynamic function f2(a: A) : B { /*body*/ }

Is the equivalent of the following AS3 code:
public function f1(a : A) : B { /*body*/ }
public var f2 : Function = function (a : A) : B { /*body*/ }

Using the latter always performs worse than the former, since there's a lot of runtime type checking involved. In Haxe however, you do not lose the compile time benefits of strict typing, unlike in AS3.
source : StackOverFlow
For advance usage on anonymous object see Haxe 2.0 Changes

«« Packages and Imports | Advanced Types »»

version #11025, modified 2011-09-23 14:22:08 by bubblebenj