Swift === with Nil

Swift === with nil

It works exactly like you expect:

var s: String? = nil
s === nil // true

The only caveat is that to compare to nil, your variable must able to be nil. This means that it must be an optional, denoted with a ?.

var s: String is not allowed to be nil, so would therefore always returns false when === compared to nil.

Swift nil Any != nil

Think of Any and Optional<Wrapped> like boxes.

  1. Any is an opaque box that can hold anything. You can gleam what's inside by trying to cast it using as?.
  2. Optional<Wrapped> is a transparent box. It lets you see that its contents are either a value of Optional<Wrapped>.some(wrapped) or Optional<Wrapped>.none().

An Optional<Any> and Any containing an Optional<Wrapped> aren't the same thing.

1. x

is a value of Optional<Any>.none, a.k.a. nil. nil gets printed, so that makes sense.

2. type(of: x)

is the type of x, Optional<Any>, as we expected.

3. x == nil

is calling an == operator of type (T, T) -> Bool. Since both args need to be the same type, and since x has a value of Optional<Any>.none (of type Optional<Any>), nil is inferred to be Optional<Any>.none. The two are equivalent, so we get true, as expected.

4. y

is a value of type Any. At compile time, nothing more is known about y. It just so happens that the value behind hidden by the opaque curtain of Any is x. print is implemented to "see through" Any instances, to show you what's really there.

5. type(of: y)

is doing something similar to print. It's using runtime type information to see exactly what the runtime value stored into y is. The static type of y is Any, but type(of: y) shows us that the runtime type of its value is Optional<Any>.

6. y == nil

This is where it gets a little trickier.

The choice of which overload of a function or operator to call is done at compile time, based on the statically known types of the operands. That is to say, operators and functions aren't dynamically dispatched based on the types of their arguments, the way they're dynamically dispatched based on the type of their objects (e.g. the foo in foo.bar()).

The overload that's selected here is ==(lhs: Wrapped?, rhs: _OptionalNilComparisonType) -> Bool. You can see its implementation on lines 449-481 of Optional.swift.

Its left-hand-side operand is Wrapped?, a.k.a. an Optional<Wrapped>.

Its right-hand-side operand is _OptionalNilComparisonType. This is a special type that conforms to ExpressibleByNilLiteral.

Optional is one type that conforms to ExpressibleByNilLiteral, meaning that you can write let x: Optional<Int> = nil, and the compiler could use that protocol to understand that nil should mean Optional<Int>.none. The ExpressibleByNilLiteral protocol exists to allow this behaviour to be extensible by other types. For example, you can imagine a Python interopability framework, where you would want to be able to say let none: PyObject = nil, which could be passed into Python and resolve to None, Python's null type.

What's happening here is that the left hand side (y, of type Any), is being promoted to type Any?. The promoted value has type Optional<Any>.some(old_value_of_y). The right hand side, the nil, is being used to instantiate a value of _OptionalNilComparisonType, equivalent to calling _OptionalNilComparisonType.init(nilLiteral: ()).

Thus, your call site is equivalent to:

Optional<Any>.some((Optional<Any>.none) as Any) == _OptionalNilComparisonType(nilLiteral: ()) /*
↑ ↑↖︎_the value of x_↗︎ ↑↑
↑ ↖︎_the value of y _________↗︎↑
↖︎_the value of y after promotion to optional__↗︎ */

According to the implementation, the left side is a some, the right side is a nil, and thus they're unequal.

You might say:

Well this is pretty non-obvious behaviour, it's not what I wanted.

To which I would respond:

Don't ignore the compiler errors, they're right on point:

warning: comparing non-optional value of type Any to nil always returns false

Performance based difference between nil and empty string in swift

If I want to choose in between nil and " " . I will go for nil parameter as nil is better than sending a empty string as according to me string will be taken as a string even if its of one char length and nil is taken as empty which will actually save memory not a big difference. But, in case of 500 UITextFields yes it matters go for nil.

What's the difference between if nil != optional … and if let _ = optional …

After optimization, the two approaches are probably the same.

For example, in this case, compiling both the following with swiftc -O -emit-assembly if_let.swift:

import Darwin

// using arc4random ensures -O doesn’t just
// ignore your if statement completely
let i: Int? = arc4random()%2 == 0 ? 2 : nil

if i != nil {
println("set!")
}

vs

import Darwin

let i: Int? = arc4random()%2 == 0 ? 2 : nil

