Why does this property/function name collision compile in AS3? - actionscript-3

In ActionScript 3.0, this compiles:
public function set func(value:Function):void
{
}
public function func():void
{
}
This doesn't:
public function set someVar44(value:int):void
{
}
var someVar44:int;
Why does the first one compile? I suppose it's possible that Adobe just specifically and arbitrarily decided to block this for variables and to allow it for functions, but allowing it for either functions or variables doesn't seem to make any sense. I'm suspicious there's more to the story here. What am I not seeing?

This is really interesting, and took a fair amount of digging to get down to (although the answer seems painfully obvious).
As you know variables/properties cannot be declared in the same scope with identical names. Therefore the set function someVar44() and the variable someVar44 are in direct conflict (besides issues with trying to initialize the variable twice). Conversely if you had tried:
public function get func(value:Function):void
{
}
you would have ran into a similar issue with a duplicate function definition error. So why does the set function seem to allow you to get past these errors? As setters and getters are known for accessing and mutating properties of a class, it would seem they are also treated as class properties as opposed to a typical method, but this is not entirely the case. In fact, only the setter appears as a property of the public interface, the getter on the other hand is a method that can read like a property.
The setter:
public function set func(value:Function):void
Is read exactly like a property of the object, and without any other properties in direct conflict with it (i.e. - there is no current property like var func.) you do not receive a compiler error.
From adobe:
set Defines a setter, which is a method that appears in the public interface as a property.
get Defines a getter, which is a method that can be read like a property.
I believe that is why you are not getting a compiler error with set method. Although if you attempt to access that set method, the priority is immediately assumed to the function func(). That is, if you attempt this.func = function():void { } you will get the error:
Error #1037: Cannot assign to a method func

I can understand logically why the first compiles (in the older compiler). When considering an instance of the object, getting the obj.func property should return the member function you've defined, while setting the obj.func property should call the setter you've defined. This doesn't seem to be an ambiguity to me, though as we've seen, the runtime disagrees with me.
In the second case, you've defined a var (which defaults to the internal scope since you didn't say public, but that's another story) which, being externally visible, implicitly defines a getter and setter. So if someone sets the obj.someVar44 property of your object, are they calling the setter or setting your variable value? It's clearly an ambiguity and a duplicate definition.

Related

Are methods also objects like functions are?

I read that functions (AKA static methods) are objects (instances of the Function class). Are methods (instance functions) also objects? I can't find the answer in the official documentation. It only says functions are objects (but doesn't explain if all functions are, including methods).
It is quite easy to verify that the method is an object:
class Foo {
bar() {}
}
void main() {
print(Foo().bar is Object); // prints true
}
and linter shows a warning:
Unnecessary type check, the result is always true
Technically, the answer is "no". In practice, that never matters.
Instance methods are properties of classes that can be invoked via objects that are instances of those classes. A method is not itself a value, so it makes not sense to ask if it's an object, because all objects are values. You can refer to a method by name (it's "denotable"), but that's it. You cannot evaluate an expression to a method or store it in a variable.
However, you can tear off an instance method from an object. When you do that, a new function object is created which, when called, will invoke the method on the original object with the same arguments.
That function object is, well, both a function and an object. It is not the method itself, though, if one is being pedantic.
In practice, if you ever care to ask if something is an object, it's likely already a value, and then that thing is an object.
(Static methods are also technically not objects, but they are so close to the function object created when you tear them off, that the distinction is never practically significant. The language semantics differentiates because when you create an object, it matters which object it is - what is it equal to and identical to - and until you creates a value, the language prefers to just not have to specify that.)

Bindable setter not called if value of property not changed?

