Nil check not functioning as expected [duplicate] - swift

I have the following code in a playground file:
extension Dictionary {
func test() {
for key in self.keys {
self[key]
}
}
}
var dict: [String: AnyObject?] = [
"test": nil
]
dict.test()
I will henceforth refer to the line within the for-each loop as the output since it is what's relevant. In this particular instance the output is nil.
When I change the for-each loop to look like this:
for key in self.keys {
print(self[key])
}
The output is "Optional(nil)\n".
What I really want to do is check the value for nil, but the code:
for key in self.keys {
self[key] == nil
}
outputs false.
One other thing I tried was the following:
for key in self.keys {
self[key] as! AnyObject? == nil
}
which produces the error:
Could not cast value of type 'Swift.Optional<Swift.AnyObject>' to 'Swift.AnyObject'
Any help with this is much appreciated!

You've gotten yourself into kind a mess, because a dictionary whose values can be nil presents you with the prospect of a double-wrapped Optional, and therefore two kinds of nil. There is the nil that you get if the key is missing, and then the nil that you get if the key is not missing and you unwrap the fetched result. And unfortunately, you're testing in a playground, which is a poor venue for exploring the distinction.
To see what I mean, consider just the following:
var d : [String:Int?] = ["Matt":1]
let val = d["Matt"]
What is the type of val? It's Int?? - an Int wrapped in an Optional wrapped in another Optional. That's because the value inside the dictionary was, by definition, an Int wrapped in an Optional, and then fetching the value by its key wraps that in another Optional.
So now let's go a bit further and do it this way:
var d : [String:Int?] = ["Matt":nil]
let val = d["Matt"]
What is val? Well, the playground may say it is nil, but the truth is more complicated; it's nil wrapped in another Optional. That is easiest to see if you print val, in which case you get, not nil, but "Optional(nil)".
But if we try for something where the key isn't there at all, we get a different answer:
let val2 = d["Alex"]
That really is nil, signifying that the key is missing. And if we print val2, we get "nil". The playground fails to make the distinction (it says nil for both val and val2), but converting to a String (which is what print does) shows the difference.
So part of the problem is this whole double-wrapped Optional thing, and the other part is that the Playground represents a double-wrapped Optional in a very misleading way.
MORAL 1: A dictionary whose value type is an Optional can get really tricky.
MORAL 2: Playgrounds are the work of the devil. Avoid them. Use a real app, and use logging to the console, or the variables pane of the debugger, to see what's really happening.

Checking if a dictionary value is nil makes sense only if the
dictionary values are an Optional type, which means that you have to
restrict your extension method to that case.
This is possible by defining a protocol that all optional types conform
to (compare How can I write a function that will unwrap a generic property in swift assuming it is an optional type?, which is just a slight modification of Creating an extension to filter nils from an Array in Swift):
protocol OptionalType {
typealias Wrapped
var asOptional : Wrapped? { get }
}
extension Optional : OptionalType {
var asOptional : Wrapped? {
return self
}
}
Now you can define an extension method with is restricted to
dictionaries of optional value types:
extension Dictionary where Value : OptionalType {
func test() {
for key in self.keys { ... }
}
}
As Matt already explained, self[key] can only be nil if that key
is missing in the dictionary, and that can not happen here. So you
can always retrieve the value for that key
let value = self[key]!
inside that loop. Better, enumerate over keys and values:
for (key, value) in self { ... }
Now value is the dictionary value (for key), and its type
conforms to OptionalType. Using the asOptional protocol property
you get an optional which can be tested against nil:
if value.asOptional == nil { ... }
or used with optional binding.
Putting all that together:
extension Dictionary where Value : OptionalType {
func test() {
for (key, value) in self {
if let unwrappedValue = value.asOptional {
print("Unwrapped value for '\(key)' is '\(unwrappedValue)'")
} else {
print("Value for '\(key)' is nil")
}
}
}
}
Example:
var dict: [String: AnyObject?] = [
"foo" : "bar",
"test": nil
]
dict.test()
Output:
Value for 'test' is nil
Unwrapped value for 'foo' is 'bar'

Related

Is there a way to compile with a generic type?

