Is it bad to prefix all of my framework class names? - actionscript-3

I develop a lot of frameworks for Flash games and applications. I have always prefixed my class names with a random character or two, to avoid conflict with class names that the developer may already have, for example:
class LEntity
Recently I had a co-worker blast me for poor and "annoying" naming of classes who then proceeded to rename every class in the frameworks I've created for people here to use.
I'm having trouble explaining my reasoning thoroughly enough for him to accept what I've done as a good approach.
Is what I've done above actually a bad thing? If not, how can I explain otherwise? If so, why?
Comments are asking about namespaces - I know AS3 in this example has what I know to be called a namespace but I'm not sure if this is the same thing or if it can be used as expected.

Given that Actionscript supports namespaces, there is no reason to use prefixes simply to prevent naming clashes. That's what namespaces are for.
Some people like to use namespaces to significy member variables (ie, underscore prefix, or sometimes m_) and that has some merit, but simply for the sake of name clashing no.

It sounds like you don't quite understand what namespacespackages are in AS3.
An example:
//Class1.as
package com.test.someModule { //This is the package/namespace
public class Class1 {...}
}
//Class2.as
package com.test.otherModule {
import com.test.someModule.Class1; //Class1 can be used as "Class1" now. Otherwise you would do "com.test.someModule.Class1"
import com.test.someModule.*; //You can also use the "*" to "import" all classes in that package
}

I have to agree with your co-worker, your class names are 'annoying'.
In Actionscript 3 we use the package name to define the namespace of a class. If you're not sure what namespace means, take the wikipedia definition (as of the time of writing):
"In general, a namespace is a container for a set of identifiers
(names), and allows the disambiguation of homonym identifiers residing
in different namespaces."
So you will never "conflict with class names" as long as you name your packages correctly. Most developers use what is called the reverse domain notation to name their packages (e.g com.mywebsite.MyGenericNamedClass). Domain names are unique so it's very unlikely you would clash with another class.
As a rule of thumb the class name should be as descriptive as possible, so some of your class names will be the same as someone else's class. Take the default Sprite class for instance:
import flash.display.Sprite;
import uk.co.mywebsite.Sprite;
if you then initialize an object:
var mySprite:Sprite = new Sprite();
The compiler would not know which Sprite you want to initialize (is it the flash sprite or your own custom sprite), and it would throw an error.
The solution is simple: because your packages have been named properly, all you need to do is to use the full class name including the package name to initialize your object:
var mySprite:uk.co.mywebsite.Sprite = new uk.co.mywebsite.Sprite();
var myOtherSprite:flash.display.Sprite = new flash.display.Sprite();
Mind you, you would rarely need to do that. This is only necessary if you want to use those two classes (the default Sprite and your own Sprite) in the same scope. Generally, you would only import your own class:
/* we are not importing this any more
import flash.display.Sprite;*/
//only importing my own class
import uk.co.mywebsite.Sprite;
/* now I can initialize my object without using the full class name, and the compiler knows
I mean my own Sprite class */
var mySprite:Sprite = new Sprite();

Related

Created new package and imported but Definition not found

I have created a simple parser package called parseLine.
I have it in a package in my project.
In parseLine I have a class called "myParse".
I can import it just fine.
import parseLine.myParse.*;
But when I compile I get an error "1172:Definition parseLine.myParse could not be found.".
This is pretty basic I know but would appreciate any help anyone my be able to offer.
myParse is not a package, it is a class, so you are importing it incorrectly.
Basic structure of a package:
src / my / package / name / ClassName
To import ClassName, you would use this:
import my.package.name.ClassName;
or
import my.package.name.*;
In ClassName, it must have the following setup:
package my.package.name {
public class ClassName {
// class code goes here
}
}
As an additional tip, you should follow standard naming schemes for AS3.
Package names should be all lowercase. Even if it is multiple words. my.packagename is proper, whereas my.packageName is not.
Class names should be UppercaseCamelcase. So ClassName is proper, whereas className and classname are not
All objects, including functions, should be lowercaseCamelcase. So var someObject is proper, whereas var SomeObject is not (same for function doSomething() vs function DoSomething())
Constants should be UPPERCASE_UNDERSCORE_SEPARATED. So const SOME_CONSTANT_VALUE is proper, whereas const someConstantValue is not.
Not using those rules won't break anything, but they are the accepted standards in AS3 which makes your code easier to read and maintain in the future.

