When are class variables loaded? - language-agnostic

See the two ways of class definition:
//definition: 1
public class MyClass{
private MyObject obj = new MyObject();
private String str = "hello world";
// constructor
public MyClass(){
}
}
// definition: 2
public class MyClass{
private MyObject obj = null;
private String str = null;
// constructor
public MyClass(){
obj = new MyClass();
str = "HelloWorld";
}
}
My question is: when are the class variables loaded. How are they loaded?
How does their initialization happen? If their initialization can happen as in definition 1, what is the purpose of a constructor?
Which is the preferred way of defining the class and why? Is the behavior same across C++/C#/Java or this behavior differs across them?
Any clarification comment on the above is welcome.

This depends on the language, but most languages initialize fields before calling the constructor. Generally I advocate doing things in context, initialization is usually only relevant where the fields are declared. However, as John pointed out, sometimes you need to do something which doesn't make sense/is possible in one line.
Also, as always, order is important if you have fields that depend on other fields for their initialization. In some languages, like ActionScript, this means the order of the declarations determine the order of initialization:
Works:
public class Foo
{
private var bar:Array = [1, 2, 3];
private var baz:Array = bar.concat([4, 5, 6]);
}
Doesn't work:
public class Foo
{
private var baz:Array = bar.concat([4, 5, 6]);
private var bar:Array = [1, 2, 3];
}

The constructor is the first function that is run when the class is instantiated into an object.
Class variables are initialized during instantiation, then the constructor is immediately run following that.