This is something that has vexed a number of developers including myself. Let say we have a protocol that defines a subscript which we apply to a simple class.
protocol Cache {
subscript<Value>(_: String) -> Value? { get set }
}
class InMemoryCache: Cache {
private var cache: [String: Any] = [:]
subscript<Value>(key: String) -> Value? {
get {
cache[key] as? Value
}
set {
if let value = newValue {
cache[key] = value
} else {
cache.remove(key)
}
}
}
}
This works fine as long as we know the types:
cache["abc"] = 5
let x: Int? = cache["abc"]
but the developers want to do this:
cache["abc"] = nil
Which won't compile because the compiler cannot determine the Value generic type. This works however
cache["abc"] = nil as String?
I've tried a number of things but they all have drawbacks. Things like adding a second subscript with the Any type. Nothing seems to work well even though it would seem like a simple problem.
Has anyone found a solution that handles cache["abc"] = nil?
You can do this by changing your protocol requirements somewhat.
Have the protocol require a subscript that does not use generics, and returns an Any?.
protocol Cache {
subscript(key: String) -> Any? { get set }
}
This subscript will let you do the following:
cache["abc"] = 5
cache["abc"] = nil
let value = cache["abc"] // value is an `Any?`
but it will not let you do this:
let number: Int? = cache["abc"] // error
So, let's fix that by adding another subscript to Cache. This subscript is equivalent to your original subscript requirement, except it doesn't need a setter and will call the other subscript (the one required by the protocol):
extension Cache {
subscript<Value>(key: String) -> Value? {
self[key] as? Value
}
}
(If you're worried that this subscript calls itself, don't be. self[key] here actually calls the other subscript, not this one. You can confirm this in Xcode by command-clicking on the [ or the ] in self[key] to jump to the definition of the other subscript.)
Then, implement the required subscript in your class:
class InMemoryCache: Cache {
private var cache: [String: Any] = [:]
subscript(key: String) -> Any? {
get { cache[key] }
set { cache[key] = newValue }
}
}
This will allow all of the following to compile:
let cache = InMemoryCache()
cache["abc"] = 5
let x: Int? = cache["abc"]
cache["abc"] = nil
There is a workaround to have your desire output.
Because this is a dictionary so you get assign nil directly in your InMemoryCache
class InMemoryCache: Cache {
private var cache: [String: Any] = [:]
subscript<Value>(key: String) -> Value? {
get {
cache[key] as? Value
}
set {
if let value = newValue {
cache[key] = value
} else {
cache[key] = nil // make nil directly here
}
}
}
}
In here because of Value is a generic type. So you can not assign nil directly. It must have a specific type.
Instead you can do like this
let nilValue : Int? = nil // any type nil you want
cache["abc"] = nilValue
or directly cast it to nil of any tupe before assign to dictionary
cache["abc"] = (nil as String?)
It will refresh anything value is store in the key.
Example
// value
let nilValue : Int? = nil
var number : Int? = nil
var string : String? = nil
cache["abc"] = 5
number = cache["abc"] // Optional.some(5)
cache["abc"] = "abc"
number = cache["abc"] // nil
string = cache["abc"] // Optional.some("abc")
cache["abc"] = nilValue
number = cache["abc"] // nil
string = cache["abc"] // nil
The reason why you are having a hard time with this is because
cache["abc"] = nil
cannot be compiled. There is not enough information to infer the generic type of the subscript - or of the optional value. The compiler sees something like
cache<?>["abc"] = Optional<?>.none
How is it supposed to figure out what to put in place of the question marks?
There's another ambiguity. Your cache can contain any type, even Optional. When you are assigning nil to the subscript, how does anybody know if you want to remove the element or store an instance of Optional<Something>.none at the subscript?
When I find myself fighting the language in this way, I usually try to take a step back and ask if I am perhaps doing something fundamentally bad. I think, in this case, the answer is yes. You are trying to pretend something is more strictly typed than it really is.
I think your getter/setter should explicitly take a value that is of type Any. It works better and it has the advantage that it explicitly documents for the user that a Cache conforming type can store anything in it.
For this reason, I would say TylerP's solution is the best. However, I would not create a subscript in the extension, I would define a function
extension Cache
{
func value<Value>(at key: String) -> Value?
{
self[key] as? Value
}
}
The reason for this is that the compiler can get confused when you have multiple subscripts with similar signatures. With the extension above, I can conform Dictionary<String, Any> to the protocol and not need a new class.
extension Dictionary: Cache where Key == String, Value == Any {}
var dict: [String : Any] = [:]
dict["abc"] = 5
let y: Int? = dict.value(at: "abc")
dict["abc"] = nil
Obviously, the above won't be useful to you if you need reference semantics for your cache.
TylerP's solution was pretty much bang on the money. For completeness though, here's what the code now looks like:
protocol Cache {
/// Handles when we need a value of a specific type.
subscript<Value>(_: String) -> Value? { get }
/// Handles getting and setting any value.
/// The getter is rarely used because the generic getter above
/// is used. Setting a value compiles because we don't care what
/// type is it. Setting a `nil` also compiles for the same reason.
subscript(_: String) -> Any? { get set }
}
class InMemoryCache: Cache {
private var cache: [String: Any] = [:]
subscript(key: String) -> Any? {
get { cache[key] }
set {
if let value = newValue {
cache[key] = value
} else {
remove(key)
}
}
}
subscript<Value>(key: String) -> Value? {
cache[key] as? Value
}
}

