Passing an implicitly unwrapped variable into inout parameter doesn't compile - swift

func someFunc<T>(obj: T, inout arr: [T])
{
}
var arr: [String]!
someFunc("a", &arr)
Upon calling someFunc("a", &arr), I get an error:
[String]! is not identical to [T]
arr is implicitly unwrapped, so shouldn't it be treated as an unwrapped value, and thus able to be passed into the function? What then would be the correct way to write this, considering I want to keep the arr declaration the same (keep it implicitly unwrapped)?

Conceptually you are correct that you should be able to use it this way, but the reality is that the value you are passing in is a different type than the array. This is important because you are taking the reference of that value which cannot be forwarded to the internal array.
An implicitly unwrapped optional is really just an optional that automatically unwraps itself when it is referenced. So you can illustrate why this wouldn't work in your case with a regular optional:
var arr: [String]? = ["Hello", "World"]
someFunc("a", &(arr!))
This also does not compile. The problem is that it is trying to pass in a reference to the value stored within the Optional enum. A method cannot interact with that reference independent of the enum that actually owns it.
I think your best bet is to return a copy of the array from someFunc instead of using an inout parameter:
func someFunc<T>(obj: T, arr: [T]) -> [T]
{
}

For me in XCode 6.1 (6A1052d), this kind of thing compiles, but just silently fails to modify the value passed in. It would be better if it failed to compile - would have saved me some head-scratching.

You can pass an implicitly-unwrapped optional as an inout parameter. You have two options: change your function to explicitly accept an implicitly-unwrapped optional, or populate the implicitly unwrapped optional with a sentinel value, and then explicitly unwrap it.
// Compiled with Xcode Version 6.2 (6C131e)
var foo: [String]!
func testImplicitlyUnwrappedOptionalInout() {
// doesn't compile: '[String]!' is not identical to '[T]'
// someFunc("bar", arr: &foo)
// crashes at runtime: EXC_BAD_INSTRUCTION (code=EXC_i286_INVOP, subcode=0x0)
// someFunc("bar", arr: &foo!)
// must populate foo before unwrapping it.
foo = []
someFunc("bar", arr: &foo!)
if let foo = foo {
XCTAssertEqual(foo, ["bar"])
} else {
XCTFail("foo wasn't populated")
}
// or you must change your function to accept an implicitly unwrapped optional inout:
foo = .None
someFuncImplcitlyUnwrapped("bar", arr: &foo)
if let foo = foo {
XCTAssertEqual(foo, ["bar"])
} else {
XCTFail("foo wasn't populated")
}
}
func someFunc<T>(obj: T, inout arr: [T]) {
arr.append(obj)
}
func someFuncImplcitlyUnwrapped<T>(obj: T, inout arr: [T]!) {
if arr == nil {
arr = []
}
arr.append(obj)
}
Thanks to Joe Groff for the hint.

Related

"Implicitly unwrapped property" warning?

