You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flex.apache.org by Christofer Dutz <ch...@c-ware.de> on 2014/10/31 15:05:14 UTC

[FALCON] Bindable interfaces?

Hi,


After finishing the advanced-telemetry option I started working on the next problem. In this case a user annotated an Interface with "Bindable". Falcon dies with a NPE (ASCompilationUnit line 383). I first thought that it was an error to make an Interface bindable, but when looking through the internet, it should actually be possible to annotate an interface with a bindable annotation. The compiler has to do a little more checking though :-(


I first thought of catching this situation and simply skipping it and reporting a warning, but I think this solution would not be correct as people are using this (I stumbled over it when trying to compile the flexicious code with falcon)


Chris

AW: [FALCON] Bindable interfaces?

Posted by Christofer Dutz <ch...@c-ware.de>.
Ok ... digging through the handling of Bindable metadata it seems that the code that was causing problems was redundant. The logic in ASCompilationUnit that changed the parent class of classes extending Object seems obsolete because even if commenting out the entire code in ASCompilationUnit binding stil seems to work.

So I guess we should remove this particular piece of code from ASCompilationUnit. Probably this would also get rid of the problems I was having.

Chris

________________________________________
Von: Christofer Dutz <ch...@c-ware.de>
Gesendet: Samstag, 1. November 2014 13:10
An: dev@flex.apache.org
Betreff: AW: [FALCON] Bindable interfaces?

Well I tried to compare the generated outputs, but couldn't manage to keep the generated output.
While looking for the reason for this, in flex-falcon/compiler/src/org/apache/flex/compiler/config/Configuration.java

I could see that the configuration of compiler.keep-generated-actionscript is marked as not supported and isn't implemented at all. I don't quite know how I should compare the output.

Any suggestions?

Chris

________________________________________
Von: Christofer Dutz <ch...@c-ware.de>
Gesendet: Freitag, 31. Oktober 2014 16:52
An: dev@flex.apache.org
Betreff: AW: [FALCON] Bindable interfaces?

Well I think the Bindable on classes is valid, but I'm talking about interfaces.

I couldn't find a definitive answer on this topic while searching the web.

Bindable is different from the other meta data tags as it explicitly changes the output and even the
type hierarchy of the class (Bindable on a class without explicit parent is changed to extend EventDispatcher for example). As you noted, every variable is re-written to fire events. But an interface can't have variables.
What I could read online is that people are suggested to make both the interface as well as the class implementing the interface bindable, to me this looks like a cheap trick to trick the IDE code completion and validation to not complaining.

The only thing I could think of that the compiler could do in case of a bindable interface, would be to automatically have the interface extend IEventDispatcher. This way an implementing class would have to make sure it dispatches events, but I guess the old compiler didn't do this.

The question is ... what should Falcon do?
1. Ignore the Bindable metadata on interfaces
2. Add a warning, but ignore the Bindable in any other way
3. Automatically extend the IEventDispatcher interface
4. something I didn't think of.

For my part I thought 3 would be best, but while writing the code for that I had to notice that in the compiler interfaces models don't seem to have any metaInfos. Going even further it seems that this part of code can't work this way at all, not even for classes.

metaInfos = pkg.getMetaInfos();

seems to be scanning the package node for metadata, but the class PackageNode implements getMetaTags() to return null. If however ASCompilationUnit would check the class instead of the package, it would find the MetaTag.

I think ASCompilationUnit.handleSyntaxTreeRequest needs a good deal of cleaning up:
1. Currently Bindable won't work ... not for Interfaces and not for Classes only for classes it doesn't throw an exception (At least Bindable classes that don't explicitly extend another class won't be changed to extend EventDispatcher ... this doesn't have any effect on the code generation later on)
2. If I changed the code to look in the class node for MetaInfo, then it would find this ... but thinking a little further ... what about files with multiple classes? What if the second class definition in a file had such Bindable annotation? As far as I can see it, this wouldn't be recognized.

I think it would be best to process each interface and class in a file, check if it is bindable and do the processing for EACH of these (Not only the one with index 0). If at least one bindable Interface was found, add the IEventDispatcher import, if at least one class was found that didn't extend any other class, add the EventDispatcher import. Thinking even further ... I think it would be best for classes to check if they have a base class and to make them extend EventDispatcher if they don't and to make them implement IEventDispatcher if they do have a base class.

So ... enough mails for today ... have to defragment my brain now ... probably with a decent amount of partying :-)

Chris


________________________________________
Von: Alex Harui <ah...@adobe.com>
Gesendet: Freitag, 31. Oktober 2014 16:14
An: dev@flex.apache.org
Betreff: Re: [FALCON] Bindable interfaces?

Yes, we need to allow [Bindable] on interfaces, even if it is an
inefficient way to write your code.

More details on why it is inefficient:

You can’t have a “var” in an interface, only functions/getter/setters.
[Bindable] was really meant to switch a var into a getter/setter pair so
that a change event gets fired and bindings update.

So if you did:

  [Bindable]
  public var foo:int;

The compiler generates something like (the 12345 is a random number to
prevent name collisions):

  private var foo_12345;
  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
     if (value !== foo_12345)
     {
        foo_12345 = value;
        dispatchEvent(new Event(“propertyChange”));
     }
  }