How can I translate this utility function into an extension function?

I wrote this utility function in Swift 4:
func insert<Key, Element>(_ value: Element, into dictionary: inout [Key : Set<Element>], at key: Key) {
if let _ = dictionary[key] {
dictionary[key]?.insert(value)
}
else {
var set = Set<Element>()
set.insert(value)
dictionary[key] = set
}
}
This is used like this:
insert("foo", into: &myDictionary, at: "bar")
... but I want to use it like this:
myDictionary.insert("foo", at: "bar")
I tried declaring it like this:
extension Dictionary where Value == Set<AnyHashable> {
mutating func insert(_ value: Value.Element, at key: Key) { // Error here
if let _ = self[key] {
self[key]?.insert(value)
} else {
var set = Set<Value.Element>() // Error here
set.insert(value)
self[key] = set
}
}
}
... but I get the following errors:
/path/to/Sequence Extensions.swift:2:41: error: 'Element' is not a member type of 'Dictionary.Value'
mutating func insert(_ value: Value.Element, at key: Key) {
~~~~~ ^
Swift.Set:608:22: note: did you mean 'Element'?
public typealias Element = Element
^
Swift._IndexableBase:3:22: note: did you mean '_Element'?
public typealias _Element = Self.Element
/path/to/Sequence Extensions.swift:6:23: error: type 'Value.Element' does not conform to protocol 'Hashable'
var set = Set<Value.Element>()
^
Unfortunately, Swift doesn't currently support parameterised extensions (the ability to introduce type variables in extension declarations), so you cannot currently directly express the notion of "an extension with a constraint to some Set<T>". However, it is a part of the generics manifesto, so hopefully it's something that makes its way into a future version of the language.
Even if your extension with Value constrained to Set<AnyHashable> compiled, it wouldn't be terribly useful. You would need to first convert your desired dictionary to a temporary [Key: Set<AnyHashable>], then call the mutating method on it, and then convert it back to its original type (using as!).
This is because the extension is on a Dictionary with heterogenous Set values. It would've been perfectly legal for the extension method to insert arbitrary Hashable elements into one of the values of the dictionary. But that's not what you wanted to express.
In simple cases, I would argue that there's no need for an extension in the first place. You can just say:
var dict = [String: Set<String>]()
dict["key", default: []].insert("someValue")
using Dictionary's subscript overload that takes a default value, as introduced in SE-0165.
If you still want an extension, I would advise simply making it more generic. For example, instead of constraining Value to Set; constrain it to the protocol SetAlgebra (which Set conforms to).
It represents types that can perform set-like operations, and also derives from ExpressibleByArrayLiteral meaning that you can implement your method using the exact syntax as above:
extension Dictionary where Value : SetAlgebra {
mutating func insert(_ value: Value.Element, at key: Key) {
self[key, default: []].insert(value)
}
}
Although one additional thing to consider here is the copy-on-write behaviour of Swift's collection types such as Set. In the above method, the dictionary will be queried for a given key, giving back either an existing set for that key, or a new empty one. Your value will then be inserted into this temporary set, and it will be re-inserted back into the dictionary.
The use of a temporary here means that if the set is already in the dictionary, the value will not be inserted into it in-place, the set's buffer will be copied first in order to preserve value semantics; which could be a performance concern (this is explored in more detail in this Q&A and this Q&A).
However that being said, I am currently looking to fix this for Dictionary's subscript(_:default:) in this pull request, such that the set can be mutated in-place.
Until fixed though, the solution is to first remove the set from the dictionary before mutating:
extension Dictionary where Value : SetAlgebra {
mutating func insert(_ value: Value.Element, at key: Key) {
var set = removeValue(forKey: key) ?? []
set.insert(value)
self[key] = set
}
}
In which case, the use of an extension is fully justified.
It's worth noting that the use of a protocol constraint here is the general solution (or workaround in some cases) to the problem of not having parameterised extensions. It allows you to realise the placeholders you need as associated types of that protocol. See this Q&A for an example of how you can create your own protocol to serve that purpose.
You could do it using a protocol to identify Sets:
protocol SetType
{
associatedtype Element:Hashable
init()
mutating func insert(_ : Element) -> (inserted: Bool, memberAfterInsert: Element)
}
extension Set:SetType
{}
extension Dictionary where Value : SetType
{
mutating func insert(_ value:Value.Element, at key:Key)
{
var valueSet:Value = self[key] ?? Value()
valueSet.insert(value)
self[key] = valueSet
}
}
var oneToMany:[String:Set<String>] = [:]
oneToMany.insert("Dog", at: "Animal")
oneToMany.insert("Cat", at: "Animal")
oneToMany.insert("Tomato", at: "Vegetable")
This will produce a dictionary of sets:
["Animal": Set(["Dog", "Cat"]), "Vegetable": Set(["Tomato"])]
A more appropriate implementation would use the same return value as a Set's insert() function however:
extension Dictionary where Value : SetType
{
#discardableResult
mutating func insert(_ value:Value.Element, at key:Key) -> (inserted: Bool, memberAfterInsert: Value.Element)
{
var valueSet:Value = self[key] ?? Value()
let result = valueSet.insert(value)
if result.inserted
{ self[key] = valueSet }
return result
}
}
[EDIT] I just read all of Hamish's response and realized that he had already given the same answer (essentially) and made use of SetAlgebra ( which I wasn't aware of) that does the same thing as the SetType I "reinvented". You should accept Hamish's answer.

