Static vs class functions/variables in Swift classes? - function

The following code compiles in Swift 1.2:
class myClass {
static func myMethod1() {
}
class func myMethod2() {
}
static var myVar1 = ""
}
func doSomething() {
myClass.myMethod1()
myClass.myMethod2()
myClass.myVar1 = "abc"
}
What is the difference between a static function and a class function? Which one should I use, and when?
If I try to define another variable class var myVar2 = "", it says:
Class stored properties not yet supported in classes; did you mean 'static'?
When this feature is supported, what will the difference be between a static variable and a class variable (i.e. when both are defined in a class)? Which one should I use, and when?
(Xcode 6.3)

static and class both associate a method with a class, rather than an instance of a class. The difference is that subclasses can override class methods; they cannot override static methods.
class properties function in the same way (subclasses can override them).

I tried mipadi's answer and comments on playground. And thought of sharing it. Here you go. I think mipadi's answer should be mark as accepted.
class A{
class func classFunction(){
}
static func staticFunction(){
}
class func classFunctionToBeMakeFinalInImmediateSubclass(){
}
}
class B: A {
override class func classFunction(){
}
//Compile Error. Class method overrides a 'final' class method
override static func staticFunction(){
}
//Let's avoid the function called 'classFunctionToBeMakeFinalInImmediateSubclass' being overriden by subclasses
/* First way of doing it
override static func classFunctionToBeMakeFinalInImmediateSubclass(){
}
*/
// Second way of doing the same
override final class func classFunctionToBeMakeFinalInImmediateSubclass(){
}
//To use static or final class is choice of style.
//As mipadi suggests I would use. static at super class. and final class to cut off further overrides by a subclass
}
class C: B{
//Compile Error. Class method overrides a 'final' class method
override static func classFunctionToBeMakeFinalInImmediateSubclass(){
}
}

Regarding to OOP, the answer is too simple:
The subclasses can override class methods, but cannot override static methods.
In addition to your post, if you want to declare a class variable (like you did class var myVar2 = ""), you should do it as follow:
class var myVar2: String {
return "whatever you want"
}

Testing in Swift 4 shows performance difference in simulator. I made a class with "class func" and struct with "static func" and ran them in test.
static func is:
20% faster without compiler optimization
38% faster when optimization -whole-module-optimization is enabled.
However, running the same code on iPhone 7 under iOS 10.3 shows exactly the same performance.
Here is sample project in Swift 4 for Xcode 9 if you like to test yourself
https://github.com/protyagov/StructVsClassPerformance

I got this confusion in one of my project as well and found this post, very helpful. Tried the same in my playground and here is the summary. Hope this helps someone with stored properties and functions of type static, final,class, overriding class vars etc.
class Simple {
init() {print("init method called in base")}
class func one() {print("class - one()")}
class func two() {print("class - two()")}
static func staticOne() {print("staticOne()")}
static func staticTwo() {print("staticTwo()")}
final func yesFinal() {print("yesFinal()")}
static var myStaticVar = "static var in base"
//Class stored properties not yet supported in classes; did you mean 'static'?
class var myClassVar1 = "class var1"
//This works fine
class var myClassVar: String {
return "class var in base"
}
}
class SubSimple: Simple {
//Successful override
override class func one() {
print("subClass - one()")
}
//Successful override
override class func two () {
print("subClass - two()")
}
//Error: Class method overrides a 'final' class method
override static func staticOne() {
}
//error: Instance method overrides a 'final' instance method
override final func yesFinal() {
}
//Works fine
override class var myClassVar: String {
return "class var in subclass"
}
}
And here is the testing samples:
print(Simple.one())
print(Simple.two())
print(Simple.staticOne())
print(Simple.staticTwo())
print(Simple.yesFinal(Simple()))
print(SubSimple.one())
print(Simple.myStaticVar)
print(Simple.myClassVar)
print(SubSimple.myClassVar)
//Output
class - one()
class - two()
staticOne()
staticTwo()
init method called in base
(Function)
subClass - one()
static var in base
class var in base
class var in subclass