If you put [Bindable] on the class definition, then all vars are
converted.  I get how that is a convenient way to save time writing code.

I suppose folks who use [Bindable] on getter/setters just want to save
time writing code, IMO, it isn’t worth it.  The Flex SDK hopefully never
does this, btw, because it is inefficient.  The inefficient pattern looks
like:

  private var _foo:int;

  [Bindable]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      _foo = value;
  }

This results in the compiler generating:

  private var _foo:int;

  [Bindable]
  public function get foo_12345():int
  {
      return _foo;
  }
  public function set foo_12345(value:int):void
  {
      _foo = value;
  }

  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
      if (value !== foo_12345)
      {
          foo_12345 = value;
          dispatchEvent(new Event(“propertyChange”));
      }
  }

Like I said, hopefully, the SDK code never does this and we always took
the time to do this:

  private var _foo:int;

  [Bindable(“fooChanged”)]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      if (_foo !== value)
      {
          _foo = value;
          dispatchEvent(new Event(“fooChanged”));
      }
  }

Yes, I had to do more typing, but if you compare the two patterns, you’ll
see that, for [Bindable] on interfaces and getter/setters, that you’ve
doubled the number of function calls required to get the value, and
tripled the number of function calls required to set the value, plus added
another not-so-short string to the string table and two functions to the
class traits in the SWF all of which have to be downloaded and decoded at
startup time.



Also, at runtime, the binding logic does an additional check if the
property change event is “propertyChange” to see if the property being
changes is the one it is interested in.

Will it make a huge difference in your app’s performance?  I don’t know
for sure, but I think it can add up over time.  Why wrap functions in
functions for no good reason?  Also, see [1] for old information on the
cost of function overhead.


Happy coding,
-Alex

[1]
http://blogs.adobe.com/aharui/2007/10/actionscript_readwrite_perform_1.html

On 10/31/14, 7:05 AM, "Christofer Dutz" <ch...@c-ware.de> wrote:

>Hi,
>
>
>After finishing the advanced-telemetry option I started working on the
>next problem. In this case a user annotated an Interface with "Bindable".
>Falcon dies with a NPE (ASCompilationUnit line 383). I first thought that
>it was an error to make an Interface bindable, but when looking through
>the internet, it should actually be possible to annotate an interface
>with a bindable annotation. The compiler has to do a little more checking
>though :-(
>
>
>I first thought of catching this situation and simply skipping it and
>reporting a warning, but I think this solution would not be correct as
>people are using this (I stumbled over it when trying to compile the
>flexicious code with falcon)
>
>
>Chris

AW: [FALCON] Bindable interfaces?

Posted by Christofer Dutz <ch...@c-ware.de>.
Well I tried to compare the generated outputs, but couldn't manage to keep the generated output.
While looking for the reason for this, in flex-falcon/compiler/src/org/apache/flex/compiler/config/Configuration.java

I could see that the configuration of compiler.keep-generated-actionscript is marked as not supported and isn't implemented at all. I don't quite know how I should compare the output.

Any suggestions?

Chris

________________________________________
Von: Christofer Dutz <ch...@c-ware.de>
Gesendet: Freitag, 31. Oktober 2014 16:52
An: dev@flex.apache.org
Betreff: AW: [FALCON] Bindable interfaces?

Well I think the Bindable on classes is valid, but I'm talking about interfaces.

I couldn't find a definitive answer on this topic while searching the web.

Bindable is different from the other meta data tags as it explicitly changes the output and even the
type hierarchy of the class (Bindable on a class without explicit parent is changed to extend EventDispatcher for example). As you noted, every variable is re-written to fire events. But an interface can't have variables.
What I could read online is that people are suggested to make both the interface as well as the class implementing the interface bindable, to me this looks like a cheap trick to trick the IDE code completion and validation to not complaining.

The only thing I could think of that the compiler could do in case of a bindable interface, would be to automatically have the interface extend IEventDispatcher. This way an implementing class would have to make sure it dispatches events, but I guess the old compiler didn't do this.

The question is ... what should Falcon do?
1. Ignore the Bindable metadata on interfaces
2. Add a warning, but ignore the Bindable in any other way
3. Automatically extend the IEventDispatcher interface
4. something I didn't think of.

For my part I thought 3 would be best, but while writing the code for that I had to notice that in the compiler interfaces models don't seem to have any metaInfos. Going even further it seems that this part of code can't work this way at all, not even for classes.

metaInfos = pkg.getMetaInfos();

seems to be scanning the package node for metadata, but the class PackageNode implements getMetaTags() to return null. If however ASCompilationUnit would check the class instead of the package, it would find the MetaTag.

I think ASCompilationUnit.handleSyntaxTreeRequest needs a good deal of cleaning up:
1. Currently Bindable won't work ... not for Interfaces and not for Classes only for classes it doesn't throw an exception (At least Bindable classes that don't explicitly extend another class won't be changed to extend EventDispatcher ... this doesn't have any effect on the code generation later on)
2. If I changed the code to look in the class node for MetaInfo, then it would find this ... but thinking a little further ... what about files with multiple classes? What if the second class definition in a file had such Bindable annotation? As far as I can see it, this wouldn't be recognized.

I think it would be best to process each interface and class in a file, check if it is bindable and do the processing for EACH of these (Not only the one with index 0). If at least one bindable Interface was found, add the IEventDispatcher import, if at least one class was found that didn't extend any other class, add the EventDispatcher import. Thinking even further ... I think it would be best for classes to check if they have a base class and to make them extend EventDispatcher if they don't and to make them implement IEventDispatcher if they do have a base class.

So ... enough mails for today ... have to defragment my brain now ... probably with a decent amount of partying :-)

Chris


________________________________________
Von: Alex Harui <ah...@adobe.com>
Gesendet: Freitag, 31. Oktober 2014 16:14
An: dev@flex.apache.org
Betreff: Re: [FALCON] Bindable interfaces?

Yes, we need to allow [Bindable] on interfaces, even if it is an
inefficient way to write your code.

More details on why it is inefficient:

You can’t have a “var” in an interface, only functions/getter/setters.
[Bindable] was really meant to switch a var into a getter/setter pair so
that a change event gets fired and bindings update.

So if you did:

  [Bindable]
  public var foo:int;

The compiler generates something like (the 12345 is a random number to
prevent name collisions):

  private var foo_12345;
  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
     if (value !== foo_12345)
     {
        foo_12345 = value;
        dispatchEvent(new Event(“propertyChange”));
     }
  }

If you put [Bindable] on the class definition, then all vars are
converted.  I get how that is a convenient way to save time writing code.

