Currently I've got some swift code like this:
class C {
let type: Type;
var num = 0;
init() {
self.type = Type({ (num: Int) -> Void in
self.num = num;
});
}
}
The Swift compiler refuses to permit it, saying that I've referenced self.type before it's initialized, even though that's clearly completely untrue. Furthermore, I can't employ the workaround found in other questions/answers, because the type is not optional, and it's immutable, so it can't be initialized with nil pointlessly first.
How can I make the Swift compiler accept this perfectly valid code?
This has nothing to do with returning from the initializer early. The callback is executed asynchronously- it is stored and then used later.
I also have a few further lets that are initialized after this one. I would have to turn them all into mutable optionals, even though they're not optional and can't be mutated.
This works:
class C {
var type: Type?;
var num = 0;
init() {
self.type = Type({ (num: Int) -> Void in
self.num = num;
});
}
}
I assume you knew that. But you want to know why your version isn't working.
Now for the tricky part: for the line
self.num = num;
to work, the compiler has to pass self to inside the closure. The closure could be and probably is executed inside of the constructor of Type.
This is as if you had written
self.type = Type({ (self: C, num: Int) -> Void in
self.num = num
});
which is syntactically wrong but explains what the compiler has to do to compile your code.
To pass this necessary instance of self to the constructor of Type, self has to be initialized. But self isn't initialized, because you are still in the constructor.
The compiler tells you which part of self is not initialized, when you try to pass self to the constructor of Type.
P.S.
obviously Type knows num in your code.
If you want to use let in C instead of var you could do...
class Type {
let num: Int
init () {
num = 3
}
}
class C {
let type: Type;
var num = 0;
init() {
self.type = Type();
num = type.num
}
}
or even
class C {
let type: Type;
var num: Int {
return type.num
}
init() {
self.type = Type();
}
}
depending on whether you want num to change or not. Both examples compile without error.
First, it's important to explain why this is not perfectly valid code, and that it isn't clear at all that self.type is not used before it is initialized. Consider the following extension of your code:
struct A {
init(_ f: (Int) -> Void) { f(1) }
}
class C {
let type: A
var num = 0 {
didSet { print(type) }
}
init() {
self.type = A({ (num: Int) -> Void in
self.num = num
})
}
}
If you walk through the logic, you'll note that self.type is accessed via print before it has been initialized. Swift can't currently prove that this won't happen, and so doesn't allow it. (A theoretical Swift compiler might prove that it wouldn't happen for some particular cases, but for most non-trivial code it would likely bump into the halting problem. In any case, the current Swift compiler isn't powerful enough to make this proof, and it's a non-trivial proof to make.)
One solution, though somewhat unsatisfying, is to use implicitly unwrapped optionals:
private(set) var type: A! = nil
Except for the declaration, every other part of the code is the same. You don't have to treat it as optional. In practice, this just turns off the "used before initialization" checks for this variable. It also unfortunately makes it settable inside of the current file, but does make it immutable to everyone else.
This is the technique I've most often used, though often I try to rework the system so that it doesn't require this kind of closure (not always possible, but I often rack my brain to try). It's not beautiful, but it is consistent and bounds the ugly.
Another technique that can work in some cases is laziness:
class C {
lazy var type: A = {
A({ (num: Int) -> Void in self.num = num })}()
var num = 0
init() {}
}
Sometimes that works, sometimes it doesn't. In your case it might. When it does work, it's pretty nice because it makes the property truly immutable, rather than just publicly immutable, and of course because it doesn't require !.
Interesting.
It looks like the error goes away if you avoid referencing self inside the closure.
If the callback is synchronous you can change your code as follow:
class C {
let type: Type
var num = 0
init() {
var numTemp = 0 // create a temporary local var
let initialType = Type({ (num: Int) -> () in
numTemp = num // avoid self in the closure
});
self.type = initialType
self.num = numTemp
}
}
Important: this will NOT work if the closure is async.
Tested with Xcode (Playground) 6.4 + Swift 1.2
Hope this helps.
As appzYourLife said, a temporary variable for num will suffice:
class Type{
var y: (Int)->Void
init(y2:((Int)->Void)){
self.y = y2
}
}
class C {
let type: Type
var num: Int = 0
init() {
var num2 = 0
self.type = Type(y2: { (num3: Int) -> () in
num2 = num3
});
self.num = num2
}
}
However, you do not need a temporary variable for type, this error message is misleading.
Related
I am trying to understand the difference between
var a: Int { calculateValue() }
and
var b = { calculateValue() }()
I'm a little confused, but I think I get the basics, so I just wanted to make sure I have it right: Is it that the first one is a computed property that will run calculateValue() every single time I use a somewhere and use that value, whereas the second one just assigns the value of the closure to b at the time of initialisation?
Thank you
A
var a: Int { calculateValue() } is a computed property, equivalent to:
var a: Int {
get { calculateValue() }
}
The computed body is called everytime a is accessed, which means calculateValue is called on every access (which can be good good, if its value changes, but wasteful if it doesn't)
B
{ calculateValue() } is a closure of type () -> Int, whose body calls calculateValue. The trailing () calls that closure, which makes it an immediately evaluated closure.
The result (as assigned to the stored property var b) is just an Int (not at () -> Int, because the closure was already called)
I have encountered what would seem like an extremely simple issue to solve, and I think I may be missing something.
The program crashes when attempting to create a recursive variable (?) with the typed to a class while being a member of the said class. For example:
class A {
var x: A
init() {
x = A()
}
}
Checking the crash log suggests a recursion of sorts, with init() being called infinitely.
Is there a proper method/syntax to solve this sort of problem, given that I need the variable x to be typed to class A, and the initializer must initialize variable x to class A?
It's obvious that at some step you should left property x uninitialized. So, thats better to declare it as Optional, and initialize it after instance was created:
class A {
var x: A?
}
let mainObject = A()
let nestedObject = A()
mainObject.x = nestedObject
Not sure but i think you are looking for this
class A {
var x: A?
init() {
}
anothermethod() {
x = A()
}
}
and you can call this method like
let a = A()
a.anothermethod()
I was doing this tutorial http://blog.teamtreehouse.com/introduction-learn-power-swift-generics and I came upon this code;
func someFunction<T, U>(a: T, b: U) {}
The problem is when I call the function using
someFunction<String, Int>(1, "Test")
I get an error saying "cannot explicitly specialize a generic function".
I then change it to
someFunction(1,b: "Test")
and now there is no error. The problem is that there is now no type safety. (Is there something wrong with the code, as it was written before swift 2.0?) What is the best way to re-introduce type safety?
The declaration is completely generic and is specifying that any two types can be used.
func someFunction<T, U>(a: T, b: U) {}
It is not that there is no type safety in Swift, this is how you express a generic without any type constraints.
You get what you ask for.
If you wanted to constrain the function to String and Int, you would have written it as
func someFunction(a:String, b:Int)
Generics are more often used with collections, protocols and classes. Basic types rarely need them :
func someFunction<T:Comparable, U:Comparable>(a:T, b:U) -> Bool
{ return (a < b) || (a > b) }
ok, see this 'self explanatory' example. try it in playground and play with it a little bit.
func foo<T>(t: T)->T {
return t
}
// here the resulting type is infered by compiler
let i = foo(1) // 1
let j: Int = foo(1) // 1
let t = foo("alpha") // "alpha"
// if you declare it self ..
//let s: String = foo(1) // error: cannot convert value of type 'Int' to expected argument type 'String'
/* this fails to compile!
func bar<T>(t:T)->Int {
return t.count
}
*/
/* this fails to compile too !!
func bar0<T:CollectionType>(t:T)->Int {
return t.count
}
*/
func bar<T:CollectionType>(t:T)->T.Index.Distance {
return t.count
}
let arr = [1,2,3]
let k:Int = bar(arr) // 3
print(k.dynamicType) // Int
// and even more interesting
let l = bar(arr)
print(l.dynamicType) // Int
It's my understanding that
var perhapsInt : Int?
This is automatically set to a .None value. And the below code snippet confirms that (no compiler errors)
class MyClass {
var num1: Int = 0
var num2: Int?
init(num1: Int) {
self.num1 = num1
}
}
var newClass = MyClass(num1: 5)
newClass.num1 // prints '5'
newClass.num2 // prints 'nil'
Is my understanding of the optional initialisation process correct? if so why does this not work when I change num2 to let.
I was expecting the same behaviour of optionals defaulting to nil when using let. Am I missing something here?
class MyClass {
var num1: Int = 0
let num2: Int?
init(num1: Int) {
self.num1 = num1
// compiler error : return from initialiser without initialising all stored properties
}
}
...
My question is, how can both of these cases be true. Shouldn't it be one or the other. Either optional values are automatically set to .None or it's not.
The behavior of var num2: Int? is caused by Optionals being sugar-powered. They're the only type in Swift which has an implicit default value (of .None).
Notice that if you type var num2: Int (without ?) – the compiler will throw the same error, regardless of using var vs. let.
class MyClass {
var num2: Int
init() {
// Return from initializer without initializing all stored properties
}
}
Because lets' values cannot be overwritten (as opposed to vars'), they require you to explicitly set their initial value:
class MyClass {
let num2: Int? = nil
}
// or this way
class MyClass {
let num2: Int?
init() {
num2 = nil
}
}
This will, however, result in an useless nil constant.
You can read more about initialization of stored properties here and here.
I think that a lot of discussion is here.
A statement from that thread - look deeper in the link above
The value of a constant doesn’t need to be known at compile time, but
you must assign it a value exactly once.
Intresting that you code will compile if you set let value like:
let num2: Int? = .None
let num2: Int? = nil
I know swift has both reference types and value types. And I know Int is a value type. But how can I store a reference to an integer?
var x:Int = 1
var y:Int = x // I want y to reference x (not copy)
++y
println(x) // prints 1, but I want 2
I tried using boxed types, and I tried using array of Int, but neither works for holding a reference to integer.
I guess I can write my own
class IntRef {
var a:Int = 0
init(value:Int) { a = value }
}
var x:IntRef = IntRef(value: 3)
var y = x
++y.a
println(x.a)
seems a bit awkward.
Unfortunately there is no reference type Integer or something like that in Swift so you have to make a Box-Type yourself.
For example a generic one:
class Reference<T> {
var value: T
init(_ value: T) { self.value = value }
}
You can also use closures. I think these better because they are more powerful and also more specific. They not only store a reference, but they also indicate how the reference will be used. For example,
var x:Int = 1
var setx = { (a:Int) in x = a }
var getx = { x }
setx(getx() + 1)
println(x) // This will print 2
I don't recommend actually defining getx/setx. Define a closure that does a specific task for your application.