Why doesn't Swift a nil-coalescing ternary operator break up?

I read that ternary operator ?? expands optional if it is not nil, but if I do:

 var type: String? type = "milk" let certainType = type ?? "melon" 

then the specific type will still be String? and if I do

 println("it a \(certainType)") 

he will print:

 it a Optional("milk") 

Thoughts?

Update:

Sorry for the confusion - did I mean var type: String?

I get that he should print β€œthis is milk”, but what I saw in the console is β€œthis is optional (β€œ milk ”),β€œ did anyone else have the same problem? Could this be caused by string interpolation?

When asked by @Antonio, here is a more contextual and real code and the code of the snapshot of the log - this is a note, which is the NSManagedObject class used to work with xcdatamodel

 class Note: NSManagedObject { @NSManaged var type: String? } 

And at some point I have the type given by "todo", and then type the following code:

 println("type class:\(_stdlib_getDemangledTypeName(note.type))") let type1 = note.type ?? "note" println("type1:\(type1)") let type2: String = note.type ?? "note" println("type2:\(type2)") 

And the conclusion:

 type class:Swift.Optional type1:Optional("todo") type2:todo 

As you can see, if I do not explicitly specify type1 as String, it will print an undesired result. Optional ("todo") - I use the type in string interpolation to construct the path so that it matters

+6
source share
8 answers

I cannot prove what I'm going to say, so any feedback is very well appreciated .

OP claims the code is similar to this:

 var type: String? = "milk" let certainType = type ?? "melon" println("it a \(certainType)") 

prints an unexpected line:

"it a Optional (" milk ")"

whereas it should be:

"this is milk"

Turns out this happens when a variable is actually a property with the @NSManaged attribute.

I suspect there is an error in type inference. OP indicates that:

 let certainType = type ?? "melon" 

prints an incorrect result, whereas:

 let certainType: String = type ?? "melon" 

prints correct.

Therefore, for some reason, without explicitly specifying the type of the variable, the nil join operator returns optional.

Should I change the type of the variable type to AnyObject or AnyObject? it really prints an unexpected result :

 var type: AnyObject = "milk" let certainType = type ?? "melon" println("it a \(certainType)") 

"this is optional (milk)"

My guess is this: since the @NSManaged attribute is @NSManaged , the property is displayed with the wrong type ( AnyObject? ) When using it, unless the correct type is explicitly specified.

As to why this happens, there is no idea (besides the fact that this is a mistake)

Feel free to raise or decline this answer, and most importantly, do not consider it as a solution. I would be very grateful for the feedback, because I am interested in what is happening and whether this is really a mistake or not.

+6
source

This is (I think) by design. If you do this:

 let type = "mil" println("it a \(type)") 

If I'm not mistaken, this will print it a "milk" , which is much more useful when debugging than it a String . Note: \(...) is similar to %@ in Objective-C: classes can override their string representation.

In addition, as Antonio has already pointed out:

  • You cannot change an immutable variable (i.e. a let ).
  • The optionally valid variables are therefore useless (that is, they do not let type: String? = "milk" , because they obviously will never be zero).
+3
source

I read that ternary operator? expands optional if it is not zero, but ...

He turns it around.

let type: String? type = "milk" let specific Type = type ?? "Melon"

Your code will not compile, but if you change let to var, it will work, and the defined Type will be of type String.

 var type: String? type = "milk" let certainType = type ?? "melon" println("it a \(certainType)") // prints "it a milk" 
+3
source

This is called the Nil Coalescing Operator .

If you have optional a , the result is a ?? b a ?? b will be a! if a not nil and b if it is. This shortens this expression:

 a != nil ? a! : b 

So, you are using the operator correctly, but you must initialize the constant in the same line that you declare it:

 let type: String? = "milk" 

However, I assume that you do not want this constant in this context (since you check what it is), so if you use var to declare it, your existing code should work.

+2
source

Is this what you want

 let certainType = type! ?? "melon" 

Notice that I expanded the type. It works when you:

 let type2: String = note.type ?? "note" 

because you are essentially expanding your cast into String.

0
source

I had a similar problem.

I have a dictionary like [String : AnyObject] , but the record I then turns out to be a String value. It may not always be feared. I extracted it with the following code:

 let message = dictionary["message"] ?? "No message" 

However, when the entry is present, it will still give the line:

Optional (actual message)

i., is the variable message type String? .

I changed it to:

 let message = (dictionary["message"] as? String) ?? "No message" 

... and now the resulting value is an expanded, optional string.

0
source

In my case, the problem was the @NSManaged attribute of type NSNumber? I tried to wrap in a string.

let time = "\(nsManagedObject.optionalNsNumber ?? "") months" /// result "Optional(<random number>) months"

The solution to this problem was to convert NSNumber to stringValue . Below is the code that worked as expected.

let time = "\(nsManagedObject.optionalNsNumber.stringValue ?? "") months" /// result "<random number> months"

The Swift compiler will not detect a problem if the value is wrapped in a string. If you try to use the nil coalescing operator, then add the result to a line that will indicate an error, Can't add NSObject and String .

Be careful when @NSManaged attributes in strings.

0
source

I found one way to try.

 infix operator ??? /// use this custom operator to overcome issue related to '??' which always needs assignment to remove Optional /// /// - parameter lhs: left hand side variable /// - parameter rhs: right hand side variable /// /// - returns: it will return unwrapped value of one of the variable which has not nil value func ???(lhs: Any?, rhs: Any?) -> Any { let temp : Any = lhs ?? rhs return temp } 
0
source

Source: https://habr.com/ru/post/981820/


All Articles