I have a class where I have a property like this:
var residenceId: Int!
When building with Xcode 10 and Swift 4.2 there are no issues. However, after installing Xcode 11 Beta and converting to Swift 5 I get the following warning:
Implicitly unwrapped property 'residenceId' declared here
Later in the class I also have this function:
func jsonDictionary() -> [String : Any] {
return ["residenceId": residenceId]
}
Here I get the warning
Coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional
Are we no longer allowed to use implicitly unwrapped optional?
EDIT:
After some more looking into it, I have come to believe that "Implicitly unwrapped property 'residenceId' declared here" is not actually a warning, but rather some info (it is in a grey label rather than usual yellow) to help me understand why I am getting the second warning.
And to clarify, my question is if we are no longer able to use the '!' symbol on properties to define an implicitly unwrapped property (obviously only if we are sure it will not be nil) in order to later avoid explicitly unwrapping it (and thus simplifying the code).
Since Swift 4, ImplicitlyUnwrappedOptional or ! as we knew it, became Optional.
Check:
let a: ImplicitlyUnwrappedOptional<Int> = 1
will spit out the error:
'ImplicitlyUnwrappedOptional' has been renamed to 'Optional'
So instead if we do:
let a: Int! = 1
print(type(of: a)) //will print "Optional<Int>"
It's still Optional<Int> but indicates to the compiler that it can be implicitly unwrapped.
Implicit Unwrapping is Part of a Declaration.
...
consider ! to be a synonym for ? with the addition that it adds a flag on the declaration letting the compiler know that the declared value can be implicitly unwrapped.
Ref: Reimplementation of Implicitly Unwrapped Optionals
Now getting to the main question:
If you do:
let a: Int! = 1
let b: Any = a
print(type(of: b)) //prints "Optional<Int>"
It will give the following warning:
Expression implicitly coerced from 'Int?' to 'Any'
or as per Xcode 11
Coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional
Note here that we tried to get a non-optional Any out of an Int? which means we were basically expecting an Int but just by specifying Any it won't also unwrap the Optional.
It will remain an Optional, and this is the meaning behind that warning.
Solutions:
To handle this warning gracefully, we can do any of the following:
let a: Int! = 1
let b: Any? = a
type(of: b) //Optional<Any>.Type
let c: Any! = a
type(of: c) //Optional<Any>.Type
let d: Any = a!
type(of: d) //Int.Type
EDIT: (based on comment)
! instead of ? have any practical difference for the programmer?
! tells the compiler that it can be implicitly unwrapped so it can help ease in the need for optional chaining.
Example:
With ?
class A {
var n: Int? = 1
}
class B {
var a: A? = A()
}
let b: B? = B()
print(b?.a?.n)
/*
but the following won't compile as compiler
will not implicitly unwrap optionals
print(b.a.n)
*/
With !
class A {
var n: Int! = 1
}
class B {
var a: A! = A()
}
let b: B! = B()
print(b.a.n) //compiler will implicitly unwrap `!` similar to print(b!.a!.n)
//also... you can still safely unwrap if you want
print(b?.a?.n)
b.a.n and b?.a?.n will both give an Optional<Int> at the end
Ofcourse if b or a is nil then b.a.n will crash because it's implicitly unwrapping b and a to get to n which is Optional<Int>
To get Int instead of Optional<Int>, you would do b.a.n! and so in your case you would do: print(residenceId!) to get Int
I hope I made sense

Unwrap/coalesce a multi-level optional

I'm trying to write a function to unwrap optionals with an arbitrary number of levels of nesting. Here's the test I'm using:
let a: Int??? = 1
let b: Int??? = nil
print(a.unwrap(0), b.unwrap(0)) // should print 1, 0
I can get the correct output with a basic generic function:
extension Optional {
func unwrap<T> (_ defaultValue: T) -> T {
return (self as? T) ?? defaultValue
}
}
print(a.unwrap(0), b.unwrap(0)) // 1, 0
But this doesn't prevent the function from being called with a different type than the optional. For instance, I could call a.unwrap("foo") and it would print "foo" instead of "1" since of course you can't cast Int??? to String.
I tried it using Wrapped instead, which semi-properly restricts the default value but doesn't give the correct output:
extension Optional {
func unwrap (_ defaultValue: Wrapped) -> Wrapped {
return (self as? Wrapped) ?? defaultValue
}
}
print(a.unwrap(0), b.unwrap(0)) // Optional(Optional(1)), nil
It only unwraps one level of the optional, instead of all three, and since nil is a valid value for Int?? it doesn't return the default.
Is there any way to safely do what I want here?
This code does what you ask for. The drawback is that you need to implement the Unwrappable protocol in every type you want to put inside optionals. Maybe Sourcery can help with that.
protocol Unwrappable {
associatedtype T
func unwrap(_ default: T) -> T
}
extension Optional {}
extension Optional: Unwrappable where Wrapped: Unwrappable {
typealias T = Wrapped.T
func unwrap(_ defaultValue: T) -> T {
if let value = self {
return value.unwrap(defaultValue)
}
return defaultValue
}
}
extension Int: Unwrappable {
typealias T = Int
func unwrap(_ default: Int) -> Int {
return self
}
}
let nestedOptionalValue: Int??? = 6
let nestedOptionalNil: Int??? = nil
let optionalValue: Int? = 6
let optionalNil: Int? = nil
print(nestedOptionalValue.unwrap(0)) // prints 6
print(nestedOptionalNil.unwrap(0)) // prints 0
print(optionalValue.unwrap(0)) // prints 6
print(optionalNil.unwrap(0)) // prints 0
The trick is that the Unwrappable protocol marks types that can be eventually unwrapped (as in after 0, 1 or more unwraps) to a certain type.
The difficulty in this problem comes from the fact that in an extension to Optional, you can get the Wrapped type, but if Wrapped is optional again, you can't access Wrapped.Wrapped (in other words, Swift doesn't support Higher Kinded Types).
Another approach, would be to try to add an extension to Optional where Wrapped == Optional. But again you'd need Higher Kinded Types support to access the Wrapped.Wrapped type. If we try to extend Optional where Wrapped == Optional<T>, we also fail, because we cant extend Optional generically over T.

