Why can't a computed property be accessed as namespace? - actionscript-3

I've found an issue in AS3 namespace indexing nearly a month ago.
First, my test:
package {
import flash.display.MovieClip;
public class main extends MovieClip {
/* Namespace definition */
protected namespace Demo;
Demo const AMOUNT = 0;
public function main() {
super();
/* Put the namespace inside a property */
const obj = {
Demo: Demo
};
/* Now namespace-index this property */
trace((obj.Demo)::AMOUNT);
/* The following fails: obj.Demo::AMOUNT,
* it's aproximately obj::AMOUNT */
}
}
}
It works as expected, outputing 0. But when I want to compute the get resolver obj.Demo, it throws an error (it's not English, but: 1043: Espacio de nombres no definido), or Namespace not defined:
trace((obj['Demo'])::AMOUNT);
I'd like to know the reason (and obj['Demo']::AMOUNT results in a syntax error).

Related

Acces of undefined property cerc

I have this code in AS3:
package clase
{
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* #author cry
*/
public class CercNegru extends MovieClip
{
var growthRate:Number = 2;
cerc.addEventListener(Event.ENTER_FRAME,grow);
public function CercNegru()
{
}
private function grow(e:Event):void
{
trace("asdda");
}
}
}
When you run this program receive error:
Line 12 1120: Access of undefined property cerc.
Line 12 1120: Access of undefined property grow.
I put an image to understand better :
Can you help me to solve this problem please?
Thanks in advance!
The errors are because in class files, all functional code needs to live inside a function.
So take this line, which is just floating in the class:
cerc.addEventListener(Event.ENTER_FRAME,grow);
And move into the constructor (assuming you want it to run right away when you instantiate the class):
public function CercNegru()
{
cerc.addEventListener(Event.ENTER_FRAME,grow);
}
In class files, the constructor (which is the function whose name exactly matches the class name), is what get's called you use the new keyword.
So doing new CercNegru() will call that function.
NOW, I'm also assuming that this class file is attached to FlashPro library object, and you have something on the timeline with an instance name of cerc. (if that is not the case, then that is the reason for your error)
Timeline stuff though, isn't always available in the constructor, so you may need to wait until the instance has been added to the screen.
public var cerc:MovieClip; //you may want to create a reference to the timeline item, so you get compile time checking
public function CercNegru()
{
this.addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
//this is the equivalent of timeline code now
cerc.addEventListener(Event.ENTER_FRAME,grow);
}
package clase
{
import flash.display.MovieClip;
import flash.events.Event;
/**
* ...
* #author cry
*/
public class CercNegru extends MovieClip
{
var growthRate:Number = 2;
var cerc:DisplayObject; // ADD THIS
public function CercNegru()
{
cerc.addEventListener(Event.ENTER_FRAME,grow);
}
private function grow(e:Event):void
{
trace("asdda");
}
}
}
As the error says cerc is undefined. So you should define it. Assuming that your 'cerc' is a Sprite,
var cerc:Sprite;

Functions and variables disappearing of scope when using package

In the document class, I got the following code:
package {
...
public class Main extends Sprite {
public function Main(){
...
model:IModel = new Model();
controller:IController = new Controller(model);
var controls:CompositeView = new Controls(model,controller)
//Accessing controls.x provokes 1202: Access of undefined property x in package view
}
}
}
Where class CompositeView is a extension of Component which in turn extends Sprite.
Component:
package view
{
....
public class Component extends Sprite
{
...
}
}
CompositeView:
package view
{
....
public class CompositeView extends Component
{
...
}
}
Controls:
package view
{
....
public class Controls extends CompositeView
{
...
}
}
But unfortunately, when I try to access controls.x I get a undefined property error.
Changing the package for all classes to the same name fixed this issue. E.g use package for everything instead of package and package.view.
What can be done in Actionscript to keep code organization and avoid this issue ?
Problem solved: var controls was used as a package name, changing name of the variable solved.

How pass class reference by using deluxe signals in AS3Signals?

I wanna pass class reference when dispatching the deluxe signals in AS3Signals ?
My code here for dispatch,
public var signal:DeluxeSignal = new DeluxeSignal(this);
protected function button1_clickHandler(event:MouseEvent):void
{
signal.dispatch(new GenericEvent());
}
and here i listen,
protected function creComp(event:FlexEvent):void
{
viewB.signal.add(onDeluxDispatched);
}
private function onDeluxDispatched(e:GenericEvent):void
{
trace(e.target, e.signal);
trace(e.currentTarget);
trace("SignalTest.onDeluxDispatched(e)");
}
But i received null in trace.
where i am wrong ?
from the documentation of DeluxeSignal class ( https://github.com/robertpenner/as3-signals/blob/master/src/org/osflash/signals/DeluxeSignal.as )
/**
* Creates a DeluxeSignal instance to dispatch events on behalf of a target object.
* #param target The object the signal is dispatching events on behalf of.
* #param valueClasses Any number of class references that enable type checks in dispatch().
* For example, new DeluxeSignal(this, String, uint)
* would allow: signal.dispatch("the Answer", 42)
* but not: signal.dispatch(true, 42.5)
* nor: signal.dispatch()
*
* NOTE: Subclasses cannot call super.apply(null, valueClasses),
* but this constructor has logic to support super(valueClasses).
*/
public function DeluxeSignal(target:Object = null, ...valueClasses)
it has to be declared and dispatched that way :
public class ClassName {
public var signal:DeluxeSignal = new DeluxeSignal(this, ClassName);
private function dispatch():void {
signal.dispatch(this);
}
}
then retrieved that way in the referenced class :
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener(classReference:ClassName) {
/* do your stuff with classReference */
}
}
i ran into same issue and that worked for me
Depending on your requirements you may not need to use DeluxeSignal. I'll use Willo's example to illustrate.
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener(classReference:ClassName) {
/* do your stuff with classReference */
}
}
Yes, we get a class reference. But this class reference is not the one that was passed to DeluxeSignal when it was instantiated, but instead it is the one that was passed to dispatch.
public class ClassName {
/* this is not the reference to 'this' that the listener gets. in fact,
all this one does is sit inside the signal as a property */
public var signal:DeluxeSignal = new DeluxeSignal(this, ClassName);
private function dispatch():void {
signal.dispatch(this); // this is the reference that the listener gets
}
}
The reference we passed into the constructor just sits inside a public property called target.
public function DeluxeSignal(target:Object = null, ... valueClasses) {
/* the reference is set as _target and is not used anywhere else in the
class other than in the setter/getter */
_target = target;
valueClasses = (valueClasses.length == 1 && valueClasses[0] is Array) ? valueClasses[0] : valueClasses;
super(valueClasses);
}
public function get target():Object { return _target; }
public function set target(value:Object):void {
if (value == _target) return;
removeAll();
_target = value;
}
So it seems the idea is to access this property when the listener is called, using a reference to the signal:
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener() {
/* not passing the reference in the dispatch() call means we can
still access the target at this point by using... */
childClass.signal.target;
/* but it just feels nicer to have the reference provided as an
argument rather than as a mutable property, right? */
}
}
Technically that works but it doesn't feel great to be getting a reference from what is a mutable property.
Where it might come in handy though is when using a dependency injection framework like Robotlegs, where the signal is injected into a command. Your command wouldn't have a listener with which to be provided a reference in an argument, but it would be able to access the reference from the signal via its target property.
The way Willo used DeluxeSignal here though, you can actually use the plain old Signal class to do exactly the same thing with less overhead.
public class ClassName {
/* note: no pointless use of 'this' in the constructor. instead,
just the types we will actually be providing to the listener */
public var signal:Signal = new Signal(ClassName, String);
private function dispatch():void {
signal.dispatch(this, "Whatever else you want");
}
}
And on the other end you get this.
public class Parent {
private var childClass:ClassName;
private function bindSignal() {
childClass.signal.add(signalListener);
}
private function signalListener(classReference:ClassName, foo:String) {
/* do your stuff with classReference */
}
}
So you get the same result for typing less code and for less inheritance overhead.
Where you might want to use DeluxeSignal though, other than when needing to keep a reference to the target in your DI frameworks, is when you're using native events. DeluxeSignal overrides the dispatch method to do some extra work with those.