Swift Dictionary access value using key within extension

It turns out that within a Dictionary extension, the subscript is quite useless since it says Ambiguous reference to member 'subscript'. It seems I'll either have to do what Swift does in its subscript(Key) or call a function. Any ideas?
For example,
public extension Dictionary {
public func bool(_ key: String) -> Bool? {
return self[key] as? Bool
}
}
won't work, since the subscript is said to be ambiguous.
ADDED My misunderstanding came from the fact that I assumed that Key is an AssociatedType instead of a generic parameter.
Swift type Dictionary has two generic parameters Key and Value, and Key may not be String.
This works:
public extension Dictionary {
public func bool(_ key: Key) -> Bool? {
return self[key] as? Bool
}
}
let dict: [String: Any] = [
"a": true,
"b": 0,
]
if let a = dict.bool("a") {
print(a) //->true
}
if let b = dict.bool("b") {
print(b) //not executed
}
For ADDED part.
If you introduce a new generic parameter T in extension of Dictionary, the method needs to work for all possible combination of Key(:Hashable), Value and T(:Hashable). Key and T may not be the same type.
(For example, Key may be String and T may be Int (both Hashable). You know you cannot subscript with Int when Key is String.)
So, you cannot subscript with key of type T.
For updated ADDED part.
Seems to be a reasonable misunderstanding. And you have found a good example that explains protocol with associated type is not just a generic protocol.

Checking for nil Value in Swift Dictionary Extension

