trouble accessing non-static functions from static functions in AS3 - actionscript-3

I have a class containing, among other things, a drop down menu. With the aim of saving space, and since the contents of the menu will never change, I've made a static DataProvider for the whole class that populates each instances menu. I was hoping to populate the list with actual functions like so:
tmpArr.push({label:"Details...", funct:openDetailsMenu, args:""});
and then assign tmpArr to the DataProvider. Because the DataProvider is static the function that contains that code also needs to be static, but the functions in the array are non-static. At first it didn't seem like a problem, because when the user clicks on a menu item the drop down menu can call a non-static "executeFunction(funct, args)" on its parent. However, when I try to compile, the static function setting up the DataProvider it can't find the non-static functions being passed. If the compiler would just trust me the code would work fine!
The simple solution is to just pass strings and use a switch statement to call functions based on that, but that's big, ugly, inelegant, and difficult to maintain, especially if something inherits from this class.
The simpler solution is to just make the DataProvider non-static, but I'm wondering if anyone else has a good way of dealing with this? Making the static function able to see its non-static brethren?
Thanks.

OK, the basic reason for making things static is if you want to make it independant of an instance, for example the Math functions in as3 (you call Math.min() as opposed to var math = new Math(); math.min()...) this is useful for reference, repetetive calculation, simple actions (add 10 to x value) etc.
the problem with combining static and non static functionality is that when calling a static function, there is a possibility that the class has no instance at that point, or (in this case) that there is any reference to the function that would make sense in compilation (if a seperate class called the function, how would it reference openDetailsMenu?).
what you need to do is either go through getting function by name (object"functionname" works for example), make annonymous functions in your array or alternatively add a callback method to your static function something similar to this:
public static function doAction(object:Menu, event:String){
if(event == "details") object.openDetailsMenu() ;
}
all in all you are just adding layers of complexity that isnt really going to help. if you just add a class function and get them all to do the same action it is not taking more space or effort than if you are calling to a static function. you need to think about how and why the function is going to be used in (or out of) the class.

you could just store a static reference to the instance, in this case _instance. ( Kind of like a ghetto singleton ) just be careful not to call the static method before the class has been instantiated.
/// in your constructor define a static reference handle to the instance
public function ClassName(){
_instance = this;
}
public static function doSomethingStatic(){
var varValue = ClassName._instance.someInstanceVariable;
}

Related

AS3 create a variable in root from within a function

