inout param with empty object since nil won't work - swift

We can't pass nil to inout param, is there a short and concise way to create an empty object literal on the fly and pass to it for the sake of it,
let's say sometimes when we have nothing to pass, wanna pass an empty array, a empty dictionary or class literal object, how would that work in the following case?
func test(inout param: Any) {
println(param)
}
//call
test(&[]())
Edit - inout with nil works
func test(inout param: Any?) {
println(param)
}
var p: Any? = nil
test(&p)

There are many things that won’t work here.
You need to give more than [] to declare an array. You need to give some indication of it’s element type. Either in the brackets e.g. [Int]() or from other context i.e. if test took an [Int] arg not an Any. Otherwise the compiler has no idea what type you mean by [].
You cannot pass literals (for example, nil) into an inout parameter. In fact you can’t pass any kind of immutable value, including temporary objects like [Int](), or variables declared with let. The only things you can pass to an inout parameter are “lvalues” – that is, things that can be on the left-hand side of an assignment. That means even if you changed this to `test(&Int) it won’t work.
Finally, even if you declare var a = [Int]() and then try to call test(&a) you’ll get an error, because the implicit copy of a from an array to an Any will result in another immutable temporary, which also can’t be passed as an inout.

Related

Weird optional type behaviour in swift forEach

This code works fine. It iterates my array of one Int! and prints its magnitude.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
}
Output:
1
Presumably, i in the loop body is an Int or an Int!, and indeed if I ask Xcode for "quick help" on forEach it reports:
func forEach(_ body: (Int) throws -> Void) rethrows
However, if perform two statements in my forEach body, instead it fails to compile, complaining that I need to unwrap i which now has the optional type Int?.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
print(i.magnitude)
}
Compile error:
Value of optional type 'Int?' must be unwrapped to refer to member 'magnitude' of wrapped base type 'Int'
And if I ask for "quick help" now I get:
func forEach(_ body: (Int?) throws -> Void) rethrows
How on earth does the number of statements I place in my loop body manage to affect the type of the loop variable?
Basically, you've elicited an edge case of an edge case. You've combined two things that are the work of the devil:
Implicitly unwrapped Optionals
Implicit type inference of closures, along with the fact that
Implicit type inference of closures works differently when the closure consists of one line (this is where the "How on earth does the number of statements" comes in)
You should try to avoid both of those; your code will be cleaner and will compile a lot faster. Indeed, implicit type inference of anything other than a single literal, like a string, Int, or Double, is a huge drag on compilation times.
I won't pretend to imitate the compiler's reasoning; I'll just show you an actual solution (other than just not using an IUO in the first place):
[x].forEach {(i:Int) in
print(i.magnitude)
print(i.magnitude)
}
Our Int type is legal because we take advantage of the single "get out of jail free" card saying that an implicitly unwrapped Optional can be used directly where the unwrapped type itself is expected. And by explicitly stating the type, we clear up the compiler's doubts.
(I say "directly" because implicit unwrappedness of an Optional is not propagated thru passing and assignment. That is why in your second example you discovered Int?, not Int, being passed into the closure.)

Why does closure capture reference while function does not? Also, why "lazy" keyword is required for closure declaration?

I experimented it with the following code in Xcode Playground:
class X {
var a = 3
init(a: Int) {
self.a = a
}
deinit {
print("\(self.a) is deallocated.")
}
func returnX() -> Int {
return self.a
}
lazy var anotherReturnX: () -> Int = {
return self.a
}
}
var e: X? = X(a: 6)
print(e!.returnX())
e = nil // prints "6 is deallocated."
var f: X? = X(a: 7)
print(f!.anotherReturnX())
f = nil // prints nothing
From the above code, I can see that no reference is captured in the function returnX(), thus e is deallocated once I set e to nil. However, a reference is captured in the closure anotherReturnX(), thus f is not deallocated. Apparently, this implies that a closure captures references while a function does not.
Additionally, when I first type out the code, I didn't include lazy keyword before the closure declaration, as I thought it would be unnecessary to do so. However it triggers a compile-time error. I infer that since the closure can only be accessed after instantiation, it must access to the instantiated self. But since what I am declaring here is effectively an "anonymous function", why would the closure access to self during instantiation anyway?
After putting in some thoughts, I found more contradictions. For instance, I understand that a reference is captured when a closure is called. However, during initialisation of X, I am simply assigning a closure to a variable without calling it, same as the declaration of other instance properties. Thus the closure should not do anything during initialisation, and compiling the code without keyword lazy should be fine. But compilation fails. I am not sure what goes wrong in my understanding.
I have read some related articles, such as strong/weak reference, retain cycle, lazy stored property. However, many explain "what happens" and do not say much about "why".
So other than the question raised in the title, I would also like to clarify, what makes function and closure different from each other such that the above situation happens?
Update:
The fact that closure captures reference while function does not is further "enforced" on me, since, according to the Xcode Compiler, I can rewrite return self.a as return a in returnX(), but I cannot do so in anotherReturnX. As such, I guess I would have to accept that, although function and closure are similar because each of them is "a bundle of functionalities", function is different from closure that it does not capture references. If I were to go deeper in the reason behind this, it would probably involve the design of Swift itself?
However, I still cannot understand why lazy keyword is required for closure declaration.
lazy var anotherReturnX: () -> Int = {
return self.a
}
The self here is a strong self.
When an object references another object strongly, ARC cant deallocate so a retain cycle is created. The reference should be weak to avoid a retain cycle by creating weak self inside the block.
lazy var anotherReturnX: () -> Int = { [weak self] in
return self?.a
}
returnX is a method of the class. Methods don't capture variables. self is an implicit local variable in methods, that is implicitly passed to the method when the method is called.
anotherReturnX is a property that is assigned a closure lazily. That closure captures outside variables that are used within it, including self. That capturing creates a strong reference from the closure to the X instance, which, combined with the strong reference from the X instance to the closure, creates a retain cycle.

The difference between Swift Optional Property Declarations [duplicate]

This question already has answers here:
Swift variable decorations with "?" (question mark) and "!" (exclamation mark)
(1 answer)
What is the difference between String? and String! (two ways of creating an optional variable)?
(7 answers)
Closed 4 years ago.
I noticed that some coding examples for Swift declare optional properties in different ways. However, I seem to have trouble trying to tell them apart (or, rather, when to use each.)
class MyClass {
// I believe this can start as nil but should always be set
// once it is.
var optionalProperty1: Type!
// I believe this can be set or nil anytime.
var optionalProperty2: Type?
// I think this is the same as
// var optionalProperty3: Type!
lazy var optionalProperty3: Type
}
How does each one differ from the others and when should each one be used?
var optionalProperty1: Type!
When you're sure you will have value for this property such as timestamp it will be something for sure. And Yes it can be nil too.
var optionalProperty2: Type?
When you're not sure about the value (Or this field is not mandatory) take it as optional for example:- If I make a Person class address can be optional and name will not.
lazy var optionalProperty3: Type
This syntax is wrong you can not declare lazy property in this way. You must assign something to it initially. See below example:
/// First way
lazy var optionalProperty3: String = {
return "Hello"
}()
/// Second way
lazy var optionalProperty4 = "Hello"
A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration. lazy variables are great for things that need to be setup once, then never re-set.
One more thing you really don't need to specify type in modern Swift. Means if you will assign 0 it will be an integer itself, if you will assign 0.0 it will take it as double and same for String, Array etc.
The third declaration is not an optional.
The third one declares a lazy property. Lazy properties will only be initialised when they are first used. Example:
class A {
lazy var a: Int = {
print("hello")
return 1 + 1
}()
}
let a = A()
print(a.a)
If you remove the last line, hello will not be printed.
The first declaration is a implicitly unwrapped optional while the second declaration is a normal optional.
When you access members of a normal optional, you need to unwrap it with ? or !:
var myInt: Int? = ...
print(myInt.description) // doesn't compile, must unwrap
print(myInt!.description) // will crash if myInt is nil
print(myInt?.description) // will print "nil" if myInt is nil
On the other hand, implicitly unwrapped optionals do this implicitly - whenever you try to access a member, it will implicitly unwrap it with ! for you:
var myInt: Int! = ...
print(myInt.description) // equivalent to "myInt!.description"
From Apple's Swift documentation:
Optionals (?): "You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all."
Implicitly Unwrapped Optionals (!): "As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist.
Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.
These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties."
Read more at https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
Explicitly Unwrapped Variable
var optionalProperty1: Type!
This means that the value should never be nil. It will always be initialized but it is better to use var optionalProperty1: Type
Optional
var optionalProperty2: Type?
This is an optional value, meaning that it can either have a value or be nil. normally to use the value you would need to unwrap it. using either conditional unwrapping or a guard statement...
if let value = optionalProperty2 {
print("optionalProperty2 had a value, value is set")
}
guard let value = optionalProperty2 else {
print("optionalProperty2 was nil value is nil")
}
or you can just check if it has a value and explicitly unwrap it (which is not considered best practice)
if optionalProperty2 != nil {
print("optionalProperty2 is set to \(optionalProperty2!)")
}
Lazy Variable
lazy var optionalProperty3: Type a lazy variable is different, it is not an optional unless you define it to be optional. Lazy variables do not initialise to a value until the value is first used. So if you do not call/use the variable it will never be set.

Why do I have to explicitly unwrap my string in this case?

I have a string var oneString: String! and later on in a method, when I want to concatenate a string to oneString I have to do this:
oneString! += anyString
If I don't add ! I get an error 'String!' is not identical to 'CGFloat'
If I initialize my string with var oneString = "" I don't have this problem. Why? Why do I need to unwrap oneString while I explicitly said it would not be nil when I declared it?
Why do I need to unwrap oneString while I explicitly said it would not be nil when I declared it?
You’ve misunderstood what var oneString: String! means. It does not mean oneString will not be nil. If you declare a type as var oneString: String, then you are declaring a type that cannot be nil.
The type String! is an “implicitly-unwrapped optional”. That is, it’s an optional, much like String?, but one that pretends to be a non-optional sometimes. Mostly for the purposes of reading it – you don’t have to explicitly unwrap it to get the value out. The downside being, if it is ever nil (and it totally can be), your code will trap and abort.
But this pretending-to-not-be-optional only goes so far. You cannot pass a String! to a function as inout when that argument is not an optional. Hence your problem.
Anton’s answer is completely correct in why it won’t work, and his suggested operator overload will make your code compile. But it isn’t the right solution – you should instead avoid using implicitly-unwrapped optionals as they are spring-loaded deathtraps and only to be used in specific circumstances (the most common being with Cocoa UI controls). 999 times out of 1,000 you would be better off with a regular optional or non-optional
Reason is that Foo, Foo? and Foo! are different types in Swift.
There are certain operators pre-defined for you "out-of-the-box" which allow great deal of transparency between Foo and Foo!, but still these types are not the same.
When it comes to strings, operator
func += (inout left: String!, right: String)
... is simply not defined.
If you declare it like:
func += (inout left: String!, right: String) {
left = left + right
}
... then your code should compile the way you like it, that is:
oneString! += anyString

Typecasting an array of enums as [Any]

When I try to pass an array of enums to a method which accepts [Any], I get a warning telling me "'EnumType' not identical to 'Any'". There is no warning if I pass EnumType or [EnumType] to a method with a parameter of type Any. Can someone shed some light as to what's going on here?
When you pass a type as a parameter into a function that takes an Any, the compiler silently does a conversion for you – if you have f(a: Any) and you call f(x), it's kind of like the compiler writing f(x as Any) for you.
But to create an array is a bit more complicated, involving iterating over the whole array converting the contents one by one, and the compiler doesn't do that automatically.
Happily it's easy to do by hand:
// some function that just takes an array of Any and prints them
func takeAnys(anys: [Any]) {
",".join(anys.map(toString))
}
let ints: [Int] = [1,2,3]
// won't compile
takeAnys(ints)
// this iterates over each entry and converts it to Any,
// returning a new array of them
takeAnys(ints.map { $0 as Any })
Note, passing an [EnumType] into a function that takes an Any is a bit different to passing an array into a function that takes an [Any]. The former works because Any can hold anything, including an array, so you you get [EnumType] as Any which is fine. But your function wants an array of Any, that is, an array with the contents converted to Any, rather than an array that has itself been converted to an Any.
It's worth noting that this feature does work with classes – if you have an array of subclasses, you can pass it into a function that takes an array of superclasses. But this is specific to reference types, you can't get the same behavior with enums or structs (or protocols of them, which is what Any is).