Optional binding to an immutable explicitly declared to be of type 'ImplicitlyUnwrappedOptional<T>' yields an immutable of type 'Optional<T>'

Background
When I was explaining the logical error in the following question:
How to use guard statement to detect nil after an assignment?
I stumbled over a peculiarity that I cannot explain myself.
Details and question
As shown in the thread above, we can explicitly state the type of the scope-local immutable, say b, in if let b = rhs ... and guard let b = rhs ... else clauses to be of the same optional type as the rhs value to (attempted to be assigned) to b, in which case the "optional binding" will always succeed:
let a: Int?
// ...
if let b: Int? = a { // will always succeed, 'Int?' to 'Int?'
print(b.dynamicType) // Optional<Int>
}
We could discuss whether this should even be allowed, as this is in essence a bloated block-local assignment, but this is not the point of this question. Rather, explaining the following peculiarity:
If we explicitly declare b above to be of an implicitly unwrapped optional type (here: Int!), then b in the scope of the if let clause is, for some reason, just a regular non-unwrapped optional, namely Int.
let a: Int? = nil
if let b: Int! = a {
print(b.dynamicType) // Optional<Int>
/* why not ImplicitlyUnwrappedOptional<Int> ? */
}
Question:
Why is b above—declared to be an implicitly unwrapped optional (Int!)—converted to a "regular" optional (Int?) (in the if let clause)?
Investigations of my own
I've simply noted that the above "shadow conversion" is naturally not present for regular assignments of optionals to implicitly unwrapped optionals
let c: Int? = 10
let d: Int! = c
print(f.dynamicType) // ImplicitlyUnwrappedOptional<Int>
neither present if we use an always-succeeding if let block-local assignment from non-optional (Int) to implicitly unwrapped optional (Int!)
let c = 10
if let d: Int! = c {
print(d.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}
After feedback from #Sulthan in the comments below, we see that this "shadow conversion" is not present if a above is a double optional (Int??), e.g.
let a: Int?? = 10
if let b: Int! = a {
print(b.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}
if let b: Int? = a {
print(b.dynamicType) // Optional<Int>
}
I am using Swift 2.2 / Xcode 7.3.

Incrementing an implicitly unwrapped optional

I declare an implicitly unwrapped optional as:
var numberOfRows: Int!
and initialize it in init:
numberOfRows = 25
Later I need to decrement it by one so I write:
numberOfRows--
but this doesn't compile. The error message says the decrement operator can't be applied to an implicitly unwrapped optional. With a little experimentation I find that the following compiles without error:
numberOfRows!--
I would like to understand this. What is the explanation for what seems like the extra '!'?
Implicitly unwrapped optional is a type on its own, and is different from the type it that wraps. Some operators on optionals and implicitly unwrapped optionals are pre-defined for you out of the box by the language, but for the rest you have to define them yourself.
In this particular case an operator postfix func --(inout value: Int!) -> Int! is just not defined. If you want to use postfix -- operator on Int! just the same way you use it on Int then you will have to define one.
E.g. something like:
postfix func --<T: SignedIntegerType>(inout value: T!) -> T! {
guard let _value = value else { return nil }
value = _value - 1
return _value
}
If we look at what the optional type is, we will see that this is enum like:
enum Optional<T> {
case Some(T)
case None
}
And it can be Some Type like Int for example or None and in this case it's have nil value.
When you make this:
var numberOfRows: Int!
you directly is indicated by the ! that this is not Int type but this is the enum Optional<Int> type. At moment of creation it's will be Some<Int> if equal it value but with this ! you have that it is enum Optional<Int> and in some next moment it will be the None. That's why you have to use ! second time when make this:
numberOfRows!--
Your nomberOfRows value is Optional<Int> type and it may be Int or nil and you have to directly indicate that this is Int type to make -- action.

Is there a way to test whether an Array's type is optional?

Let's say I want to write a method on Array that either returns a copy of the array if its type is non-optional, or a subarray of unwrapped values if its type is an optional. To do this, I think I need to be able to test whether the Array's type T is an optional type or not. For example, this just returns a copy of the array in either case:
extension Array {
func unwrapped() -> Array<T> {
return filter({
var x: T? = $0
return x != nil
})
}
}
I understand that if I know I have an array of optionals I could just use filter() and map():
let foo: [String?] = [nil, "bar", "baz"]
let bar: [String] = foo.filter({ $0 != nil }).map({ $0! })
I'm not looking for a solution to that specific problem. Rather I'm wondering if there's a way to determine in an Array extension if its type is optional, which could be useful in a number of different convenience methods.
One possible solution is to use global functions instead of extensions; then you can overload with two definitions, one for non-optional and one for optional types:
func unwrapped<T>(a: [T]) -> [T] { return a }
func unwrapped<T>(a: [T?]) -> [T] {
return a.filter { $0 != nil }.map { $0! }
}
unwrapped([1, 2, 3, 4, 5]) // -> [1, 2, 3, 4, 5]
unwrapped([1, 2, 3, nil, 5]) // -> [1, 2, 3, 5]
I'm unsure whether this is guaranteed to work; it would be interesting if someone can find a case where it breaks or somewhere in the Swift guides that says it's always correct.
See also the discussion in this question.
Use reduce:
let unwrapped = foo.reduce([String]()) {
if let bar = $1 as String? { return $0 + [bar] }
return $0
}
That will return a copy if the original is non-optional, or a subarray of non-nil unwrapped values if the original is optional. You don't need to know if the array contains optionals in order to do this.
If an array contains at least one value, you can determine if that value is an optional like this:
extension Array {
func optTest() {
switch reflect(self[0]).disposition {
case .Optional:
println("I am an optional")
default:
break
}
}
}
You would only need to test the first value. But I haven't figured out how to test an empty array - I suppose you could add an element to it and then test that element...
To do this, I think I need to be able to test whether the Array's type T is an optional type or not.
No, you don't have to - just use flatMap!
let foo: [String?] = [nil, "bar", "baz"]
let foo2: [String] = ["bar", "baz"]
foo.flatMap{$0}
foo2.flatMap{$0}
// yield both ["bar", "baz"] and are of type Array<String>
The Array struct can be extended to return its generic type, and then a protocol can be used to test for a typeless Optional.
The example is made for Swift 2, but I believe it should work similarly on previous versions.
protocol OptionalProtocol {}
extension Optional : OptionalProtocol {}
extension Array {
func elementType() -> Any.Type {
return Element.self
}
}
[String]().elementType() is OptionalProtocol.Type // false
[String?]().elementType() is OptionalProtocol.Type // true
Specific to Swift 2, the Array extension can be foregone entirely since the typealias allow to access the Element type:
protocol OptionalProtocol {}
extension Optional : OptionalProtocol {}
[String]().dynamicType.Element.self is OptionalProtocol.Type // false
[String?]().dynamicType.Element.self is OptionalProtocol.Type // true