Swift class vs static
[Reference vs Value Type]
class is used inside Reference Type(class, function):
computed property
method
can be overridden by subclass
static is used inside Reference Type(class, function) and Value Type(struct, enum, tuple):
computed property and stored property
method
cannot be changed by subclass
protocol MyProtocol {
// class var protocolClassVariable : Int { get }//ERROR: Class properties are only allowed within classes
static var protocolStaticVariable : Int { get }
// class func protocolClassFunc()//ERROR: Class methods are only allowed within classes
static func protocolStaticFunc()
}
struct ValueTypeStruct: MyProtocol {
//MyProtocol implementation begin
static var protocolStaticVariable: Int = 1
static func protocolStaticFunc() {
}
//MyProtocol implementation end
// class var classVariable = "classVariable"//ERROR: Class properties are only allowed within classes
static var staticVariable = "staticVariable"
// class func classFunc() {} //ERROR: Class methods are only allowed within classes
static func staticFunc() {}
}
class ReferenceTypeClass: MyProtocol {
//MyProtocol implementation begin
static var protocolStaticVariable: Int = 2
static func protocolStaticFunc() {
}
//MyProtocol implementation end
var variable = "variable"
// class var classStoredPropertyVariable = "classVariable"//ERROR: Class stored properties not supported in classes
class var classComputedPropertyVariable: Int {
get {
return 1
}
}
static var staticStoredPropertyVariable = "staticVariable"
static var staticComputedPropertyVariable: Int {
get {
return 1
}
}
class func classFunc() {}
static func staticFunc() {}
}
final class FinalSubReferenceTypeClass: ReferenceTypeClass {
override class var classComputedPropertyVariable: Int {
get {
return 2
}
}
override class func classFunc() {}
}
//class SubFinalSubReferenceTypeClass: FinalSubReferenceTypeClass {}// ERROR: Inheritance from a final class

There's one more difference: class can be used to define type properties of computed type only. If you need a stored type property use static instead.
You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.
https://docs.swift.org/swift-book/LanguageGuide/Properties.html

Adding to above answers static methods are static dispatch means the compiler know which method will be executed at runtime as the static method can not be overridden while the class method can be a dynamic dispatch as subclass can override these.

Related

Get class name in constructor

export class InvalidCredentialsError extends Error {
constructor(msg) {
super(msg);
this.message = msg;
this.name = 'InvalidCredentialsError';
}
}
As you can see above, I'm writing InvalidCredentialsError twice. Is there a way to somehow get the class name already in the constructor method and set it? Or does the object have to be instantiated?
In browsers with native ES6 class support, this.constructor.name will display the InvalidCredentialsError. If you transpile the code with Babel it will show Error.
Without Babel (use on Chrome or another browser that supports class):
class InvalidCredentialsError extends Error {
constructor(msg) {
super(msg);
console.log(this.constructor.name);
this.message = msg;
this.name = 'InvalidCredentialsError';
}
}
const instance = new InvalidCredentialsError('message');
With Babel:
class InvalidCredentialsError extends Error {
constructor(msg) {
super(msg);
console.log(this.constructor.name);
this.message = msg;
this.name = 'InvalidCredentialsError';
}
}
const instance = new InvalidCredentialsError('message');
this.myName="literallycopiedclassname"
Is not the same as
this.myName=this.constructor.name
Look at this:
class B extends Error {
constructor() {
super();
this.myName="B";
}
};
class D extends B {constructor() {super();}};
let o=new D(); console.log(o.myName);
And this:
class B extends Error {
constructor() {
super();
this.myName=this.constructor.name;
}
};
class D extends B {constructor() {super();}};
let o=new D(); console.log(o.myName);
As I know, you cannot access static class properties from within constructor of that class an easy way, except when explicitly referencing the class:
this.myName=B.name;
However, you can access static properties of the outermost class of the constructors super()-chain (the class of object being constructed) (and of its ancestors) using this.constructor. If it is, what you want, enjoy the this.constructor.name construction.
If you want to record the class name from within the constructor defined by that class, you need to explicitly reference the class, but then you need to write it's identifier once more as well. However, it doesn't need to be a string literal, as shown above. If the reason for your question is that you dislike using string literals where not necessary and/or you will avoid maintaining all the identifier-names and literals when renaming the class(es), you can try the following:
If you write
class B extends Error {};
Then B is an identifier refering to the class being defined, accessible in the class' body, AND that class' static property "name" (B.name) is set to it's literal representation (B.name="B"). Additionally, if written this way, it behaves like this:
B=class B extends Error {};
So you can reference the class with B from outside the class' body as well. But you can also write
C=class B extends Error {};
Than you can reference the class with C from outside, with B from inside and the "name" property becomes "B". It shows, that the "internal" name can differ from the name of variable holding the reference to the class. You can name it at will and there is no need to rename it:
const C=class ThisClass extends Error {
constructor() {
super();
this.myName=ThisClass.name;
}
};
let o=new C();
The drawback is, that your class will have the internal name ThisClass. It may or may not be wrong, all classes can have the same internal name without interferring, when you don't use it for some (e.g. debug) purposes. After all, the internal name can be reassigned (again, to whatever you want):
Object.defineProperty(C,"name",{value:"C", configurable:true});
However, you have to write it as a string literal again. But there is a workaround:
You can save the reference to the class whereever you want:
const cName="YourClass";
const classes={};
classes[cName]=class ThisClass extends Error {};
All put together:
const cName="YourClass";
const classes={};
Object.defineProperty (
classes[cName]=class ThisClass extends Error {
constructor() {
super();
this.myName=ThisClass.name;
}
},
"name",
{value:cName, configurable:true}
);
class D extends classes[cName] {
constructor() {super();}
};
let o=new (classes[cName])();
console.log("YourClass myName", o.myName);
console.log("YourClass constructor", o.constructor.name);
let od=new D();
console.log("D myName", od.myName);
console.log("D constructor", od.constructor.name);
Now there is only one place, where the class name is specified, as string literal. And you don't need to rewrite the name in new...