I suppose folks who use [Bindable] on getter/setters just want to save
time writing code, IMO, it isn’t worth it.  The Flex SDK hopefully never
does this, btw, because it is inefficient.  The inefficient pattern looks
like:

  private var _foo:int;

  [Bindable]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      _foo = value;
  }

This results in the compiler generating:

  private var _foo:int;

  [Bindable]
  public function get foo_12345():int
  {
      return _foo;
  }
  public function set foo_12345(value:int):void
  {
      _foo = value;
  }

  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
      if (value !== foo_12345)
      {
          foo_12345 = value;
          dispatchEvent(new Event(“propertyChange”));
      }
  }

Like I said, hopefully, the SDK code never does this and we always took
the time to do this:

  private var _foo:int;

  [Bindable(“fooChanged”)]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      if (_foo !== value)
      {
          _foo = value;
          dispatchEvent(new Event(“fooChanged”));
      }
  }

Yes, I had to do more typing, but if you compare the two patterns, you’ll
see that, for [Bindable] on interfaces and getter/setters, that you’ve
doubled the number of function calls required to get the value, and
tripled the number of function calls required to set the value, plus added
another not-so-short string to the string table and two functions to the
class traits in the SWF all of which have to be downloaded and decoded at
startup time.



Also, at runtime, the binding logic does an additional check if the
property change event is “propertyChange” to see if the property being
changes is the one it is interested in.

Will it make a huge difference in your app’s performance?  I don’t know
for sure, but I think it can add up over time.  Why wrap functions in
functions for no good reason?  Also, see [1] for old information on the
cost of function overhead.


Happy coding,
-Alex

[1]
http://blogs.adobe.com/aharui/2007/10/actionscript_readwrite_perform_1.html

On 10/31/14, 7:05 AM, "Christofer Dutz" <ch...@c-ware.de> wrote:

>Hi,
>
>
>After finishing the advanced-telemetry option I started working on the
>next problem. In this case a user annotated an Interface with "Bindable".
>Falcon dies with a NPE (ASCompilationUnit line 383). I first thought that
>it was an error to make an Interface bindable, but when looking through
>the internet, it should actually be possible to annotate an interface
>with a bindable annotation. The compiler has to do a little more checking
>though :-(
>
>
>I first thought of catching this situation and simply skipping it and
>reporting a warning, but I think this solution would not be correct as
>people are using this (I stumbled over it when trying to compile the
>flexicious code with falcon)
>
>
>Chris

AW: [FALCON] Bindable interfaces?

Posted by Christofer Dutz <ch...@c-ware.de>.
Well I think the Bindable on classes is valid, but I'm talking about interfaces.

I couldn't find a definitive answer on this topic while searching the web.

Bindable is different from the other meta data tags as it explicitly changes the output and even the
type hierarchy of the class (Bindable on a class without explicit parent is changed to extend EventDispatcher for example). As you noted, every variable is re-written to fire events. But an interface can't have variables. 
What I could read online is that people are suggested to make both the interface as well as the class implementing the interface bindable, to me this looks like a cheap trick to trick the IDE code completion and validation to not complaining.

The only thing I could think of that the compiler could do in case of a bindable interface, would be to automatically have the interface extend IEventDispatcher. This way an implementing class would have to make sure it dispatches events, but I guess the old compiler didn't do this.

The question is ... what should Falcon do? 
1. Ignore the Bindable metadata on interfaces
2. Add a warning, but ignore the Bindable in any other way
3. Automatically extend the IEventDispatcher interface
4. something I didn't think of.

For my part I thought 3 would be best, but while writing the code for that I had to notice that in the compiler interfaces models don't seem to have any metaInfos. Going even further it seems that this part of code can't work this way at all, not even for classes. 

metaInfos = pkg.getMetaInfos();

seems to be scanning the package node for metadata, but the class PackageNode implements getMetaTags() to return null. If however ASCompilationUnit would check the class instead of the package, it would find the MetaTag. 

I think ASCompilationUnit.handleSyntaxTreeRequest needs a good deal of cleaning up:
1. Currently Bindable won't work ... not for Interfaces and not for Classes only for classes it doesn't throw an exception (At least Bindable classes that don't explicitly extend another class won't be changed to extend EventDispatcher ... this doesn't have any effect on the code generation later on)
2. If I changed the code to look in the class node for MetaInfo, then it would find this ... but thinking a little further ... what about files with multiple classes? What if the second class definition in a file had such Bindable annotation? As far as I can see it, this wouldn't be recognized.

I think it would be best to process each interface and class in a file, check if it is bindable and do the processing for EACH of these (Not only the one with index 0). If at least one bindable Interface was found, add the IEventDispatcher import, if at least one class was found that didn't extend any other class, add the EventDispatcher import. Thinking even further ... I think it would be best for classes to check if they have a base class and to make them extend EventDispatcher if they don't and to make them implement IEventDispatcher if they do have a base class.

So ... enough mails for today ... have to defragment my brain now ... probably with a decent amount of partying :-)

Chris


________________________________________
Von: Alex Harui <ah...@adobe.com>
Gesendet: Freitag, 31. Oktober 2014 16:14
An: dev@flex.apache.org
Betreff: Re: [FALCON] Bindable interfaces?

Yes, we need to allow [Bindable] on interfaces, even if it is an
inefficient way to write your code.

More details on why it is inefficient:

You can’t have a “var” in an interface, only functions/getter/setters.
[Bindable] was really meant to switch a var into a getter/setter pair so
that a change event gets fired and bindings update.

So if you did:

  [Bindable]
  public var foo:int;

The compiler generates something like (the 12345 is a random number to
prevent name collisions):

  private var foo_12345;
  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
     if (value !== foo_12345)
     {
        foo_12345 = value;
        dispatchEvent(new Event(“propertyChange”));
     }
  }