AS3 undefined function #1006

I have a parent class called 'main.as'. I am trying to get the child class to call main's function. They both reside in the same folder.
// main.as //
package {
public class main extends MovieClip {
public function main() {
var child:child_mc = new child_mc(this);
}
public function callFunction():void {
trace("Done it");
}
}
}
.
// child.as //
package {
import main;
public class child extends MovieClip {
private var main:MovieClip = new MovieClip();
public function child(main:MovieClip):void {
this.main = main;
main.callFunction();
}
}
}
This is the error I've been getting:
TypeError: Error #1006: callFunction is not a function.
so I tried doing a trace like this
trace(main.callFunction);
and it says undefined. Can someone tell me what I am missing. I get this feeling its a very basic thing that I have overlooked!
Your "child" package is defined as "main". I'm not even sure how it complied, let alone run to the point of showing the error message you got.
I believe the code below should do what you expected.
(I also took the liberty to rename the classes to use CamelCase (with initial caps) to adhere to best practices and to be easier to distinguish from variable names.)
Main.as
package {
public class Main extends MovieClip {
public function Main() {
var child:ChildMC = new ChildMC();
child.main = this;
}
public function callFunction():void {
trace("Done it");
}
}
}
EDIT: I just saw your comment that points out that child_mc is a MovieClip in the Library. I guess then that the child class is set as the Base Class of the child_mc?
If so, you cannot pass properties through the instantiator, you need to find another way to pass along the instance of the Main class to the Child class.
One way would be to add a setter, like the following:
Child.as (Base Class for ChildMC)
package {
public class Child extends MovieClip {
private var _main:Main;
public function Child() {
}
public function set main(main:Main):void {
this._main = main;
this._main.callFunction();
}
}
}

