Is 'x?.y' in Swift the same as 'x?' followed by '.y'? - syntax

I understand that in Swift, if I define
var opt:String? = "Optional"
I will get an error if I attempt
opt.isEmpty
since opt is of type String? which does does not have an isEmpty method. And I thought that I understood that
opt?.isEmpty
does not produce an error because opt? unwraps (any non-nil) opt, resulting in a String, which does have an isEmpty method. But
opt?
on its own results in a String? and not a String.
Is ?. a different operator from ? followed by .?
Try
(opt?).isEmpty
and get a suggestive error.

Yes opt?.isEmpty is different from String?.It is called optional chaining.From swift programming guide:
You specify optional chaining by placing a question mark (?) after the
optional value on which you wish to call a property, method or
subscript if the optional is non-nil. This is very similar to placing
an exclamation mark (!) after an optional value to force the
unwrapping of its value. The main difference is that optional chaining
fails gracefully when the optional is nil, whereas forced unwrapping
triggers a runtime error when the optional is nil.
This creates optional as you thinking
var opt:String?
Now
opt?.isEmpty //it will not crash if opt is nil
is same as except
opt!.isEmpty //it will crash if opt is nil
if opt! is nil than it will not crash at runtime.Optional chaining is used to call long sequences of optional without calling.Every optional chain returns optional i.e opt? returns optional unwraps it and if nil than not call isEmpty else call isEmpty and reutns value.
Also
(opt?).isEmpty
When you are writing above statement it is just optional(not optional of optional) and it fails to unwrap because of braces.So error is showing
$T2?? does not have a member named `isEmpty`
to unwrap it use
(opt?)!.isEmpty
it will return false
Edit: To clarify more
var o1 = opt?
var o2 = ((opt?)?)
is doing nothing in its own it just assign same value to o1,o2 i.e String?.
to unwrap opt and o1,o2 they both are optional and need single ! operator to unwrap it.
Also please do not misunderstood between String? and opt? they both are different when ? is used after some type in decleration it makes optional and when ? used after variable optit is used for unwrap in optional chaining and return optional value it is returning
Extra Stuff:
try this to more clarify
(((opt?)?)!).isEmpty //it will unwrap with single !
((((opt?)?)!)?).isEmpty //compiler will show suggestion to remove ?
the below statement makes optional of optional of optional
var opt:String??? = "Optional"
to unwrap
opt!!!.isEmpty
EDIT2
opt? always return optional but if opt is defined as String! it is implicit optional and opt? will return optional(explicit).But if opt is already optional opt? will do nothing
From swift programming guide
To put it another way:
If the type you are trying to retrieve is not optional, it will become optional because of the optional chaining.
If the type you are trying to retrieve is already optional, it will not become more optional because of the chaining.
Therefore:
If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.

But opt? on its own results in a String? and not a String.
Yes. According to the Swift language reference, Expressions, Postfix Expressions, Optional-Chaining Expression:
On its own, the postfix ? operator simply returns the value of its
argument as an optional.
So putting a ? by itself at the end of an optional is a complete no-op. It has no effect.
Is ?. a different operator from ? followed by .?
Yes. More specifically, ? has the optional-chaining effect when used in any "postfix expression", including when followed by () (function call), . (member access), and [] (subscript).

Related

Sense of Optional.orElse() [duplicate]