if let _ = i {
println("set!")
}

produces identical assembly code:

    ; call to arc4random
callq _arc4random
; check if LSB == 1
testb $1, %al
; if it is, skip the println
je LBB0_1
movq $0, __Tv6if_let1iGSqSi_(%rip)
movb $1, __Tv6if_let1iGSqSi_+8(%rip)
jmp LBB0_3
LBB0_1:
movq $2, __Tv6if_let1iGSqSi_(%rip)
movb $0, __Tv6if_let1iGSqSi_+8(%rip)
leaq L___unnamed_1(%rip), %rax ; address of "set!" literal
movq %rax, -40(%rbp)
movq $4, -32(%rbp)
movq $0, -24(%rbp)
movq __TMdSS@GOTPCREL(%rip), %rsi
addq $8, %rsi
leaq -40(%rbp), %rdi
; call println
callq __TFSs7printlnU__FQ_T_
LBB0_3:
xorl %eax, %eax
addq $32, %rsp
popq %rbx
popq %r14
popq %rbp
retq

Does anybody know the rationale behind (nil 0) == true and (nil = 0) == true in Swift?

Optionals are comparable, so they can be sorted, for example. The rules are very simple:

  1. Any two optionals that are nil compare equal.
  2. If one of the optionals is nil and the other is not, nil is less than non-nil.
  3. If both optionals are not nil, then the unwrapped values are compared.

As a consequence, nil equals nil, and nil is less than any non-nil optional.

It has nothing to do with the value 0 that you assigned. Assign -1000, or +100, or whatever you like, and you get the same result.

Swift nil values behaviour

Not exactly, you have to use Optional Chaining. In swift, an instance can only be nil if it is declared as an "optional" type. Normally this looks like this:

var optionalString : String?

Notice the ? after the String That is what makes it possible to be nil

You cannot call a method on that variable unless you first "unwrap" it, unless you use the aforementioned Optional Chaining.

With optional chaining you can call multiple methods deep, that all allow for a nil value to be returned:

var optionalResult = optionalString.method1()?.method2()?.method3()

optionalResult can also be nil. If any of the methods in the chain return nil, methods after it are not called, instead optionalResult immediately gets set to nil.

You cannot deal directly with an optional value until you explicitly handle the case that it is nil. You can do that in one of two ways:

Force it to unwrap blindly

println(optionalString!)

This will throw a runtime error if it is nil, so you should be very sure that it is not nil

Test if it is nil

You can do this by using a simple if statement:

if optionalString {
println(optionalString!)
}
else {
// it was nil
}

or you can assign it to a scoped variable so that you don't have to forcefully unwrap it:

if let nonoptionalString = optionalString {
println(nonoptionalString)
}
else {
// it was nil
}

How can ı add value to nil object in swift

See inline comments for an explanation of what's going on:

struct NilControl{
var name:String?
}

var k: NilControl? //you've defined k as NilControl? and not assigned it a value yet

print(k) //this will be nil, since k has not been set

k = NilControl() //this sets k to have a value (ie not nil), but its `name` is still nil at this point
k?.name = "name"

print(k?.name) //will print Optional("name")

If you want to do some nil checking on it before printing the name, it might look something like this:

k = NilControl(name: "name") //this sets k to have a value & assigns a name

if let k = k, let name = k.name {
print(name)
}

Is checking nil and empty for a set at the same time safe in Swift?

It is perfectly safe as it will execute the second statement only when the first one is true.

It's better to use:

   guard let newValue = newValue // First unwrap it
where newValue.count > 0 else { // Then check if the unwrapped value has items
return // If not we don't continue
}

// From this point you don't need to use ? or ! to access newValue anymore

Always try to use safe patterns in your Swift code. To me casting with ! is a code smell and I would always try to replace it with a if let thing = thing or guard let thing = thing statement

Checking for nill equality in custom == operator

Here's the code to make your class Equatable

class ClassXYZ: Equatable {
let uniqueID: String

init(uniqueID: String) {
self.uniqueID = uniqueID
}
}

func ==(left: ClassXYZ, right: ClassXYZ) -> Bool {
return left.uniqueID == right.uniqueID
}

You don't need (and you can't) to explicitly specify that nil == nil is true, it is already built into Swift, look

let a: ClassXYZ? = nil
let b: ClassXYZ? = nil

print(a == b) // true


Related Topics



Leave a reply



Submit