In SwiftHTTP, it has this following code for its GET method:
public func GET(url: String,
parameters: Dictionary<String,AnyObject>?,
completionHandler:((HTTPResponse) -> Void)!) { ... }
By making this implicitly unwrapped optional, does it mean the completionHandler must be provided? If so why bother making it an optional?
The implicitly unwrapped optional means you technically can pass nil, but whether or not it crashes depends on the rest of the code. In this case, it appears that the case where completionHandler is nil is handled properly (so you don't have to provide one). I would simply say this is a sub-optimal API :)
Related
I found an interesting function in the Swift Tests source code:
func test(_ v: A????, _ cast: (A????) -> B?)
Since Type? is just syntax sugar for Optional<Type>, this means that the type of the argument v can be rewritten as Optional<Optional<Optional<Optional<A>>>>.
I know that this function is used to test optional types, so it is definitely going overboard with the arguments v and cast, but what would be the actual use of having "an optional of an an optional, etc." type in Swift (if any)?
These occur sometimes in Swift when you are accessing data.
One example is if you have a dictionary with an optional type for the value, and then you look up a value in that dictionary:
let rockStars: [String: String?] = ["Sting": nil, "Elvis": "Presley", "Bono": nil, "Madonna": nil]
let lastName = rockStars["Elvis"]
print(lastName as Any)
Optional(Optional("Presley"))
This happens because a dictionary look up can fail when the key is not present, and it returns nil in that case. So the return type of a dictionary lookup has to be the value type wrapped in an optional. A look up from the rockStars dictionary returns a String??.
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
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.
I was under the impression that implicitly unwrapped optional will cause a runtime exception when used and it is nil. But the following code works without runtime exception, why?
var str:String?
println(str!) // Crashes as expected
var str:String! // Implicitly unwrapped
println(str) // Does not crash, not what I expect - it prints nil
It prints the variable as enum (i.e. optional), because internally an optional is enum Optional<T>.
More precisely, I presume it uses the debugDescription property, in fact this is what happens:
var str:String?
println(str) // Prints "nil"
str.debugDescription // Prints "nil"
An implicitly-unwrapped optional is only forcibly unwrapped in a situation which expects a non-optional. println() accepts all types, including optionals, and so there is no need to forcibly unwrap it before passing to println(). Since it is not unwrapped, it does not crash.
The name of the ! always confuses me: it's called an 'implicitly unwrapped optional'. However, what is implicit about it? Implicit means "implied though not plainly expressed." However, does not adding a ! plainly express its purpose? Does not adding a ! make it explicit what we are trying to accomplish?
In Swift, trailing exclamation marks (!) are used in two different ways. One is called Forced Unwrapping. This is when you have a variable defined as an Optional and you want to basically assert that the value is not nil so that you can use it as if it were not an optional:
var optionalName: String? = "World"
if optionalName != nil {
sayHelloTo(optionalString!)
}
An alternate way you could describe "Forced Unwrapping" is "Explicit Unwrapping", but forced adds the extra hint that the whole program will crash if you try to "Force Unwrap" an optional that is nil.
The second is when you are actually declaring the type of a variable and it is called an Implicitly Unwrapped Optional. This is for when you want to declare a variable that is technically optional, but that you will treat as if it is not optional. Every time you use this Implicitly Unwrapped Optional, it is in reality, doing the "Force Unwrapping" I described above:
var name: String! = "World"
if name != nil {
sayHelloTo(name)
}
You can still test an Implicitly Unwrapped Optional for nil, but you can also use it directly as if it were not optional. That is why it is considered implicit. Every time you use it, it is automatically, implicitly unwrapped for you.
Like "Forced Unwrapping" an "Implicitly Unwrapped Optional" will still crash the entire program if you try to use it when it is nil
Normal Optional
var foo : Foo? = Foo()
foo!.doSomething() // explicitly unwrap it and call the method
Implicitly Unwrapped Optional
var foo : Foo! = Foo()
foo.doSomething() // implicitly unwrap it and call the method just like it is not optional
In both case, you need something to declare an optional (? or !). Implicitly Unwrapped Optional does not add more. But you can omit unwrap operator when use it.