In most languages, instance fields (they're not called class variables in any language I know of) will be initialized during instance construction. They are effectively part of the constructor, executed before the actual constructor code.
You can certainly initialize them in explicit constructor code (though save yourself the setting to null if you're going to set them to something else).
You asked what a constructor is for - you can't do everything in an initializer. What if you needed to loop or something?

Related

Accessing properties after using getdefinitionbyname

I'm trying to access properties from a class like this:
public class Oak extends Tree //base class for tree classes
{
public static const CLASS_NAME:String = getQualifiedClassName(Oak);
public var branches:Array;
public function Oak()
{
branches =
[
"Leaf1",
"Leaf2",
];
}
The class trying to access the variable is shown here:
public class TreeTest extends BaseScreen //just extends Sprite, TreeTest is shown on the stage
{
public var oak:Tree;
private var inc:int;
public function TreeTest(pModel:Model)
{
model = pModel;
model.createTree(Oak.CLASS_NAME);
oak = model.getTree(Oak.CLASS_NAME);
inc = 0;
this.addMouseClickListener(0, treeHandler); //from BaseScreen
}
private function treeHandler(e:MouseEvent):void
{
inc++;
this.displayText.text = oak.branches[inc];
}
and the model is shown below:
public class Model
{
public var treeArray:Array;
public function Model()
{
treeArray = new Array();
}
public function createTree(pClassName:String):void
{
var name:String = pClassName;
var ClassReference:Class = getDefinitionByName(name) as Class;
var classInstance:Tree = new ClassReference;
treeArray.push([name, classInstance]);
}
public function getTree(pClassName:String):Tree
{
var treeName:String = pCharacterClassName;
var match:Boolean = false;
var matchArrayRef:int = 0;
for (var i:int = 0; i < treeArray.length; i++)
{
if (match == true)
{
break
}
if (treeArray[i][0] == treeName)
{
match = true;
matchArrayRef = i;
}
else
{
match = false;
}
}
if (match == false)
{
return null;
}
else
{
return treeArray[matchArrayRef][1];
}
}
When I ran this, I got the error "Access of possibly undefined property branches through a reference with static type Tree".
After searching for a solution, I discovered that basically means that the branches array was not in the Tree class. To confirm this, if I went and took public var branches:Array away from the Oak class and put it in the Tree class, the code worked.
Why can I not access variables defined in the Oak class, and have to put everything in the Tree base class? Even if I change var classInstance:Tree to var classInstance:Oak, or even var classInstance:Object, I still get the same error if the array is in the Oak class, not the Tree class.
Like, if I create a new class Pine which would also extend Tree, do I have to put all of Pine's variables in the Tree class too?
You are referencing the oak variable as class Tree, so any property you reference from it should be of class Tree, not any subclasses, because exactly the superclass does not have them, thus compiler does not know how to address memory from branches property. Worse, this addressing might technically differ from subclass to subclass, an that's why directly addressing properties of a subclass via reference of type superclass is not possible.
There is a workaround. You can use hasOwnProperty method defined in Object class to check whether a certain tree has branches, and then address via string-based addressing like tree["branches"].
if (tree.hasOwnProperty("branches")) {
var br=tree["branches"];
trace(br); //or whatever
}
In fact, you can even go like this:
if (tree is Oak) {
var oak:Oak=tree as Oak;
// now all oaks have branches, go get em
trace(oak.branches);
}
Still, this breaks one of the object-oriented programming's core principles - you attempt to explicitly depend on subclasses having variables of certain names and are expecting them to contain values of same meaning across subclasses. Or, with the second approach, you are trying to make code know about every single subclass of Tree that will ever exist. Effectively you try to make subclasses behave as a superclass, without giving the superclass enough properties to provide that behavior in a common manner. This is not how OOP works. So, you should first devise a superclass by assigning it properties and methods of a generic Tree. All trees have branches, so branches should belong to Tree class. All trees can grow() for example, with whatever set of parameters supplied to growth, be it humidity, warmth, soil thickness, etc, but they are the same for all subclasses of Tree, be it oaks or sequoias, thus, grow() method should belong to Tree class as well. They, however, grow differently, and respond to parameters differently, but this is where override comes to help provide different behavior in subclasses.

Are classes methods created individually for instances?

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

AS3 Access stage object in singleton returns null

I know singletons are sensitive subjects, but I really don't want to hear anything about that, or what you think about this implementation. This question is not about that.
So, I have implemented a singleton using a static var with the instance.
private static var instance:SomeClass = new SomeClass();
public static function getInstance():SomeClass {
return instance;
}
SomeClass is a class in the library, and inside that one there some instance called someSymbol.
For some reason, when I use SomeClass as a singleton, every time I want to access someSymbol I get Cannot access a property or method of a null object reference. But if I implement SomeClass with regular instantiation the error disappears.
I've tried accessing someSymbol in different ways but I always get the error.
someSymbol.rotation = 0;
and also
var aSymbol = getChildByName("someSymbol");
aSymbol.rotation = 0;
and also
trace(someSymbol); // null
trace(this['someSymbol']); // null
trace(SomeClass.instance.someSymbol); // throws error
So why do I get null when using this singleton implementation, and not when instantiating the class as usual?
Edit:
Thanks to #Marty Wallace answer, I changed my singleton implementation and now it works.
So, instead of instantiating the instance this way:
private static var instance:SomeClass = new SomeClass();
I instead instantiate it the first time getInstance() is called, as #Marty does it.
I don't know exactly what is going on behind the curtains, but it seems as if SomeClass wasn't fully exported when instantiating before the document class is running.
Your example is working fine for me:
public class Singleton
{
private static var _instance:TestClip;
public static function get instance():TestClip
{
if(_instance === null) _instance = new TestClip();
return _instance;
}
}
And TestClip has an inner MovieClip with the instance name inner:
trace(Singleton.instance.inner); // [object MovieClip]
Do you have any luck if you make a class for SomeClass and make a getter for someSymbol like this?
public function get someSymbol():MovieClip
{
return this["someSymbol"];
}

ActionScript Calling Private Functions By Changing Public Variables?

i've never tried to do this before, so my head a swimming a bit. i'd like to have a public boolean called enabled in myClass custom class. if it's called to be changed, how do i trigger a function from the change?
should i add an Event.CHANGE event listener to my variable? can i do that? or is there a more standard way?
We usually use properties for that.
Properties are just like public variables for the outside -- you can set instance.enabled = true; and so forth.. But you define properties as getters and/or setters functions for the class.
They are the perfect place for custom logic to be executed on value changes.
For example:
public class CustomClass {
private var _enabled:Boolean = false;
public function set enabled(value:Boolean):void {
trace('CustomClass.enabled is now', value);
this._enabled = value;
}
public function get enabled():Boolean {
trace('CustomClass.enabled was retrieved');
return this._enabled;
}
}
Note that they can't have the same name as your private variable and you don't need both of them defined. Actually, you don't even need a variable for a setter/getter. You could use them just like any function -- they just supply you with a different syntax.
For example:
var object:CustomClass = new CustomClass();
object.enabled = false;
if (object.enabled) {
...
}
They are great to expose a simple API, keeping you from rewriting outside code if the class' internals have to change.
AS3 Reference on getters and setters.

Actionscript 3: Can someone explain to me the concept of static variables and methods?

I'm learning AS3, and am a bit confused as to what a static variable or method does, or how it differs from a method or variable without this keyword. This should be simple enough to answer, I think.
static specifies that a variable, constant or method belongs to the class instead of the instances of the class. static variable, function or constant can be accessed without creating an instance of the class i.e SomeClass.staticVar. They are not inherited by any subclass and only classes (no interfaces) can have static members. A static function can not access any non-static members (variables, constants or functions) of the class and you can not use this or super inside a static function. Here is a simple example.
public class SomeClass
{
private var s:String;
public static constant i:Number;
public static var j:Number = 10;
public static function getJ():Number
{
return SomeClass.j;
}
public static function getSomeString():String
{
return "someString";
}
}
In the TestStatic, static variables and functions can be accessed without creating an instance of SomeClass.
public class TestStaic
{
public function TestStaic():void
{
trace(SomeClass.j); // prints 10
trace(SomeClass.getSomeString()); //prints "someString"
SomeClass.j++;
trace(SomeClass.j); //prints 11
}
}
A static variable or method is shared by all instances of a class. That's a pretty decent definition, but may not actually make it as clear as an example...
So in a class Foo maybe you'd want to have a static variable fooCounter to keep track of how many Foo's have been instantiated. (We'll just ignore thread safety for now).
public class Foo {
private static var fooCounter:int = 0;
public function Foo() {
super();
fooCounter++;
}
public static function howManyFoos():int {
return fooCounter;
}
}
So each time that you make a new Foo() in the above example, the counter gets incremented. So at any time if we want to know how many Foo's there are, we don't ask an instance for the value of the counter, we ask the Foo class since that information is "static" and applies to the entireFoo class.
var one:Foo = new Foo();
var two:Foo = new Foo();
trace("we have this many Foos: " + Foo.howManyFoos()); // should return 2
Another thing is static functions could only access static variables, and couldn't be override, see "hidden".