If you put [Bindable] on the class definition, then all vars are
converted.  I get how that is a convenient way to save time writing code.

I suppose folks who use [Bindable] on getter/setters just want to save
time writing code, IMO, it isn’t worth it.  The Flex SDK hopefully never
does this, btw, because it is inefficient.  The inefficient pattern looks
like:

  private var _foo:int;

  [Bindable]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      _foo = value;
  }

This results in the compiler generating:

  private var _foo:int;

  [Bindable]
  public function get foo_12345():int
  {
      return _foo;
  }
  public function set foo_12345(value:int):void
  {
      _foo = value;
  }

  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
      if (value !== foo_12345)
      {
          foo_12345 = value;
          dispatchEvent(new Event(“propertyChange”));
      }
  }

Like I said, hopefully, the SDK code never does this and we always took
the time to do this:

  private var _foo:int;

  [Bindable(“fooChanged”)]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      if (_foo !== value)
      {
          _foo = value;
          dispatchEvent(new Event(“fooChanged”));
      }
  }

Yes, I had to do more typing, but if you compare the two patterns, you’ll
see that, for [Bindable] on interfaces and getter/setters, that you’ve
doubled the number of function calls required to get the value, and
tripled the number of function calls required to set the value, plus added
another not-so-short string to the string table and two functions to the
class traits in the SWF all of which have to be downloaded and decoded at
startup time.



Also, at runtime, the binding logic does an additional check if the
property change event is “propertyChange” to see if the property being
changes is the one it is interested in.

Will it make a huge difference in your app’s performance?  I don’t know
for sure, but I think it can add up over time.  Why wrap functions in
functions for no good reason?  Also, see [1] for old information on the
cost of function overhead.


Happy coding,
-Alex

[1]
http://blogs.adobe.com/aharui/2007/10/actionscript_readwrite_perform_1.html

On 10/31/14, 7:05 AM, "Christofer Dutz" <ch...@c-ware.de> wrote:

>Hi,
>
>
>After finishing the advanced-telemetry option I started working on the
>next problem. In this case a user annotated an Interface with "Bindable".
>Falcon dies with a NPE (ASCompilationUnit line 383). I first thought that
>it was an error to make an Interface bindable, but when looking through
>the internet, it should actually be possible to annotate an interface
>with a bindable annotation. The compiler has to do a little more checking
>though :-(
>
>
>I first thought of catching this situation and simply skipping it and
>reporting a warning, but I think this solution would not be correct as
>people are using this (I stumbled over it when trying to compile the
>flexicious code with falcon)
>
>
>Chris

Re: [FALCON] Bindable interfaces?

Posted by Alex Harui <ah...@adobe.com>.
Yes, we need to allow [Bindable] on interfaces, even if it is an
inefficient way to write your code.

More details on why it is inefficient:

You can’t have a “var” in an interface, only functions/getter/setters.
[Bindable] was really meant to switch a var into a getter/setter pair so
that a change event gets fired and bindings update.

So if you did:

  [Bindable]
  public var foo:int;

The compiler generates something like (the 12345 is a random number to
prevent name collisions):

  private var foo_12345;
  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
     if (value !== foo_12345)
     {
        foo_12345 = value;
        dispatchEvent(new Event(“propertyChange”));
     }
  }

If you put [Bindable] on the class definition, then all vars are
converted.  I get how that is a convenient way to save time writing code.

I suppose folks who use [Bindable] on getter/setters just want to save
time writing code, IMO, it isn’t worth it.  The Flex SDK hopefully never
does this, btw, because it is inefficient.  The inefficient pattern looks
like:

  private var _foo:int;
 
  [Bindable]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      _foo = value;
  }

This results in the compiler generating:

  private var _foo:int;

  [Bindable]
  public function get foo_12345():int
  {
      return _foo;
  }
  public function set foo_12345(value:int):void
  {
      _foo = value;
  }

  [Bindable(“propertyChange”)]
  public function get foo():int
  {
      return foo_12345;
  }
  public function set foo(value:int):void
  {
      if (value !== foo_12345)
      {
          foo_12345 = value;
          dispatchEvent(new Event(“propertyChange”));
      }
  }

Like I said, hopefully, the SDK code never does this and we always took
the time to do this:

  private var _foo:int;

  [Bindable(“fooChanged”)]
  public function get foo():int
  {
      return _foo;
  }
  public function set foo(value:int):void
  {
      if (_foo !== value)
      {
          _foo = value;
          dispatchEvent(new Event(“fooChanged”));
      }
  }

Yes, I had to do more typing, but if you compare the two patterns, you’ll
see that, for [Bindable] on interfaces and getter/setters, that you’ve
doubled the number of function calls required to get the value, and
tripled the number of function calls required to set the value, plus added
another not-so-short string to the string table and two functions to the
class traits in the SWF all of which have to be downloaded and decoded at
startup time.



Also, at runtime, the binding logic does an additional check if the
property change event is “propertyChange” to see if the property being
changes is the one it is interested in.

Will it make a huge difference in your app’s performance?  I don’t know
for sure, but I think it can add up over time.  Why wrap functions in
functions for no good reason?  Also, see [1] for old information on the
cost of function overhead.


Happy coding,
-Alex

[1] 
http://blogs.adobe.com/aharui/2007/10/actionscript_readwrite_perform_1.html

On 10/31/14, 7:05 AM, "Christofer Dutz" <ch...@c-ware.de> wrote:

>Hi,
>
>
>After finishing the advanced-telemetry option I started working on the
>next problem. In this case a user annotated an Interface with "Bindable".
>Falcon dies with a NPE (ASCompilationUnit line 383). I first thought that
>it was an error to make an Interface bindable, but when looking through
>the internet, it should actually be possible to annotate an interface
>with a bindable annotation. The compiler has to do a little more checking
>though :-(
>
>
>I first thought of catching this situation and simply skipping it and
>reporting a warning, but I think this solution would not be correct as
>people are using this (I stumbled over it when trying to compile the
>flexicious code with falcon)
>
>
>Chris