(This may be too localized an issue but I will try to generalize it)
Question: If a property setteris marked as Bindable, will it not get called if the new value is the same as the old value?
I am seeing the above behavior in a legacy project I have inherited: the setter is not getting called. If I don't declare the setter as Bindable then the setter is called no matter what the new value is.
Can anyone confirm that the above is the way things are designed to work with Binding?
This project uses Binding all over the place and there are no comments in the code so it is hard to tell what the dependencies are and which parts of the code depend on particular bindings. I'm trying to avoid making major changes but I also don't want to waste time trying to work around something which should be refactored.
The property is bound:
[Bindable]
protected var _source:AolMediaFile;
The setter is bound:
[Bindable]
public function set source(file:AolMediaFile):void{
_source = file;
// do some stuff with file
}
The setter should only get called if the event source is [Bindable]. Data binding is basically a chain of events dispatched from source to target in a variety of scenarios. When you declare your property or setter as [Bindable], that will basically change nothing in the behaviour in terms of side effects, as events are dispatched and listeners are generated. For example:
<your:Component source="{any.source.aolMediaFile}" />
Only when any, source and aolMediaFile are declared [Bindable], source would be invoked. Having source declared as a [Bindable] property is only interesting, if a second component would be depending on your component's state
<your:Component id="yourComponent" source="{any.source.aolMediaFile}" />
<s:TextField text="{yourComponent.source}" />
If you would want to bind to a property of AolMediaFile, then the class or the specific property has to be be [Bindable] as well.
Usually the compiler prints warnings, if bindings can't be generated:
warning: unable to bind to property 'source' on class 'Object'
(class is not an IEventDispatcher)
So check the source object, which are the source's host object's dependency and the compiler warnings.
So digging around here a bit more I came across this question: Flex: Help me understand data Binding on getters and setters which describes the code generated by declaring a setter or getter Bindable
So apparently in the generated code there is a check to see if the value is different:
public function set name(value:String)
{
if (_name == value)
return;
_name = value;
dispatchEvent(new Event("nameChanged"));
}

AS3: inline way to write get and set?

I was reading a tutorial and the user there was starting setters and getters like so
function get f():Number;
function set f(value:Number):void;
inside an interface, then saving it in the main file inside a variable
var testNode:INode;
and referencing them as
testNode.f;
I thought this was really handy, specially for when you have a lot of variables. Instead of having to create two functions for each private value.
However, I tried to do the same without instancing the get and set inside an interface (because I had no need for this) and I get an error saying the function doesn't have a body.
Why is that? Is there any way to write get and set in such a clean, short manner? So far I've been writing these as
public function get someVar():SomeClass {
return _someVar;
}
public function set someVar(newValue:SomeClass):void {
_someVar = newValue;
}
but it's a bit of a hassle when I have several private variables.
An interface is just a model for your class, it does not allows you to skip the definition of a function (or a getter/setter). You must declare the getter and the setter in any class implementing your interface. What you are looking for is an extension (inheritage).
If you define a class Mother.as with a getter and a setter, the class Child.as which extends Mother.as doesn't need to redefine the getter and setter.
Furthermore, if you don't plan on writing anything else inside the getter and setter, you should use a public variable. These are less resource consuming than useless get/set.

Compatability when passing object to class