AS3: Not possible to have getters and setters for same variable in different interfaces?

The following code seems to create an ambiguity for the compiler (please see error commented near the bottom). Is it not possible to have getters and setters split between interfaces?
public interface GetterInterface
{
function get test():int;
}
public interface SetterInterface
{
function set test(value:int):void;
}
public interface SplitTestInterface extends GetterInterface, SetterInterface
{
}
public class SplitTest implements SplitTestInterface
{
public function SplitTest()
{
}
/* INTERFACE test.SetterInterface */
public function set test(value:int):void
{
}
/* INTERFACE test.GetterInterface */
public function get test():int
{
return 0;
}
}
//Somewhere...
var splitTest:SplitTestInterface = new SplitTest();
splitTest.test = 2; //Error: Property is read-only.
I put together the following (which is all but identical to your code) and works fine for both the get and set method.
/* IGet.as */
package {
public interface IGet
{
function get test():int;
}
}
/* ISet.as */
package {
public interface ISet
{
function set test(i:int):void;
}
}
/* ISplit.as */
package {
public interface ISplit extends IGet, ISet {
}
}
/* SplitTest.as */
package {
public class SplitTest implements ISplit {
public function SplitTest() {
}
public function set test(i:int):void {
trace("Set");
}
public function get test():int {
trace("Get");
}
}
}
The following is on the maintimeline:
var foo:SplitTest = new SplitTest();
foo.test;
foo.test = 1;
And outputs:
Get
Set
Interesting question. Based on the output, it looks like the compiler doesn't really understand what's going on. Using a custom compiler to call force the call in the player results in
Property SplitTestInterface::test not found on SplitTest and there is no default value.
So the answer is no. It's not supported by the language, and it's not supported by the runtime. That's good though, I would never want to see this in production code.
Edit: My test was messed up, actually it works fine in the runtime.