Why does this throw a java.lang.NullPointerException?
List<String> strings = new ArrayList<>();
strings.add(null);
strings.add("test");
String firstString = strings.stream()
.findFirst() // Exception thrown here
.orElse("StringWhenListIsEmpty");
//.orElse(null); // Changing the `orElse()` to avoid ambiguity
The first item in strings is null, which is a perfectly acceptable value. Furthermore, findFirst() returns an Optional, which makes even more sense for findFirst() to be able to handle nulls.
EDIT: updated the orElse() to be less ambiguous.
The reason for this is the use of Optional<T> in the return. Optional is not allowed to contain null. Essentially, it offers no way of distinguishing situations "it's not there" and "it's there, but it is set to null".
That's why the documentation explicitly prohibits the situation when null is selected in findFirst():
Throws:
NullPointerException - if the element selected is null
As already discussed, the API designers do not assume that the developer wants to treat null values and absent values the same way.
If you still want to do that, you may do it explicitly by applying the sequence
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
to the stream. The result will be an empty optional in both cases, if there is no first element or if the first element is null. So in your case, you may use
String firstString = strings.stream()
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
.orElse(null);
to get a null value if the first element is either absent or null.
If you want to distinguish between these cases, you may simply omit the flatMap step:
Optional<String> firstString = strings.stream()
.map(Optional::ofNullable).findFirst().orElse(null);
System.out.println(firstString==null? "no such element":
firstString.orElse("first element is null"));
This is not much different to your updated question. You just have to replace "no such element" with "StringWhenListIsEmpty" and "first element is null" with null. But if you don’t like conditionals, you can achieve it also like:
String firstString = strings.stream()
.map(Optional::ofNullable).findFirst()
.orElseGet(()->Optional.of("StringWhenListIsEmpty"))
.orElse(null);
Now, firstString will be null if an element exists but is null and it will be "StringWhenListIsEmpty" when no element exists.
You can use java.util.Objects.nonNull to filter the list before find
something like
list.stream().filter(Objects::nonNull).findFirst();
The following code replaces findFirst() with limit(1) and replaces orElse() with reduce():
String firstString = strings.
stream().
limit(1).
reduce("StringWhenListIsEmpty", (first, second) -> second);
limit() allows only 1 element to reach reduce. The BinaryOperator passed to reduce returns that 1 element or else "StringWhenListIsEmpty" if no elements reach the reduce.
The beauty of this solution is that Optional isn't allocated and the BinaryOperator lambda isn't going to allocate anything.
Optional is supposed to be a "value" type. (read the fine print in javadoc:) JVM could even replace all Optional<Foo> with just Foo, removing all boxing and unboxing costs. A null Foo means an empty Optional<Foo>.
It is a possible design to allow Optional with null value, without adding a boolean flag - just add a sentinel object. (could even use this as sentinel; see Throwable.cause)
The decision that Optional cannot wrap null is not based on runtime cost. This was a hugely contended issue and you need to dig the mailing lists. The decision is not convincing to everybody.
In any case, since Optional cannot wrap null value, it pushes us in a corner in cases like findFirst. They must have reasoned that null values are very rare (it was even considered that Stream should bar null values), therefore it is more convenient to throw exception on null values instead of on empty streams.
A workaround is to box null, e.g.
class Box<T>
static Box<T> of(T value){ .. }
Optional<Box<String>> first = stream.map(Box::of).findFirst();
(They say the solution to every OOP problem is to introduce another type :)

Swift Wrap and Unwrap

I'm a little confused about Swift Wrap and Unwrap! So lets say this is my code:
var name:String? = "FirstName"
print(name)
Does the print function automatically unwrap the name which is optional? so I do not need to say
print(name!) in order to unwrap the name?
I guess what I am trying to understand is these two are equivalent for unwraping an optional variable?
print("name") is just like saying print ("name"!)
The other question I have is about nil.
is saying var name:String? = "FirstName" equivalent to saying var name:String? = nil . So does assigning a nil value wraps a variable?
When something can be nil it can be two things, it can be Some (the value of the given type) or it can be nil.
declaring something like this:
var name: String?
Means that the name variable can be nil, if you assigned a value to it you need to unwrap it to use it.
name = "FirstName"
Now the name variable has been defined, however you still need to ensure it's not nil in some cases, in other cases however (such as when the string doesn't need to be not nil) optional chaining is used.
Optional chaining allows the continuous evaluation of nil or some throughout a statement as long as it's not required to be not nil. If that is the case then you will need to unwrap it:
let someThingRequiresAString = NeedAStringInitializer(string: name!)
In the above statement if name is nil the program will crash, there are several approaches to dealing with things like this, here's a quick example:
if name != nil {
let someThingRequiresAString = NeedAStringInitializers(string: name!)
}
Here you know you can do this b/c name has been evaluated to not be nil. You can also use a nil coalescing operator, or a guard statement. Here's a quick example of nil coalescence in Swift:
let someThingRequiresAString = NeedAStringInit(string: name ?? "New Name")
The optional paradigm is quite powerful and expressive.

Swift optionals - warning on conditional cast from 'x' to 'x' always succeeds

I was wondering if there is a way to turn off/avoid 'yellow' warnings in xcode on if let...NSUserDefaults constructs where the key is of a known value.
For example:
if let x = NSUserDefaults.standardUserDefaults().integerForKey("myKey") as? Int {...}
Because of the if let I have to use as?. However, as I am using a known value type (in this case integer) the as? Int is effectively redundant - which is why I am getting the 'yellow warning'.
Thoughts? Is there a better way to code these types of constructs?
My suggestion would be to address the issue instead of silencing the warnings. :)
NSUserDefaults.standardUserDefaults().integerForKey("myKey") does not return an Optional, and the type is known, so you don't need neither optional binding with if let nor type casting with as?.
Just this:
let x = NSUserDefaults.standardUserDefaults().integerForKey("myKey")
will suffice, since .integerForKey just returns 0 if it can't get the actual value.
If you don't like this behavior of getting a default value (I don't), then don't use .integerForKey and use objectForKey with optional binding and type casting instead. Like you were doing first but with .objectForKey replacing .integerForKey. That way you'll get an actual nil if the value for the key is unreachable, not a default value.
if let x = NSUserDefaults.standardUserDefaults(). objectForKey("myKey") as? Int {...}
First of all check always the signature:
⌥-click on the symbol integerForKey: or look at Quick Help.
You will see:
func integerForKey(_ defaultName: String) -> Int
It reveals the return value is a non optional.
Non optionals can retrieved directly as described in Eric's answer without any type casting, optional binding causes an error.
That's one of the essential semantics in Swift.