AS3 - how to extend this function

This is first class with "gordz()" function
public class Model extends Object implements IModel
{
public static function gordz() : void
{
newobject = gallas.pop();
}
}
Now i try to override the function but i still want that old code is executed... How can i extend this function correctly?
public class LOL extends Model
{
override public static function gordz() : void
{
... //New code + execute old code
}
}
Neither super
You cannot use the super statement in a static method.
nor override
You cannot use the override attribute on any of the following:
[...]
Static methods
can be used in a static method.
Whatever you are trying to do should be accomplished in a different way.

How to Override Constants in ActionScript 3

I have the two following classes:
public class Parent{
static internal const _name:String = "Parent";
public function get name():String{
return _name;
}
}
public class Child{
static internal const _name:String = "Child";
}
If I create an instance of class Child and call its name() getter, since it will call the name() method it inherits from Parent, it returns "Parent". I could, of course, override the name() method:
public class Child{
static internal const _name:String = "Child";
override public function get name():String{
return _name;
}
}
That returns "Child". However, it seems silly to have to copy the exact same code of the method from the parent. Is there any simpler way to do this?
I would take a different approach by making the "name" property a requirement for the parent's constructor:
public class Parent
{
static internal var _name : String;
public function Parent(name : String = "Parent") {
_name = name;
}
public function get name() : String {
return _name;
}
}
Child Class:
public class Child extends Parent
{
public function Child() {
super("Child");
}
}
Firstly, you cannot override static methods or properties - they are not inherited, so no override for them.
Secondly, if you declared a constant to be of a complex type, it is not really a constant. I.e. if it is an object, then you can change its keys / values, if it is an array, you can add / remove members and so on.
But the desire to make this functionality more generic is understandable. So, what I'd do:
Have some property outside both parent and child, let say in class X, or package Y. Let it be package Y. So, you'd create a dictionary in package Y, let it be Y.names and in your name getter you'd do:
import Y.names;
. . .
public function get name() {
return names[(this as Object).constructor];
}
your names variable would be:
package Y {
public var names:Dictionary = generateNames();
internal function generateNames():Dictionary {
var result:Dictionary = new Dictionary();
result[ChildClass] = "child";
result[ParentClass] = "parent";
. . .
return result;
}
}
This way it would be sufficient to only implement name getter in super-class, and all inheriting classes will be able to use super-class code as is, no need to change anything. However, this means that some (maybe important) information pertaining to this class will be stored elsewhere (may be difficult to find, this is not the common way people program in AS3).
your implementation of get name should look like this, then the getter is one and each of the new classes needs to have it's own public static var _name defined:
//in the base class
public function get name():String
{
var _sName:String;
if ((this as Object).constructor._name)
{
_sName = (this as Object).constructor._name;
}
else
{
try
{
var o:Object = getSuperClass(this);
while (o)
{
if (o._name)
{
_sName = o._name;
break;
}
o = getSuperClass(o);
}
}
catch (e:*)
{}
}
return _sName;
}
//as found here: http://www.actionscriptdeveloper.co.uk/getting-the-class-of-an-object-in-as3/
public static function getSuperClass(o: Object): Object
{
var n: String = getQualifiedSuperclassName(o);
if (n == null)
return(null);
return getDefinitionByName(n);
}
the static members can be accessed only via class reference which we can get from constructor object, "this" will point to the current class in the inheritance chain so you can call this in parent class and it will point to a Child in a Child class.
[EDIT]
I've modified it so it tests for existance of the public static property _name if not found on "this" instance then in a loop the parent class is checked until one is found - like inheritance:)
I'm using this feature to create clone method: constructor as helper in clone method implementation
best regards
Why don't you store such a constant within a corresponding function instead of declaring an inaccessible constant?
class Parent {
...
public function get name():String { return 'Parent'; }
}
class Child extends Parent {
...
override public function get name():String { return 'Child'; }
}
By the way, if your Parent class is a descendant of DisplayObject, you should be careful with name property, as it's needed sometimes by operating code, e.g. getChildByName().
I have found something that seems to work. Any feedback is greatly appreciated:
public class Parent{
prototype._name = "Parent";
public function get name():String{
return this["_name"];
}
}
public class Child{
prototype._name = "Child";
}

