Comparing Int and nil in swift [duplicate] - swift

This is valid code in Swift:
println(nil < 1)
And the output will be true, likewise
println(nil > 1)
will be false (the number 1 is arbitrary, you can do the same for -1 and probably something else). The reason I ask is because I saw some code that tried to compare "some_string".toInt() to a numeric value and it compiled, which seems wrong considering toInt() returns Int?.
My question is, should this be valid syntax in Swift? If so, what is the numeric value of nil?
Swift 3.0 Update:
Looks like Swift Evolution tackled this issue by removing the optional comparison operators. This is no longer an issue in Swift 3.0 as it doesn't compile.

I believe what is happening is that the literal 1 is being implicitly typecast to the Int? type by the comparison to nil. For those who aren't used to Swift, I'll explain a little further. Swift has a concept called "optionals", which can either have a value or be nil. (For anyone familiar with Haskell, this is basically the Maybe monad.) It's illegal to assign nil to a variable that wasn't explicitly defined as optional, so let i: Int = nil will be rejected by the compiler. This allows for several benefits which are out of the scope of this answer, and it's a rather clever way to do it.
What's happening here, though, is that the literal 1 is a valid value of several types: Int, Int32, Int64, UInt32, UInt64, etc., etc., etc. And it's also a valid value of the optional versions of those types: Int?, Int32?, etc.
So when the Swift compiler sees a comparison between a literal value and nil, it tries to find a type that both these values would be valid for. 1 is a valid value of the Int? type, and nil is also a valid value of the Int? type, so it applies the comparison operator with the type signature (Int?, Int?) -> Bool. (That's the comparison operator that takes two Int? values and returns a Bool). That operator's rules say that nil values sort lower than anything else, even Int.min, and so you get the result seen in the OP's question.

Related

Why are null checks bad / why would I want an optional to succeed if it's null?

I've read more than a few answers to similar questions as well as a few tutorials, but none address my main confusion. I'm a native Java coder, but I've programmed in Swift as well.
Why would I ever want to use optionals instead of nulls?
I've read that it's so there are less null checks and errors, but these are necessary or easily avoided with clean programming.
I've also read it's so all references succeed (https://softwareengineering.stackexchange.com/a/309137/227611 and val length = text?.length). But I'd argue this is a bad thing or a misnomer. If I call the length function, I expect it to contain a length. If it doesn't, the code should deal with it right there, not continue on.
What am I missing?
Optionals provide clarity of type. An Int stores an actual value - always, whereas an Optional Int (i.e. Int?) stores either the value of an Int or a nil. This explicit "dual" type, so to speak, allows you to craft a simple function that can clearly declare what it will accept and return. If your function is to simply accept an actual Int and return an actual Int, then great.
func foo(x: Int) -> Int
But if your function wants to allow the return value to be nil, and the parameter to be nil, it must do so by explicitly making them optional:
func foo(x: Int?) -> Int?
In other languages such as Objective-C, objects can always be nil instead. Pointers in C++ can be nil, too. And so any object you receive in Obj-C or any pointer you receive in C++ ought to be checked for nil, just in case it's not what your code was expecting (a real object or pointer).
In Swift, the point is that you can declare object types that are non-optional, and thus whatever code you hand those objects to don't need to do any checks. They can just safely just use those objects and know they are non-null. That's part of the power of Swift optionals. And if you receive an optional, you must explicitly unpack it to its value when you need to access its value. Those who code in Swift try to always make their functions and properties non-optional whenever they can, unless they truly have a reason for making them optional.
The other beautiful thing about Swift optionals is all the built-in language constructs for dealing with optionals to make the code faster to write, cleaner to read, more compact... taking a lot of the hassle out of having to check and unpack an optional and the equivalent of that you'd have to do in other languages.
The nil-coalescing operator (??) is a great example, as are if-let and guard and many others.
In summary, optionals encourage and enforce more explicit type-checking in your code - type-checking that's done by by the compiler rather than at runtime. Sure you can write "clean" code in any language, but it's just a lot simpler and more automatic to do so in Swift, thanks in big part to its optionals (and its non-optionals too!).
Avoids error at compile time. So that you don't pass unintentionally nulls.
In Java, any variable can be null. So it becomes a ritual to check for null before using it. While in swift, only optional can be null. So you have to check only optional for a possible null value.
You don't always have to check an optional. You can work equally well on optionals without unwrapping them. Sending a method to optional with null value does not break the code.
There can be more but those are the ones that help a lot.
TL/DR: The null checks that you say can be avoided with clean programming can also be avoided in a much more rigorous way by the compiler. And the null checks that you say are necessary can be enforced in a much more rigorous way by the compiler. Optionals are the type construct that make that possible.
var length = text?.length
This is actually a good example of one way that optionals are useful. If text doesn't have a value, then it can't have a length either. In Objective-C, if text is nil, then any message you send it does nothing and returns 0. That fact was sometimes useful and it made it possible to skip a lot of nil checking, but it could also lead to subtle errors.
On the other hand, many other languages point out the fact that you've sent a message to a nil pointer by helpfully crashing immediately when that code executes. That makes it a little easier to pinpoint the problem during development, but run time errors aren't so great when they happen to users.
Swift takes a different approach: if text doesn't point to something that has a length, then there is no length. An optional isn't a pointer, it's a kind of type that either has a value or doesn't have a value. You might assume that the variable length is an Int, but it's actually an Int?, which is a completely different type.
If I call the length function, I expect it to contain a length. If it doesn't, the code should deal with it right there, not continue on.
If text is nil then there is no object to send the length message to, so length never even gets called and the result is nil. Sometimes that's fine — it makes sense that if there's no text, there can't be a length either. You may not care about that — if you were preparing to draw the characters in text, then the fact that there's no length won't bother you because there's nothing to draw anyway. The optional status of both text and length forces you to deal with the fact that those variables don't have values at the point where you need the values.
Let's look at a slightly more concrete version:
var text : String? = "foo"
var length : Int? = text?.count
Here, text has a value, so length also gets a value, but length is still an optional, so at some point in the future you'll have to check that a value exists before you use it.
var text : String? = nil
var length : Int? = text?.count
In the example above, text is nil, so length also gets nil. Again, you have to deal with the fact that both text and length might not have values before you try to use those values.
var text : String? = "foo"
var length : Int = text.count
Guess what happens here? The compiler says Oh no you don't! because text is an optional, which means that any value you get from it must also be optional. But the code specifies length as a non-optional Int. Having the compiler point out this mistake at compile time is so much nicer than having a user point it out much later.
var text : String? = "foo"
var length : Int = text!.count
Here, the ! tells the compiler that you think you know what you're doing. After all, you just assigned an actual value to text, so it's pretty safe to assume that text is not nil. You might write code like this because you want to allow for the fact that text might later become nil. Don't force-unwrap optionals if you don't know for certain, because...
var text : String? = nil
var length : Int = text!.count
...if text is nil, then you've betrayed the compiler's trust, and you deserve the run time error that you (and your users) get:
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Now, if text is not optional, then life is pretty simple:
var text : String = "foo"
var length : Int = text.count
In this case, you know that text and length are both safe to use without any checking because they cannot possibly be nil. You don't have to be careful to be "clean" -- you literally can't assign anything that's not a valid String to text, and every String has a count, so length will get a value.
Why would I ever want to use optionals instead of nulls?
Back in the old days of Objective-C, we used to manage memory manually. There was a small number of simple rules, and if you followed the rules rigorously, then Objective-C's retain counting system worked very well. But even the best of us would occasionally slip up, and sometimes complex situations arose in which it was hard to know exactly what to do. A huge portion of Objective-C questions on StackOverflow and other forums related to the memory management rules. Then Apple introduced ARC (automatic retain counting), in which the compiler took over responsibility for retaining and releasing objects, and memory management became much simpler. I'll bet fewer than 1% of Objective-C and Swift questions here on SO relate to memory management now.
Optionals are like that: they shift responsibility for keeping track of whether a variable has, doesn't have, or can't possibly not have a value from the programmer to the compiler.

Precondition failed: Negative count not allowed

Error:
Precondition failed: Negative count not allowed: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.74.1/src/swift/stdlib/public/core/StringLegacy.swift, line 49
Code:
String(repeating: "a", count: -1)
Thinking:
Well, it doesn't make sense repeating some string a negative number of times. Since we have types in Swift, why not use an UInt?
Here we have some documentation about it.
Use UInt only when you specifically need an unsigned integer type with
the same size as the platform’s native word size. If this isn’t the
case, Int is preferred, even when the values to be stored are known to
be nonnegative. A consistent use of Int for integer values aids code
interoperability, avoids the need to convert between different number
types, and matches integer type inference, as described in Type Safety
and Type Inference.
Apple Docs
Ok that Int is preferred, therefore the API is just following the rules, but why the Strings API is designed like that? Why this constructor is not private and the a public one with UInt ro something like that? Is there a "real" reason? It this some "undefined behavior" kind of thing?
Also: https://forums.developer.apple.com/thread/98594
This isn't undefined behavior — in fact, a precondition indicates the exact opposite: an explicit check was made to ensure that the given count is positive.
As to why the parameter is an Int and not a UInt — this is a consequence of two decisions made early in the design of Swift:
Unlike C and Objective-C, Swift does not allow implicit (or even explicit) casting between integer types. You cannot pass an Int to function which takes a UInt, and vice versa, nor will the following cast succeed: myInt as? UInt. Swift's preferred method of converting is using initializers: UInt(myInt)
Since Ints are more generally applicable than UInts, they would be the preferred integer type
As such, since converting between Ints and UInts can be cumbersome and verbose, the easiest way to interoperate between the largest number of APIs is to write them all in terms of the common integer currency type: Int. As the docs you quote mention, this "aids code interoperability, avoids the need to convert between different number types, and matches integer type inference"; trapping at runtime on invalid input is a tradeoff of this decision.
In fact, Int is so strongly ingrained in Swift that when Apple framework interfaces are imported into Swift from Objective-C, NSUInteger parameters and return types are converted to Int and not UInt, for significantly easier interoperability.

Binary operator '&&' cannot be applied to two 'Int' operands

I wanted to check for below values firstName and lastName. But Swift will not allowing me to access. It is giving error like "Binary operator '&&' cannot be applied to two 'Int' operands".
if firstName.length && lastName.length {
}
In Swift you cannot check for non-null like in C and Objective-C, you have to write
if firstName.length > 0 && lastName.length > 0 { }
#Vadian has a good answer, but it could be put more clearly — and there's an extra wrinkle:
For things like logic operators (&& and ||) and the conditions of if and while statements, C accepts any type -- it just treats any zero value (which includes null pointers, but your string length here is just a zero integer) as false, and anything else as true.
In Swift, though, the only type allowed in such Boolean logic contexts is Bool — you can't pass an integer and expect to branch on whether the value is zero, so you have to use a comparison operator like > or ==, or a property or method that returns a Bool value.
Since you're dealing with Strings, you'd do best to use the isEmpty property anyway. Getting the length of a Swift String is not a "free" computation — the same number of bytes could be different numbers of human-readable characters depending on what those bytes are, so you can't count characters without examining bytes. It's a lot faster to answer whether the string is empty than to check all the bytes.
(Then again, maybe you're not using Swift strings anyway? Those don't have the length property you're using.)

What's the rationale of Swift's size methods taking `Int`s?

I've noticed a lot of swift built ins take or return Ints and not UInts:
Here are some examples from Array:
mutating func reserveCapacity(minimumCapacity: Int)
var capacity: Int { get }
init(count: Int, repeatedValue: T)
mutating func removeAtIndex(index: Int) -> T
Given that the language is completely new, and assuming that this design choice was not arbitrary - I'm wondering: Why do swift built ins take Ints and not UInts?
Some notes: Asking because I'm working on a few collections myself and I'm wondering what types I should use for things like reserveCapacity etc. What I'd naturally expect is for reserveCapacity to take a UInt instead.
UInt is a common cause of bugs. It is very easy to accidentally generate a -1 and wind up with infinite loops or similar problems. (Many C and C++ programmers have learned the hard way that you really should just use int unless there's a need for unsigned.) Because of how Swift manages type conversion, this is even more important. If you've ever worked with NSUInteger with "signed-to-unsigned" warnings turned on (which are an error in Swift, not an optional warning like in C), you know what a pain that is.
The Swift Programming Guide explains their specific rationale in the section on UInt:
NOTE
Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference.
Here is a possible explanation (I am no expert on this subject): Suppose you have this code
let x = 3
test(x)
func test(t: Int) {
}
This will compile without a problem, since the type of 'x' is inferred to be Int.
However, if you change the function to
func test(t: UInt) {
}
The compiler will give you a build error ('Int' is not convertible to 'UInt')
So my guess is that it is just for convenience, because Swift's type safety would otherwise require you to convert them manually each time.

What the difference between using or not using "!" in Swift?

The ! mark is used for the optional value in Swift to extract the wrapped value of it, but the value can be extracted without the !:
var optionalString: String? = "optionalString"
println(optionalString)
another example using the !:
var optionalString: String? = "optionalString"
println(optionalString!)
both the codes above get the right value, so I wonder what's the difference between using and not using !, is it just for detect an error at runtime if the optional value is nil or something else? Thanks in advance.
As others have already stated, a really good place to start would be with the official documentation. This topic is extraordinarily well covered by the documentation.
From the official documentation:
Trying to use ! to access a non-existent optional value triggers a
runtime error. Always make sure that an optional contains a non-nil
value before using ! to force-unwrap its value.
println() is probably not the best way to test how the ! operator works. Without it, println() will either print the value or nil, with it it will either print the value or crash.
The main difference is when we're trying to assign our optional to another value or use it in an argument to a function.
Assume optionalValue is an optional integer.
let actualValue = optionalValue
Using this assignment, actualValue is now simply another optional integer. We haven't unwrapped the value at all. We have an optional rather than an integer.
Meanwhile,
let actualValue = optionalValue!
Now we're forcing the unwrap. Actual value will be an integer rather than an optional integer. However, this code will cause a runtime exception is optionalValue is nil.
Your question is answered in the book "The Swift Programming Language: iBooks
Download it and search it for "!".
You could've easily found the answer without having to ask here. For future reference, please always remember to look in the manual first.
From "The Swift Programming Language":
You can use an "if" statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to "true"; if it has no value at all, it evaluates to "false".
Once you're sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional's name. The exclamation mark effectively says, "I know that this optional definitely has a value; please use it." This is known as forced unwrapping of the optional's value.
I've never heard of Swift before now, but reading the documentation seems clear
"Using the ! operator to unwrap an optional that has a value of nil results in a runtime error."
If in your application nil is a valid and expected value in any normal circumstance and/or you want to trap and handle it in your code then I suggest that you don't use it. If you never expect it to be nil then use it as a debug aid. Runtime error suggest to me that your program will be terminated with a message reported by the OS.