I have a fairly big swf right now with a bit of coding already. Most vars are created in the root, but now I have a problem.
I want to reload the flash swf (reset), and for that, I need to create a function that destroys all the vars and another one that creates them. At the moment, I have a javascript function that reloads the page, but that really isnt a good solution.
The problem is that when I create a var inside a function, it doesn't get created in "MovieClip(root)", and instead is only related to the function, thus rendering my swf unable to work.
Is there a way to create vars in MovieClip(root) from within a function? Or is there an alternative to what I'm trying to do?
EDIT: Added some example code.
function SetVar():void{
var test:String= new String("foobar");
}
SetVar();
trace(test);
...and the output is:
Scene 1, Layer 'Layer 1', Frame 1, Line 7 1120: Access of undefined property test.
Which is normal, because the "var test" is not global, so it was lost when the function ended. I want to make it so the function "SetVar()" adds the vars to the root, or global.
You need to read up on how scope works.
Basically:
An object declared within another object (be it a Class, Function, Object, or Loop), is only available within that specific object or loop iteration.
Object scope is inherited by children, not by parents. So a function within a class has access to an object declared within that class, but a class does not have access to an object declared within a function
A parent (or any other object) can access objects declared within child classes, but only if it is a public object
So looking at those basic rules (they are very, very basic. If you are just starting out, I urge you to do some proper research into object scope in OOP. It is the basis of everything you will do in dozens of languages), you are declaring an object in a function and trying to access it from outside that function. This breaks Rule #1 from above.
Instead, try this:
var test:String;
function setVar():void{
this.test = 'foorBar';
}
trace(test); //output: null (undeclared)
setVar();
trace(this.test); // output: fooBar
Looking at this, I did two things:
I moved the declaration of test into global space, meaning any object in that object will have access to it
I renamed SetVar to setVar. This has nothing to do with your question, but in AS3, the standard naming conventions dictate you use lowerCaseCamelCase for all objects (including functions), UpperCaseCamelCase for all Class names, and lowercasename for all package names. Again, unrelated but it is good to learn.
Now, ideally, you would probably want to do that setVar function slightly differently. To allow for better abstraction (basically making your code as generic an reusable as possible), you would want to return the value from the function rather than manually set the variable in the function.
var test:String;
var anotherTest:String;
function setVar():String {
return 'foorBar';
}
this.text = setVar();
this.anotherTest = setVar();
trace(this.test); // output: fooBar
trace(this.anotherTest); // output: fooBar
So that allows you to use that function with any String variable imaginable. Obviously, that is not very useful here since it doesn't do any logic. But I am sure you can see how that could be expanded with more code to make it more dynamic and much more useful
EDIT: As an afterthought, I used the this keyword. In AS3 (and a few other languages), this refers to the scope of the current class (or current frame, in case of timeline frame coding). So this.test refers to a variable test declared in the scope of the frame or class.
I am not entirely sure what you are looking for because there is no code associated with your question. However I will impart a bit of information I feel relates to the subject.
if you declare your variables in the class then you can reference them from a function as such:
package{
import flash.display.MovieClip;
public class DocumentClass extends MovieClip{
public var example:String = 'dog';
public function DocumentClass(){
trace(example); // dog
testFctn();
trace(example); // frog
}
public function testFctn(){
example = 'frog'
}
}
}
if you want to reference the variable of a parent class this.parent['variableName'] can be useful too. or a sibling of your working class sharing a parent class, this.parent['childClass']['variableName'] ...
Since you are declaring the variable within the function, its scope is restricted to that function only.
Try declaring the variable outside the function and initializing it in the function instead.
You should then be able to access it from root.
But if you wish to declare a variable on root from within a function (highly unusual requirement) then you can try doing:
document["variableName'] = value;
or
root["variableName'] = value;
inside the function.

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.

Passing Model to View constructor for Stage Instances

I'm looking for an elegant solution to setting the Model argument for a View that is a stage instance.
My View constructor looks like this:
public function View($model:Model, $controller:IController=null){ ... }
My Subclass constructor:
public function ViewSubClass($model:Model, $controller:IController=null){ ... }
The idea is that the subclass will be a UI element that I'd rather just have on stage and not have to position it manually. I've thrown around the possibility of having placeholder elements that get removed and using their positions to attach the real UI elements but it seems a little hackish to me.
I suppose I could always set the default value of the $model argument in View to null, but not all views will be stage instances so I don't exactly want to do that either.
Any thoughts are appreciated.
Flash has no way to populate constructor parameters. This is why I always suggest avoiding constructor parameters for View. If this is your own Class, I'd suggest to go ahead and fix the parent Class so it doesn't need this.
If it is not, you can use
public function VewSubClass() {
super(null, null);
}
I would be concerned here that you actually need the Model and controller, so I would make setters available on the View subclass and then populate those variables once the instance arrives on stage.
public function set model(value:Model):void {
_model = value;
//do whatever the super constructor did based on receiving the model
}
public function set controller(value:IController):void {
_controller = value;
//etc.
}
Note that it probably shouldn't be necessary for the View to know about the controller, and I wouldn't suggest that the entire model be given to the View either--just the few properties it needs. So if the Class is yours, that puts you into a better position to correct these (IMO) architectural problems.
Based on the signature you've provided, I wouldn't be at all surprised to find that the model and controller internal storage are private, rather than protected, which means you're pretty much faced with a rewrite anyway (assuming the model and controller are needed on the View).
I solved the issue by changing the ViewSubClass constructor to:
public function ViewSubClass ($model:Model=null, $controller:IController=null){ ... }
Not sure why I was thinking that the constructor had to match the superclass' constructor perfectly. I'm still open to more elegant solutions if there are any. Thanks for looking.
-Veo

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.

Function Parameter best practice

I have question regarding the use of function parameters.
In the past I have always written my code such that all information needed by a function is passed in as a parameter. I.e. global parameters are not used.
However through looking over other peoples code, functions without parameters seem to be the norm. I should note that these are for private functions of a class and that the values that would have been passed in as paramaters are in fact private member variables for that class.
This leads to neater looking code and im starting to lean towards this for private functions but would like other peoples views.
E.g.
Start();
Process();
Stop();
is neater and more readable than:
ParamD = Start(paramA, ParamB, ParamC);
Process(ParamA, ParamD);
Stop(ParamC);
It does break encapsulation from a method point of view but not from a class point of view.
There's nothing wrong in principle with having functions access object fields, but the particular example you give scares me, because the price of simplifying your function calls is that you're obfuscating the life cycle of your data.
To translate your args example into fields, you'd have something like:
void Start() {
// read FieldA, FieldB, and FieldC
// set the value of FieldD
}
void Process() {
// read FieldA and do something
// read FieldD and do something
}
void Stop() {
// read the value of FieldC
}
Start() sets FieldD by side effect. This means that it's probably not valid to call Process() until after you've called Start(). But the code doesn't tell you that. You only find out by searching to see where FieldD is initialized. This is asking for bugs.
My rule of thumb is that functions should only access an object field if it's always safe to access that field. Best if it's a field that's initialized at construction time, but a field that stores a reference to a collaborator object or something, which could change over time, is okay too.
But if it's not valid to call one function except after another function has produced some output, that output should be passed in, not stored in the state. If you treat each function as independent, and avoid side effects, your code will be more maintainable and easier to understand.
As you mentioned, there's a trade-off between them. There's no hard rule for always preferring one to another. Minimizing the scope of variables will keep their side effect local, the code more modular and reusable and debugging easier. However, it can be an overkill in some cases. If you keep your classes small (which you should do) then the shared variable would generally make sense. However, there can be other issues such as thread safety that might affect your choice.
Not passing the object's own member attributes as parameters to its methods is the normal practice: effectively when you call myobject.someMethod() you are implicitly passing the whole object (with all its attributes) as a parameter to the method code.
I generally agree with both of Mehrdad and Mufasa's comments. There's no hard and fast rule for what is best. You should use the approach that suits the specific scenarios you work on bearing in mind:
readability of code
cleanliness of code (can get messy if you pass a million and one parameters into a method - especially if they are class level variables. Alternative is to encapsulate parameters into groups, and create e.g. a struct to whole multiple values, in one object)
testability of code. This is important in my opinion. I have occassionally refactored code to add parameters to a method purely for the purpose of improving testability as it can allow for better unit testing
This is something you need to measure on a case by case basis.
For example ask yourself if you were to use parameter in a private method is it ever going to be reasonable to pass a value that is anything other than that of a specific property in the object? If not then you may as well access the property/field directly in the method.
OTH you may ask yourself does this method mutate the state of the object? If not then perhaps it may be better as a Static and have all its required values passed as parameters.
There are all sorts of considerations, the upper most has to be "What is most understandable to other developers".
In an object-oriented language it is common to pass in dependencies (classes that this class will communicate with) and configuration values in the constructor and only the values to actually be operated on in the function call.
This can actually be more readable. Consider code where you have a service that generates and publishes an invoice. There can be a variety of ways to do the publication - via a web-service that sends it to some sort of centralized server, or via an email sent to someone in the warehouse, or maybe just by sending it to the default printer. However, it is usually simpler for the method calling Publish() to not know the specifics of how the publication is happening - it just needs to know that the publication went off without a hitch. This allows you to think of less things at a time and concentrate on the problem better. Then you are simply making use of an interface to a service (in C#):
// Notice the consuming class needs only know what it does, not how it does it
public interface IInvoicePublisher {
pubic void Publish(Invoice anInvoice);
}
This could be implemented in a variety of ways, for example:
public class DefaultPrinterInvoicePublisher
DefaultPrinterInvoicePublisher _printer;
public DefaultPrinterInvoicePublisher(DefaultPrinterFacade printer) {
_printer = printer
}
public void Publish(Invoice anInvoice) {
printableObject = //Generate crystal report, or something else that can be printed
_printer.Print(printableObject);
}
The code that uses it would then take an IInvoicePublisher as a constructor parameter too so that functionality is available to be used throughout.
Generally, it's better to use parameters. Greatly increases the ability to use patterns like dependency injection and test-driven design.
If it is an internal only method though, that's not as important.
I don't pass the object's state to the private methods because the method can access the state just like that.
I pass parameters to a private method when the private method is invoked from a public method and the public method gets a parameter which it then sends to the private method.
Public DoTask( string jobid, object T)
{
DoTask1(jobid, t);
DoTask2(jobid, t);
}
private DoTask1( string jobid, object T)
{
}
private DoTask2( string jobid, object T)
{
}