How can I subclass a class loaded from a swf

I want to subclass "superClass" and override one of it's functions.
public class superClass {
protected function f1(...) : Boolean {...}
protected function f2(...) : Boolean {...}
...
protected function f100(...) : Boolean {...}
}
public class subClass extends superClass {
// override f1 in the subclass
protected override function f1(...) : Boolean {...}
}
The problem is that the "superClass" is loaded from a swf. I do not have a reference to the class definition in my project. Is there a way to do something like below?
public class subClass {
private var superClassObject: Object;
// construct from an instance of superClass
public function subClass (s : Object) {
superClassObject = s;
}
private function myF1(...) : Boolean {...}
override InvokeFunction (fname: string, args: Array) : Object {
if (fname == "f1") {
return myF1(args);
} else {
return superClassObject.InvokeFunction(fname, args);
}
}
}
I'm not sure how function call is implemented in AS. What should "InvokeFunction" be?
You should use .swc , not .swf. The class you want to extend must be available at compile time, not at runtime. Anyway if using of swf is mandatory for you, you could use different techniques to 'override' functionality.
Besides inheritance there are other OOP concepts (Composition, Aggregation,etc...) and design patterns(Proxy,Adapter,etc...) for changing functionality of class. You could use them.

Overriding a public variable with set

I have a base class like this
class Base {
public var space:Number;
}
which gets extended by
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
This doesn't compile. Say, you don't have control of the base class, what ways is there implement the same thing?
The obvious is create a function setSpace(), but this object is being embedded in an already existing system that use the public space.
Thanks in advance.
Your base class should be defined that way:
class Base {
// Don't use public variables. Make them private and define setters and getters
private var space_:Number;
public function get space():Number {
return space_;
}
public function set space(v:Number):void {
if (space_ === v) return;
space_ = v;
}
}
And then it can be overriden that way:
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
Edit:
I missed the part where you say you don't have control over the base class. In that case, hope that space is defined as a getter/setter (it should be if the class is implemented properly). If not, you'll indeed have to use a function such as getSpace and setSpace.
From Adobe:
Class member variables that are declared using the var keyword cannot
be overridden in a subclass.
Using a setter is not an option in your case. If you need to preserve the interface, use composition instead of inheritance:
class Desc {
private var _base:Base;
public function set space(space:Number):void {
//code
this._base.space = space;
}
}