Returning an Unwrapped Optional in Swift?

When I was sifting through some of the class discussions for AVFoundation, I stumbled upon the following:
class func defaultDeviceWithMediaType(mediaType: String!) -> AVCaptureDevice!
Because optionals are a new concept to me, I'm a bit confused.
The discussion says that this method could either return "the default device with the given media type, or nil if no device with that media type exists." However, if there is a possibility that it's returning nil, why do they unwrap this optional in the return statement? Shouldn't it be AVCaptureDevice?
Then, when looking at an example that utilizes the above method, I find the following:
public lazy var device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
public func hasFlash() -> Bool {
if let d = self.device {
return d.hasFlash
}
return false
}
From what I understand, you would use an if let statement when you have an optional, but because the class defaultDeviceWithMediaType returns an unwrapped variable, why is having an if let necessary?
Thank you so much in advance.
Implicitly unwrapped optional is basically an optional, that gets an ! everywhere you use it. Thats it.
e.g.:
//this:
var number: Int? = ...
print(number!)
//is the same as this:
var number: Int! = ...
print(number)
An implicitly unwrapped optional is only to save you the need of unwrapping it every time you use it, wether with if let or with an !, but it has the same optionality of being nil as a normal optional.
A popular use of Implicitly unwrapped optionals is with outlets - they can't be non-optionals because we don't init them in the init of the VC, but we definitely have them later, so having them unwrapped saves us the need to do annoying things like if let table = self.tableView....
An implicitly unwrapped optional is still an optional - it could be nil. If you simply write self.device.hasFlash, when self.device is nil, you will get an exception.

Swift Optionals vs. Ruby ||=

I'm making the transition from learning Ruby to Swift and trying to make any useful associations in order to get a better understanding of similar concepts from both programming languages. I noticed in Swift there are optionals which either have or don't have a value assigned to variables.
var optinalString: String? = "This is optional"
In Ruby we have ||= which from what I understand does something very similar where if the user doesn't assign a value to this variable, then it will use the predefined one that's already been set.
optionalString ||= "This is optional"
Am I on the right track with this assumption? Overall what makes these concepts similar/different?
These two concepts are not equivalent.
In your Swift example, you're creating a variable of type String? and assigning it the value of a string literal. In the Ruby example, you're assigning a string literal to your optionalString variable if optionalString is undefined, nil, or evaluates false (more info).
In Swift, when you create a variable of optional type, all you're doing is specifying that the variable is allowed to be nil, so a closer representation of your Ruby example might look like this:
var optionalString: String?
optionalString = optionalString ?? "This is optional"
Which uses Swift's nil coalescing operator and is equivalent to the following usage of the ternary conditional operator, where optionalString is assigned the unwrapped value of optionalString if it isn't nil, or a fallback value of "This is optional" if it isn't.
optionalString = optionalString != nil ? optionalString! : "This is optional"
Note that by doing this, your variable will still have an optional type and need to be unwrapped to be used, and since you're fallback value is a string literal that won't ever be nil, you can confidently forcibly unwrap the optional with the ! operator.
But even though this can be used to set a variable with a fallback value, it still isn't entirely the same as your Ruby example since all it's doing is checking the nilness of the variable, and not whether it evaluates false or is undefined.
In Swift, you can't test the falseness of variables by sticking them into conditions unless they are instances of a type that conforms to the BooleanType protocol. This means that if you wanted to achieve something similar with a type that supports a falseness check, you could implement something like this:
var optionalBool: Bool? = false
optionalBool = optionalBool != nil ? (!optionalBool! ? true : optionalBool!) : true
Which will assign a fallback value of true to the optionalBool variable if the variable is either nil or evaluates to false. (optionalBool will still need to be unwrapped for most uses)
But this still leaves a difference with undefined variables, and as far as I know, there isn't any way to achieve the equivalence to Ruby's ||= in this regard in Swift without inlining the nilness checks in the instantiation of a variable based on a fallback value and the value of some other variable.
var optionalString: String?
var nonOptionalString = optionalString ?? "This is not optional"
Note, there's no point in nonOptionalString being optional here, since it will always have a value.

Resources