Ok, so this might be me being pendantic but I need to know the best way to do something:
(This is psudocode, not actual code. Actual code is huge)
I basically have in my package a class that goes like this:
internal class charsys extends DisplayObject {
Bunch of Variables
a few functions
}
I another class which I intend to add to the timeline I want to create a function like this:
public class charlist {
var list:Array = new Array();
var clock:Timer = new Timer(6000);
var temp:charsys;
function addObj(MC:DisplayObject, otherprops:int) {
temp=MC;
temp.props = otherprops;
list.push(temp)
}
function moveabout(e: event) {
stuff to move the items in list
}
function charlist() {
stuff to initialize the timers and handle them.
}
}
So the question is, is my method of populating this array a valid method of doing it, is there an easier way, can they inherit like this and do I even need to pass the objects like I am?
(Still writing the package, don't know if it works at all)
Yes, you can pass an object into a function, but you should be careful of what you are planning to do with that object inside that function. Say, if you are planning to pass only charsys objects, you write the function header as such:
function addObj(MC:charsys, otherprops:int) {
Note, the type is directly put into the function header. This way Flash compiler will be able to do many things.
First, it will query the function body for whether it refers to valid properties of a passed instance. Say, your charsys object does not have a props property, but has a prop property, this typing error will be immediately caught and reported. Also if that props is, for example, an int, and you are trying to assign a String value to it, you will again be notified.
Second, wherever you use that function, Flash compiler will statically check if an instance of correct type charsys is passed into the function, so if there is no charsys or its subclass, a compilation error is thrown.
And third, this helps YOU to learn how to provide correct types for functions, and not rely on dynamic classes like MovieClip, which can have a property of nearly any name assigned to anything, and this property's existence is not checked at compile time, possibly introducing nasty bugs with NaNs appearing from nowhere, or some elements not being displayed, etc.
About common usage of such methods - they can indeed be used to create/manage a group of similar objects of one class, to the extent of altering every possible property of them based on their corresponding values. While default values for properties are occasionally needed, these functions can be used to slightly (or not so slightly) alter them based on extra information. For example, I have a function that generates a ready-to-place TextField object, complete with formatting and altered default settings (multiline=true etc), which is then aligned and placed as I need it to be. You cannot alter default values in the TextField class, so you can use such a function to tailor a new text field object to your needs.
Hope this helps.
This would work, I think I would assign values to the properties of the charsys object before passing it into the add method though, rather than passing the properties and having a different class do the property assignment. If you have some common properties they could either have defaults in charsys class definition or you could set literals in the addObj method.

Actionscript: How exactly does ExternalInterface.addCallback() work?

I'm pretty new to ActionScript, but not new to either object oriented or procedural languages in general. ActionScript's particular combination of features from both categories, however, confuses me.
Specifically, I'm confused about the mechanism of ExternalInterface.addCallback(). The method signature is:
public static function addCallback(functionName:String, closure:Function):void
Of particular interest is the closure parameter, which has the following documentation:
closure:Function — The function closure to invoke. This could be a free-standing
function, or it could be a method closure referencing a method of an
object instance. By passing a method closure, you can direct the
callback at a method of a particular object instance.
I take the above to mean that closure only be a function (not a method), which may or may not be a closure containing a method call from an instantiated object. So I get confused when I see code like this (taken from the same documentation page):
public class ext_test extends Sprite {
function ext_test():void {
ExternalInterface.marshallExceptions = true;
ExternalInterface.addCallback("g", g);
try {
ExternalInterface.call("throwit");
} catch(e:Error) {
trace(e)
}
}
function g() { throw new Error("exception from actionscript!!!!") }
}
The above code inserts in to addCallback, a non-static method of ext_test without wrapping it in a closure containing an instantiated ex_test object.
The method contains trivial code, but what if it were to have statements containing member variables and the like? How would the method be evaluated when it has no parent object?
Furthermore, (since the addCallback seems to allow the passing of arbitrary methods) the documentation makes no mention on the effect access modifiers have on the passed methods, if any. If I label a method private, am I still able to pass it to addCallback? What's the deal?
I'd appreciate it if anyone can help me wrap my head around this.
If your concern is to know in what context the method you passed will be executed, this is simply the context in which you attached it.
The doc's jibber jabber simply means that there are several kinds of function in AS3 and the runtime. "Free-standing" function refers to what you usually call an anonymous function - that still preserves the context in which they were defined :
var anonymous:Function = createAnonymous();
trace(anonymous()); // 123
function createAnonymous():Function {
var internalStuff:Number = 123;
var func:Function = function():Number {
return internalStuff;
}
return func;
}
Methods closures are instances of your classes' methods, the same way objects are instances of these classes. So, when you pass a method closure to ExternalInterface.addCallback(), you'll be safe about the context (i.e. member variables) when it will be invoked.
Woops. Totally forgot the that in all the examples I've seen, addCallback is being executed in the context of a constructor, so the method references passed to it have a context to execute under.
As such, access modifiers don't matter since everything in a class can be seen by the class.