I have the following code in a playground file:
extension Dictionary {
func test() {
for key in self.keys {
self[key]
}
}
}
var dict: [String: AnyObject?] = [
"test": nil
]
dict.test()
I will henceforth refer to the line within the for-each loop as the output since it is what's relevant. In this particular instance the output is nil.
When I change the for-each loop to look like this:
for key in self.keys {
print(self[key])
}
The output is "Optional(nil)\n".
What I really want to do is check the value for nil, but the code:
for key in self.keys {
self[key] == nil
}
outputs false.
One other thing I tried was the following:
for key in self.keys {
self[key] as! AnyObject? == nil
}
which produces the error:
Could not cast value of type 'Swift.Optional<Swift.AnyObject>' to 'Swift.AnyObject'
Any help with this is much appreciated!
You've gotten yourself into kind a mess, because a dictionary whose values can be nil presents you with the prospect of a double-wrapped Optional, and therefore two kinds of nil. There is the nil that you get if the key is missing, and then the nil that you get if the key is not missing and you unwrap the fetched result. And unfortunately, you're testing in a playground, which is a poor venue for exploring the distinction.
To see what I mean, consider just the following:
var d : [String:Int?] = ["Matt":1]
let val = d["Matt"]
What is the type of val? It's Int?? - an Int wrapped in an Optional wrapped in another Optional. That's because the value inside the dictionary was, by definition, an Int wrapped in an Optional, and then fetching the value by its key wraps that in another Optional.
So now let's go a bit further and do it this way:
var d : [String:Int?] = ["Matt":nil]
let val = d["Matt"]
What is val? Well, the playground may say it is nil, but the truth is more complicated; it's nil wrapped in another Optional. That is easiest to see if you print val, in which case you get, not nil, but "Optional(nil)".
But if we try for something where the key isn't there at all, we get a different answer:
let val2 = d["Alex"]
That really is nil, signifying that the key is missing. And if we print val2, we get "nil". The playground fails to make the distinction (it says nil for both val and val2), but converting to a String (which is what print does) shows the difference.
So part of the problem is this whole double-wrapped Optional thing, and the other part is that the Playground represents a double-wrapped Optional in a very misleading way.
MORAL 1: A dictionary whose value type is an Optional can get really tricky.
MORAL 2: Playgrounds are the work of the devil. Avoid them. Use a real app, and use logging to the console, or the variables pane of the debugger, to see what's really happening.
Checking if a dictionary value is nil makes sense only if the
dictionary values are an Optional type, which means that you have to
restrict your extension method to that case.
This is possible by defining a protocol that all optional types conform
to (compare How can I write a function that will unwrap a generic property in swift assuming it is an optional type?, which is just a slight modification of Creating an extension to filter nils from an Array in Swift):
protocol OptionalType {
typealias Wrapped
var asOptional : Wrapped? { get }
}
extension Optional : OptionalType {
var asOptional : Wrapped? {
return self
}
}
Now you can define an extension method with is restricted to
dictionaries of optional value types:
extension Dictionary where Value : OptionalType {
func test() {
for key in self.keys { ... }
}
}
As Matt already explained, self[key] can only be nil if that key
is missing in the dictionary, and that can not happen here. So you
can always retrieve the value for that key
let value = self[key]!
inside that loop. Better, enumerate over keys and values:
for (key, value) in self { ... }
Now value is the dictionary value (for key), and its type
conforms to OptionalType. Using the asOptional protocol property
you get an optional which can be tested against nil:
if value.asOptional == nil { ... }
or used with optional binding.
Putting all that together:
extension Dictionary where Value : OptionalType {
func test() {
for (key, value) in self {
if let unwrappedValue = value.asOptional {
print("Unwrapped value for '\(key)' is '\(unwrappedValue)'")
} else {
print("Value for '\(key)' is nil")
}
}
}
}
Example:
var dict: [String: AnyObject?] = [
"foo" : "bar",
"test": nil
]
dict.test()
Output:
Value for 'test' is nil
Unwrapped value for 'foo' is 'bar'

Referencing self in Dictionary extension

I'm trying to extend Dictionary but can't reference self with a key. I'm confused as to why this is.
extension Dictionary {
func foo() {
var result = self["key"]
}
}
I get this error :
Type 'DictionaryIndex' does not conform to protocol 'StringLiteralConvertible'
If anyone has any insight, it would be appreciated.
Dictionary is a Generic struct. It is generic on its Key and Value.
Thus in your extension you have to use Key as the type for the dictionary keys, and Value as the type for dictionary values.
The compiler is complaining because you are using the wrong type for the dictionary key extension.
Here is an example:
extension Dictionary {
func ext(key: Key) {
if let value = self[key] {
// use your value
println("Key is present")
} else {
println("No value for key")
}
}
}
let dic = ["A": 20]
dic.ext("A")
dic.ext("B")
Here is how you can do something similar ... it might make clearer why your test didn't work:
extension Dictionary {
var foo: String? {
if let key = "key" as? Key {
return self[key] as? String
}
return nil
}
}
let dic1 = ["A": "an A", "key": "the value"]
dic1.foo // "the value" as optional
dic.foo // nil since dic value type is Int
Since Dictionary is a generic struct, you might reconsider extending it as if it is a specific concrete type.