Namespace vars between Classes

Synopsis
How do you declare variables in a namespace while using the use statement? (ie., without declaring the namespace with the variable name)
How do you reference namespace variables with the "use" statement without a container reference. (ie., trace(foo) rather than trace(a.foo) [seems kinda pointless if I have to state this after already switching to the namespace])
Explanation
Having read Grant Skinner's "Complete Guide to Using Namespaces", and other articles, such as Jackson Dustan's "Better OOP Through Namespaces", I'm left with the above unanswered questions. I feel as though I'm missing some basic principle, but I can't seem to get namespaces to work. The following examples are written for use with the Flash IDE, so assume the following...
locus.as
package com.atriace {
public namespace locus = "atriace.com";
}
testA.as
package com.atriace {
public class testA {
import com.atriace.locus;
locus var foo:String = "Apple";
public function testA() {}
}
}
testB.as
package com.atriace {
public class testB {
import com.atriace.locus;
use namespace locus;
public function testB() {
trace(foo);
}
}
}
Document Class:
import com.atriace.testA;
import com.atriace.testB;
var a:testA = new testA();
trace(a.foo); // results in "Apple"
var b:testB = new testB(); // compile error: variable "foo" not defined.
Issue #1
In my mind, a namespace is little more than an object to hold variables that has scope level access. Ergo, global is a namespace visible to all functions (since it's the root scope), local is namespace (specific to the current and child scopes), and so on. If true, then switching to a namespace with use should allow you to simply declare variables that happen to exist in both the local and custom namespaces. For example:
use namespace locus
var bar:String = "test"; // this now *should* exist in both local & locus scope/namespace.
Since I'm unaware of a method to iterate over a namespace like a normal object, I don't know whether this is what happens. Furthermore, I haven't seen any cases where someone has declared a custom namespace variable this way, so I assume namespace variables must always be explicitly defined.
Issue #2
You might ask, "what's the goal here?" Quite simply, we want a dynamic pool of variables and methods that any new classes can add to (within the same package). By switching to this namespace prior to calling methods, we can reduce the wordiness of our code. So, class.method() becomes just method().
In testB.as we'd fully expect an error to occur if we never imported the testA.as class and instantiated it; especially because foo isn't a static member of the class (nor do we want it to be). However, since we've instantiated foo at least once, the namespace locus should now have a variable called foo, which means that when testB.as gets instantiated, and the constructor seeks a value for foo, the namespace already has one.
Obviously, there's a flaw in this thinking since the Flash compiler complains that foo has never been declared, and the only way I can reference foo from the document class is by referencing the container (ie., a.foo rather than just switching to the namespace with use, and tracing foo directly).
For the sake of argument, neither inheritance nor static members are a solution to this dilema. This is both an excercise in learning better code techniques, and an answer to the structure of a large utility class that has complicated dependencies. Given the absence of a variable/method, you could simply code around it.
I know it's not a heavily documented topic, which is why I'm hoping some sage here may see what I'm missing. The help would be much appreciated. :)
"use namespace" is for the consumer side. You always have to include the namespace in any declaration:
MyNamespace var foobar : uint;
If you wish to add namespaced package-global variables (you shouldn't as a general rule), you have to define each one of them in a separate .as file as packages only allow one publicly-visible definition per file at the top-level.
In your example above you are using namespaces incorrectly. A namespace can span multiple classes, but does not achieve the cross-class functionality you are looking for. This is more the domain of aspect-oriented programming.

Using instances already on stage from another class

I'm new to this OOP stuff, and I'm having a hard time understanding all of this.
I'm trying to recreate in AS3.0 with classes a simple whack-a-mole game I created in AS2.0 using timeline coding.
I've read through a lot of forums, but I still don't understand what exactly I'm doing wrong.
Heres my setup:
I have a movie clip named mrBunny (my girlfriend told me to change it to bunnies as moles were too ugly.). Now there are 6 instances of mrBunny on the stage, each named mrBunny0-5.
The mrBunny symbol is linked to the com.mrBunny class.
The class has a method called randomPlay(); which I use to randomize the animation times of mrBunny.
I also have a button on the stage with the class stageBtn.
package com{
import flash.display.SimpleButton;
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.MouseEvent;
public class startBtn extends SimpleButton {
//Constructor
public function startBtn() {
this.addEventListener(MouseEvent.CLICK, startClick);
}
public function startClick(event:MouseEvent):void {
mrBunny0.randomPlay();
mrBunny1.randomPlay();
mrBunny2.randomPlay();
mrBunny3.randomPlay();
mrBunny4.randomPlay();
mrBunny5.randomPlay();
}
}
}
I want to be able to use the startBtn to start the animation of the mrBunny# instances.
As far as I am aware, I'm not fully grasping the situation of classes and OOP.
(The bunnies were just too cute to pass on this question, so here goes...)
There are several problem areas to consider in your code about OOP. I will try to explain them a bit.
Package Names:
Package names are given in order to uniquely identify a class. Consider the situation when you are using a 3rd party library, which has a StringUtils class. You also happen to have a StringUtils class yourself. How do you store them in your work folder? How do you address each of them in your code?
Packages, as the name implies, provide a mechanism to group classes. So when you refer to your class you might address it as com.joemidi.utils.StringUtils and the other as com.someoneelse.utils.StringUtils. Package names can be anything you like, as long as it reflects the folder structure. But, as an industry standart people use URLs in their package names, as they are guaranteed to be unique. This is the reason you see com in many packages. In your situation it is better if you restructure your packages (and folder structures) according to this.
Stage Instances from the IDE:
When you create instances in the Flash IDE, you must remember where you put them and whether your code knows about them or not. The bunnies, as #weltraumpirat said, are not inside your startBtn. The proper way to do what you are trying to do is this:
Main:
+ contains the bunnies.
+ listens to startButton for MouseEvent.CLICK
+ when startButton is clicked, manipulates the bunnies.
That said, we realize there is another problem:
Don't Rely on Instance Names:
You should instantiate (that is, create new) bunnies in your code, not in the Flash IDE; and access them from a central variable. For example:
public class Main extends MovieClip {
var bunnies:Array = new Array();
public function Main() {
createBunnies(7);
startButton.addEventListener(MouseEvent.CLICK, onStartClicked)
}
protected function createBunnies(bunnyCount:int):void {
for (var i:int = 0; i < bunnyCount; i++) {
var bunny:Bunny = new Bunny();
addChild(bunny);
// configure bunny.x, bunny.y, etc. here.
bunnies.push(bunny);
};
}
protected function onStartClicked(e:MouseEvent) {
for (var i:int = 0; i < bunnies.length; i++) {
var bunny:Bunny = bunnies[i];
bunnies.randomPlay();
};
}
Here, you are no longer bound to what instance names you gave to the bunnies. (Of course, I'm just assuming your stage structure here.) And this way, the bunnies are more "independent" of the code above them. Also, you could use a holder sprite and track the bunnies from there, but it might be a bit advanced right now.
Hope these may prove useful to you. If you are serious about this subject, you might like to read more on OOP, specifically on why it is needed, and key terms about it: decoupling, inheritance, encapsulation, etc.
startBtn doesn't have members mrBunny0-5, the main timeline does. Try root.mrBunny0 instead.

AS3 - Parametrized Factory method using actual class name

Rather than use a hard-coded switch statement where you pass it the string name of a class and it then instantiates the appropriate class, I'd like to pass the actual name of the class to my factory method and have it dynamically create an instance of that class. I thought it would be trivial and am surprised it is not working. I must be missing something quite basic:
sample code:
createProduct(50, "Product1Class");
createProduct(5, "Product2Class");
private function createProduct(amount:uint, productClassName:String):void {
var productReference:Class;
try {
productReference = getDefinitionByName(productClassName) as Class;
for (var i:uint = 0; i < amount; i++) {
var product = new productReference() as ProductBaseClass; // throws reference error!
}
} catch (error:ReferenceError) {
throw new ReferenceError(error.message + " Have you linked a library item to this class?");
}
}
The only thing that may be a little odd (not sure) is that these "products" are actually linked Library items (ie: I have a movieClip in the Library that has a linkage to Product1Class and another to Product2Class both of which extend ProductBaseClass, which in turn extends MovieClip.
Why the ReferenceError?
If you have a runtime loaded library then the Class's are not compiled into the main swf, so you get the runtime reference error when you try to create them.
To work around this you can declare "dummy" vars of the classes you want to compile, or if using the flex compiler there are options to include the classes you are missing.
e.g. declare these anywhere in your project
private var p1:Product1Class;
private var p2:Product2Class;
Its a frustrating problem, if your classes extend MovieClip which is a dynamic class you might be able to access the properties etc by doing something like this:
var product:MovieClip = new productReference() as MovieClip;
p1["someCustomProperty"]; //Dot notation might work here as it is a dynamic class
Chris is absolutely right, the ReferenceError is actually being thrown during the call to getDefinitionByName, meaning that the reflection method cannot find Product1Class or Product2Class in your application domain. You can always check if a definition is available by checking the application domain directly, like:
// inside your createProduct method, yields 'false'.
ApplicationDomain.currentDomain.hasDefinition( productClassName );
Are these library assets loaded in at runtime? If so, you can either make sure that the library swf is loaded into the current application domain by adding an appropriately configured LoaderContext to your Loader, or you can replace the call to getDefinitionByName with the loaded swf's application domain's getDefinition method.
getDefinitionByName() and ApplicationDomain.currentDomain.hasDefinition() require full qualified class names. The example code in the original post works when Product1Class and Product2Class are in the default package. However, if you move the product classes to another package, you have to make sure that you are supplying the fully qualified class name to getDefinitionByName().
So if we put our product classes in com.example.products, then the call becomes:
productReference = getDefinitionByName("com.example.products.Product1Class") as Class;
I'm not really sure what the best practice is with this kind of dynamic factory class, but what I ended up doing (since all products were in the same package) was to create a constant within my factory class that defines the package for my products:
private const PRODUCT_PACKAGE:String = "com.example.products."; // note the trailing period
So that way your client code doesn't need to know (nor define) the product package. You just prepend this constant to your product class name when using getDefinitionByName().

What are the rules for naming AS3 classes?

I'm trying to write a RegEx for a code generator (in C#) to determine a proper class or package name of an AS3 class.
I know that class names
must start with a letter (capital or otherwise)
any other digit can be alphanumeric
cannot have spaces
Is there anything else?
Although you can start class names with lower case letters and include underscores and dollar signs, the "naming convention" is to start the class name and each separate word with a capital letter (e.g. UsefulThing), and not include underscores. When I see classes like useful_thing, it looks wrong, because it's not the naming convention. Maybe your question should have said what are the valid names for an AS3 class?
Other than that I think you + maclema have it.
The conventions for Class and Package naming as far as I've heard:
The package structure should use the "flipped domain" naming, with lowercase folders and CamelCased class names, i.e.:
import com.yourdomain.nameofsubfolder.YourSpecialClass;
This is reflected in all of the packages shipped with Flash and Flex. Examples:
import flash.events.MouseEvent;
import flash.display.MovieClip;
There is also a convention of naming Interfaces after the functionality they add or impose as in: Styleable, Drawable, Movable etc... Many (including Adobe) also prefer to use an upper case "I" to mark interfaces clearly as such, i.e.:
IEventDispatcher
IExternalizable
IFocusManager
which are all internal interfaces in the flash.* packages.
Here are some more valid classes.
Actionscript 3 classes (and packages) must start with a letter, "_", or "$". They may also contain (but not start with) a number.
public class $Test {}
public class _Test {}
public class test {}