Saturday, June 21, 2014

Gotchas for people coming from JVM languages

Initializers:


The signature includes the parameter names, so you can have two initializers, both taking the same types of parameters, as long as they have different names. eg.

init(withDouble: Double) {...}
init(withAnotherDouble: Double) {...}

And that's just fine.


Structs


 Structs are *always* copied, so if you have a struct Foo with a property Bar:

struct Foo{var bar = 10}

let foo = Foo(bar: 100)
var foo2 = foo

then modify foo2:

foo2.bar = 99
println(foo.bar + " " + foo2.bar) 

you get

100 99



Not really a gotcha, but if you don't declare your own initializers for a struct, and you have default values for all properties, then you get both an empty initializer

Foo() // bar will be 10

and a memberwise one

Foo(bar:100) // bar will be 100 

Function Parameter names are not external by default


func aFunc(param: Int){...}

Cannot be called like this

aFunc(param:10)

You need to explicitly set an external name for the parameter, or use #

func aFunc(externalName param:Int){...}

or

func aFunc(#param:Int){...}

or call it without parameter names:

aFunc(10)

Class Initializers 

Can be designated or convenience

Designated (init(...){...)})means that by the end of them, all properties will be set. Convenience(convenience init(...){...}) means that it'll only do a partial job. 

Have rules about what can call what

Designated initializers *must* call a designated initializer from their super class
Convenience initializers *must* call another initializer in the same class
Convenience initializer *must* ultimately call a designated initializer.

Have rules about the order you do things

Designated initializers must first initialize properties in the current class, then call a designated initializer in the parent class, then they can change their inherited properties.

Convenience initializers must call other initializers first, before they assign any values to anything.

You cannot access self, read properties, or call any methods until all the properties have been initialized - ie. once the calls to other initializers have returned.

Can be inherited


If you have defaults for all your properties, and you don't declare any designated initializers yourself, then a sub class inherits all the parent's designated initializers.

If you have implementations - either automatically from above, or by creating them yourself - of all your parent's designated initializers, then you inherit all their convenience initializers too.

Is and As

is checks if something is an instance similar to instanceof/isInstanceOf[T])

as/as? performs a cast similar to (Float) or asInstanceOf[T] note that you can do this to a whole array in one go, you don't have to cast the individual elements:

let bar: AnyObject[] = ....

for foo in bar as SomeClass[] {println("SomeClass: '\(SomeClass.someProperty)'")}

These checks only work with protocols if you annotate that protocol with @objc which will have the side-effect that that protocol can only be applied to classes.

Any/AnyObject

AnyObject is any instance of a class
Any is an instance of any type at all (except functions)


No comments:

Post a Comment