Wednesday, January 27, 2010

Flex Binding "Gotcha!"

Somewhere online, I saw a comment saying that binding in Flex is "evil magic" and should be avoided except in the simplest of cases. Though I could see where the author was coming from in theory, it wasn't until today that I encountered this in practice.

In short, setting a bindable variable to a field of a bindable class binds the variable to the value referenced by the field, not to the reference in the bindable class. Get it? The whole pass by value vs. pass by reference thing. Here's an example (ignore the use of the default package):

Class A:
package
{
[Bindable]
public class A
{
public var val : int;
public var b : B;

public function A()
{
val = 0;
b = new B(0);
}
}
}

Class B:
package
{
[Bindable]
public class B
{
public var val : int;
    public function B(v:int)
{
this.val = v;
}
}
}

MXML Test:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">

<mx:Button click="onClick()" label="Click Me" />
<mx:Text text="A: {myA.val}" />
<mx:Text text="B: {myB.val}" />

<mx:Script>
<![CDATA[
[Bindable] var myA:A = new A();
[Bindable] var myB:B = myA.b;

function onClick() : void
{
myA.val += 1;
myA.b = new B(3);
}
]]>
</mx:Script>
</mx:Application>

At launch, the text elements both have the value 0. But, after one click of the button, what is the value of myB.val?

I don't think I'm alone on this, but maybe I am. In any case, I expected myB.val to be 3, because myB was assigned to myA.b and A is a [Bindable] class. When I changed the value of myA.b, I expected myB to reference new instance of B that myA.b now referenced.

Turns out it doesn't. After one click of the button, myB.val == 0. Why? Because myB is still bound to the original instance of B referenced by myA.b at the time myB was assigned, rather than whatever instance of B that myA.b might reference in the future.

Bummer. If only myB was a pointer...