What are the main differences (advantages/disadvantages) of declaring functions inside the default constructor function of a new class and functions declared outside the default constructor function? Is the access to access modifiers the only reason to declare functions outside default constructor functions?
Thank you.
If you mean this:
public class MyClass {
public function MyClass() {
function myFunction() : void {
}
}
}
then the main difference is not only visibility, but scope: myFunction() is declared as a temporary function, which can only be called from within the same method. After execution of the constructor is done, the function is discarded and garbage collected, as would any temp variable. You can easily verify this: Simply add a "regular" member function and try to call myFunction() from there - compilation will fail. So, of course, will trying to access the function from another class.
If you were referring to declaring the function as a variable, and initializing it from within the constructor, the main difference is type safety.
Consider this standard declaration:
public class MyClass {
public function myFunction ( param1:String ) : String {
// doSomething
return myString;
}
public function MyClass() {
}
}
We've declared a member function with a strictly typed parameter and a strictly typed return type. If we try to access this function in a way that does not comply with the declaration, the compiler will throw an error, and compilation will fail, just as one would expect.
Now the same declaration from within the constructor:
public class MyClass {
public var myFunction : Function;
public function MyClass() {
myFunction = function ( param1:String ) : String {
// doSomething
return myString;
}
}
}
We've declared a strictly typed member variable of type Function that is initialized to do the same thing as the member function above. But its strictly typed parameter and return type are evaluated by the compiler only within the scope of the declaration - if, for example, you try to access the function specifying too many parameters:
myClassInstance.myFunction ("whatever", "and", "some", "more");
the compiler won't complain, because both the parameter and return type are now only checked at runtime, instead of at compile time (there would still be an error, of course). So the major disadvantage of this approach is the lack of compile time type checking - errors will occur at runtime and will thus be harder to debug.
One advantage of this approach is that we could exchange this function at any time:
myClassInstance.myFunction = function ( i:int ) : void { trace (i); };
This is perfectly legal and will obviously change the object's behavior significantly. If we would do the same in the member function example, the compiler would also throw an error.
Related
I want to know whether in ActionScript 3 there's a way to share a same function (method) between the instances of a class definition, only referencing the same function everytime... i.e., this example should log true, but logged false (note: I'd want this to reduce duplicating functions).
class A {
function f() {}
}
trace(
(new A).f === (new A).f
)
An ActionScript 3 language specification appears to say that a prototype attribute exists, but not implemented. I've understood that individual classes have a prototype object. I've specially found a prototype property (probably inherited from Class/Object) and wonder if classes use meta functions in order to be constructed (since their type is "object"... when I test with typeof: trace(typeof A, typeof Class, typeof Object)).
My last try:
class A {}
A.prototype.f = function() {}
trace(
(new A).f === (new A).f
)
It says that f doesn't exist. I could define this class as a function instead (in order to move methods to the prototype object):
function A() {}
A.prototype.f = function() {}
, but in this way I can't control access of instance members.
AS3 uses Bound methods to ensure that inside your functions, this always points to original instance object by default.
Imagine that you pass a function f of an instance a to some other object b. When then object b calls function f, the this name still points to a inside scope of the function - this reference has to be store somewhere.
Well, you could assign function to static property of your class:
package adnss.projects.evTest
{
public class A {
private var x:Number = 5;
private var _y:Number = 0;
public function A(){}
static public const f = function (p:Number):Number {
this._y = p;
return this.x*p;
}
public function get y():Number { return _y; }
}
}
And then have access to private properties of the instance of A in that static function by explicitly using this:
var instance:A = new A();
trace("return:", A.f.call(instance, 3)); //return: 15
trace("instace:", instance.y); //instance: 3
But that is kind of tricky for possible benefits (if any).
And about prototypes. You basically don't use them in AS3. Is't there like a souvenir :) - read this for more info
I want to create a internal ctor for class in ActionScript3 to make it immutable. I want that only another builder class will be allow to create instances of this immutable class.
I try to find the answer in Adobe's ActionScrtip 3 specification but it does not explain what happen when no public namespace (accessible) is define for ctor.
Immutable object:
package {
public class Immutable {
private var _value1:int;
private var _value2:int;
private var _value3:int;
public function Immutable(value1:int, value2:int, value3:int) {
_value1 = value1;
_value2 = value2;
_value3 = value3;
}
public function get value1():int {
return _value1;
}
public function get value2():int {
return _value2;
}
public function get value3():int {
return _value3;
}
}
}
As for access modifiers, internal is default.
The internal attribute is similar to the default access control in Java, although in Java there is no explicit name for this level of access, and it can be achieved only through the omission of any other access modifier. The internal attribute is available in ActionScript 3.0 to give you the option of explicitly signifying your intent to make a property visible only to callers within its own package.
As for constructor, you can't specify internal. If you omit access modifier, by default constructor will be accessible (public)
How do I use an unevaluated (and/or possibly undefined) variable as a parameter for a function? For example:
function myFun(a:int):void {
a = 5;
}
If you are familiar with Mathematica it would be equivalent to:
f[a_Integer]:=a=5
Attributes[f]={HoldAll};
The core idea being that it is the variable's name itself which I want to pass to the function, not the value which is current associated with the variable's name.
You can pass a string.
private function my_fun(name:String):void {
trace(this[name]);
}
Example of use:
public class Main extends Sprite {
public var a:int = 5;
....
public function Main():void {
my_fun("a");
}
According to these guys: get string representation of a variable name in as3 if it's a classe you can get it's name. If it's a local variable you cannot, the reason is probably related with efficience (the name gets lost on compiling phase)
Another way you could solve the problem is to use closures to change evaluation scopes.
public class A {
public static function myFun(setter:Function):void {
setter(5);
}
}
public class B {
function someOtherFunction() {
var val:Number;
A.myFun(function(v:Number):void { val = v; });
trace(val); // 5
}
}
Instead of passing a value, I'm passing a function that is bound in the calling scope that is evaluated in the callee's scope.
I've asked this same question with Python.
Now I like to know if this can be done in AS3.
If I have something like this:
package
{
public class SomeClass
{
private function A():void { C() }
private function B():void { C() }
private function C():void
{
// who is the caller, A or B ???
}
public function SomeClass()
{
A()
B()
}
}
}
Despite the design or other issues, this is only a question of an inquiring mind.
Note: I like to have an access to an instance of the caller function so I can call that caller function (if I want to)
Note 2 : This has to be done without changing function C() signature
"Unlike previous versions of ActionScript, ActionScript 3.0 has no arguments.caller property. To get a reference to the function that called the current function, you must pass a reference to that function as an argument."
From http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/arguments.html
That's the only way you can do that, otherwise you'll need to make a global variable to tell what function is calling C
Sure it can be done. You can do something like
private function C():void
{
var e:Error = new Error();
var stack:String = e.getStackTrace();
//analyze stack and find out which function called it.
}
this is ugly but it would work.
Background
I am developing a highly modular application in pure Action Script 3 (we are using Flex 4 SDK to automate our builds, but all our code must be able to compile directly in Flash CS4 Professional).
We have a "framework.swc" file which contains interface definitions which are shared between all our modules, we have a "mainmodule.swf" that loads our other modules, and then we have various .swf files for our other modules. We are using the Loader class, in conjuction with ApplicationDomain::getDefinition() for loading classes dynamically [we use "new LoaderContext(false,ApplicationDomain.currentDomain)"].
Problem
All our modules implement the "AbstractModule" interface, which is defined in "framework.swc". When I instantiate a dynamically loaded module, however, (module is AbstractModule) returns false. More importantly, if I call module.someMethod(someobject), where someobject implements an interface defined in "framework.swc" and where the module's method expects an object of the same interface defined in "framework.swc", I get a runtime error "TypeError: Error #1034: Type Coercion failed: cannot convert _ to _."
It seems that "mainmodule.swf" and "loadedmodule.swf" (the module I have been loading for testing), are, internally, using separate definitions for the shared interfaces in "framework.swc"
Question
How can I make "mainmodule.swf" and "loadedmodule.swf" resolve their common interfaces to a shared definition, so that class casting and class comparison succeed correctly?
Ok. This isn't the prettiest solution, but it will work. Basically, for every interface "AbstractX" (replace "X" with something else), you need to create two wrapper classes: "ImportX" and "ExportX". The goal of ExportX is to successfully widen AbstractX to type Object, by wrapping an AbstractX, providing all the same methods as type AbstractX, but to use only builtin/predefined data types or data types which are part of flash in their signatures. The goal of ImportX is to narrow a dynamically loaded object with the same characteristics as type AbstractX (but which cannot be cast to type AbstractX and which is not recognized as type AbstractX) but is of type Object to the AbstractX interface. Both ExportX and ImportX use ImportY, ImportZ, etc.; however, ExportX uses ImportY, ImportZ, etc. to wrap parameters, which it delegates to an object of type AbstractX, while ImportX uses them to wrap return values, which come about from delegating to an object of type Object. To make this a little more understandable, I present the following examples:
public interface AbstractX
{
// The export/import functions are mandatory
// for all such interfaces. They allow
// for the wrappers to be correctly manipulated.
function export() : Object;
function original() : Object;
// The interface functions vary from
// interface to interface. They can
// be called something much more appropriate.
function interfaceFunction1(param : AbstractY) : AbstractZ;
function interfaceFunction2(param : AbstractA) : AbstractB;
}
// A class of type Import_ always implements Abstract_
public class ImportX implements AbstractX
{
// The constructor for an Import_ Object
// is always of type Object.
public function ImportX(obj : Object) : void {
_loadedobj = obj;
_exportobj = obj.export();
}
// Every Import_ class must implement a similar "wrap" function:
public static function wrap(obj : Object) : AbstractX {
var result : AbstractX = null;
if ( obj != null ){
if ( obj is AbstractX ){ // Don't wrap if convertible, directly.
result = obj as AbstractX;
}else if ( obj.original() is AbstractX ){ // Don't double wrap
result = obj.original() as AbstractX;
}else{
// Needs to be wrapped.
result = new ImportX(obj);
}
}
return result;
}
public function export() : Object {
return _exportobj;
}
public function original() : Object {
return _loadedobj;
}
// For the interface functions, we delegate to _exportobj
// and we wrap the return values, but not the parameters.
public function interfaceFunction1(param : AbstractY) : AbstractZ {
return AbstractZ.wrap(_exportobj.interfaceFunction1(param));
}
public function interfaceFunction2(param : AbstractA) : AbstractB {
return AbstractB.wrap(_exportobj.interfaceFunction2(param));
}
private var _loadedobj : Object;
private var _exportobj : Object;
}
// Although an Export_ object provides SIMILAR methods to type Abstract_,
// the signatures need to be changed so that only builtin/predefined types
// appear. Thus Export_ NEVER implements Abstract_.
public class ExportX
{
// The constructor to Export_ always takes an object of type Abstract_
public function ExportX(obj : AbstractX) : void {
_obj = obj;
}
public function original() : Object {
return _obj;
}
public function export() : Object {
return this;
}
// For the interface functions, we delegate to _obj
// and we wrap the parameters, not the return values.
// Also note the change in signature.
public function interfaceFunction1(param : Object) : Object {
return _obj.interfaceFunction1(AbstractY.wrap(param));
}
public function interfaceFunction2(param : Object) : Object {
return _obj.interfaceFunction2(AbstractA.wrap(param));
}
private var _obj : AbstractX = null;
}
// The definition of class X can occur in and be loaded by any module.
public class X implements AbstractX
{
public function X( /* ... */ ) : void {
//...
}
public function export() : Object {
if ( ! _export ){
_export = new ExportX(this);
}
return _export;
}
public function original() : Object {
return this;
}
public function interfaceFunction1(param : AbstractY) : AbstractZ {
// ...
}
public function interfaceFunction2(param : AbstractA) : AbstractB {
// ...
}
private var _export : Object = null;
}
// Ok. So here is how you use this...
var classx : Class = dynamicallyLoadClassFromModule("X","module.swf");
var untypedx : Object = new classx();
var typedx : AbstractX = ImportX.wrap(untypedx);
// Use typedx ...
you should try -compiler.external-library-path as documented here ... that way, you can build one swc having dependancies on an interface, that is not in it, but comes from another, thus avoiding collisions ... don't know how to do that in CS4 though ...
greetz
back2dos
You may want to use a Runtime Shared Library (RSL). An RSL allows you to do dynamic linking. However, I don't know if CS4 can build those. Maybe you could reconsider the "must be able to compile directly in Flash CS4" requirement, or look into compiling using the Flex SDK through macros/scripts in the CS4 IDE.
If that's absolutely not an option, another approach would be to have a looser coupling between modules, and rely on more of an implied common external interface for the module SWFs instead of code-level integration.
I'm not 100% sure if its what you need, but Gaia Framework implements a global API, shared by many swfs to interact with each other. You could check it out and maybe get some ideas. Right now I'm confronted with quite a similar situation as yours, so I'm checking alternatives... this post will be very useful, thanks!