Swift operators == vs === - swift

I have stupid question, I'm most certain, that I do something wrong, but can't figure out what it is. I have simple playground where I play with Swift Operators and came on case, where I have following code:
1 != 1 // false
1 !== "1".toInt() //false
1 === 1 // true
1 == "1".toInt() // true
Which should be perfectly fine, but the playground compiler is displaying following error:
What am I doing wrong? What exactly this issue mean?
Update
When I delete the line #2, the error disappear:
Xcode Version 6.1 (6A1052d)
Update 2
When I compare 1 === 1.toInt() I got another error:

=== is the identity operator and can only be applied to instances of classes,
it is declared as
func ===(lhs: AnyObject?, rhs: AnyObject?) -> Bool
Now 1 === 1 works because the compiler creates NSNumber instances here
automatically. NSNumber conforms to the IntegerLiteralConvertible
protocol:
extension NSNumber : FloatLiteralConvertible, IntegerLiteralConvertible, BooleanLiteralConvertible {
/// Create an instance initialized to `value`.
required convenience init(integerLiteral value: Int)
/// Create an instance initialized to `value`.
required convenience init(floatLiteral value: Double)
/// Create an instance initialized to `value`.
required convenience init(booleanLiteral value: Bool)
}
This can also be seen from the assembly code generated with
xcrun -sdk macosx swiftc -emit-assembly main.swift
which shows two calls of
callq __TFE10FoundationCSo8NSNumberCfMS0_FT14integerLiteralSi_S0_
and demangling this function name with
xcrun swift-demangle __TFE10FoundationCSo8NSNumberCfMS0_FT14integerLiteralSi_S0_
gives
ext.Foundation.ObjectiveC.NSNumber.init (ObjectiveC.NSNumber.Type)(integerLiteral : Swift.Int) -> ObjectiveC.NSNumber
So in 1 === 1 two instances of NSNumber are compared (which are objects).
Note that this works only if the Foundation framework is included (i.e., NSNumber
is available). Otherwise 1 === 1 fails to compile with
type 'AnyObject?' does not conform to protocol 'IntegerLiteralConvertible'
Both
1 !== "1".toInt() // value of optional type 'Int?' not unwrapped
1 !== "1".toInt()! // type 'AnyObject?' does not conform to protocol 'IntegerLiteralConvertible'
do not compile because the right-hand side is not an object and not a literal that
the compiler converts in to an object automatically. For the same reason,
let i = 1
1 !== i // type 'Int' does not conform to protocol 'AnyObject'
does not compile.
==, on the other hand, is the equality operator and compares the contents of its
operands. It is defined for optionals if the underlying type is equatable:
func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool
Therefore in 1 == "1".toInt(), the lhs is converted to Int? and then compared
with the rhs.

Mind you, I never programmed or even heard of Swift, but from the
documentation I found and the experience in C#, I try to give an
answer I think is correct. If not, I'll remove the answer.
Swift seems to have (like C#) "optional types", that are denoted with a question mark after to the type identifier, like this: int?. toInt() seems to return an "optional int", which is not identical with an int (as shown by the error).
To make that optional int to a "normal" int, use an exclamation mark:
1 == "1".toInt()!

The "===" operator is to test whether two object references both refer to the same object instance
In other languages, i know it is used to test if it is the same type and value.
But you called the to.Int() function on a string literal, when the code was expecting an integer literal.
I'd do it like this:
let a = "1";
let b = a.toInt()
if 1 !== b {// Do something}

Related

Weird optional type behaviour in swift forEach

This code works fine. It iterates my array of one Int! and prints its magnitude.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
}
Output:
1
Presumably, i in the loop body is an Int or an Int!, and indeed if I ask Xcode for "quick help" on forEach it reports:
func forEach(_ body: (Int) throws -> Void) rethrows
However, if perform two statements in my forEach body, instead it fails to compile, complaining that I need to unwrap i which now has the optional type Int?.
import Foundation
let x : Int! = 1
[x].forEach {i in
print(i.magnitude)
print(i.magnitude)
}
Compile error:
Value of optional type 'Int?' must be unwrapped to refer to member 'magnitude' of wrapped base type 'Int'
And if I ask for "quick help" now I get:
func forEach(_ body: (Int?) throws -> Void) rethrows
How on earth does the number of statements I place in my loop body manage to affect the type of the loop variable?
Basically, you've elicited an edge case of an edge case. You've combined two things that are the work of the devil:
Implicitly unwrapped Optionals
Implicit type inference of closures, along with the fact that
Implicit type inference of closures works differently when the closure consists of one line (this is where the "How on earth does the number of statements" comes in)
You should try to avoid both of those; your code will be cleaner and will compile a lot faster. Indeed, implicit type inference of anything other than a single literal, like a string, Int, or Double, is a huge drag on compilation times.
I won't pretend to imitate the compiler's reasoning; I'll just show you an actual solution (other than just not using an IUO in the first place):
[x].forEach {(i:Int) in
print(i.magnitude)
print(i.magnitude)
}
Our Int type is legal because we take advantage of the single "get out of jail free" card saying that an implicitly unwrapped Optional can be used directly where the unwrapped type itself is expected. And by explicitly stating the type, we clear up the compiler's doubts.
(I say "directly" because implicit unwrappedness of an Optional is not propagated thru passing and assignment. That is why in your second example you discovered Int?, not Int, being passed into the closure.)

Enforce function parameter must be optional

I have a custom operator ?= that is used to simply assign optional values to non-optionals.
var a: String
let b: String?
a = b ?? a
// is simplified to
a ?= b
This works well, but I don't want people to be able to use this operator when b is not optional. It's not going to cause any problems but it looks bad and I don't like it.
My function signature is currently:
func ?=<T> (originalValue: inout T, optionalNewValue: T?)
How could I make this cause a compiler warning or error when optionalNewValue is not actually an optional?
As other have said in the comments, the ?= operator might not be the best solution to your problems. Now if you're keen to that operator, or adds value to your code base, then there is a workaround that would allow you to reject non optional values on the right hand side of the operator.
You can use an OptionalCompatible protocol for the right hand side of the operator:
protocol OptionalCompatible {
associatedtype Wrapped
var optionalValue: Wrapped? { get }
}
extension Optional: OptionalCompatible {
var optionalValue: Wrapped? { return self }
}
func ?=<T, U> (originalValue: inout T, optionalNewValue: U) where U: OptionalCompatible, U.Wrapped == T {
originalValue = optionalNewValue.optionalValue ?? originalValue
}
Using a custom protocol will disable the auto-promotion of non-optionals to optionals, allowing only optionals to be used.
There is a caveat, though: in theory the conformance OptionalCompatible can be added to any type.
How could I make this cause a compiler warning or error when optionalNewValue is not actually an optional?
You cannot. It is a built-in fact of Swift that a nonOptional of type T can always be assigned or passed where an Optional<T> is expected.

Implicit type casting in Swift

Playing with the sample code from Swift Language Guide: Extensions I've extedned struct Double like this
extension Double {
func someFunc() {
print("someFunc")
}
}
I was surprised that this statement
2.someFunc()
did not generate compile time error like: Value of type 'Int' has no member 'someFunc'. I've expected value of 2 to be implicitly casted to Int but Swift casted it to Double. Why is that ? How does Swift determine that value of 2 in this case is of type Double ?
Then I've tried calling someFunc() like that
let x = 2
x.someFunc()
Here I get the expected compile time error
Does'n this contradict statement in Swift Programming Language 3.0.1 : Language guide : The basics : Type Safety and Type Inference?
Type inference enables a compiler to deduce the type of a particular
expression automatically when it compiles your code, simply by
examining the values you provide.
EDIT
From the responses I've learned that it happens because Double conforms to ExpressibleByIntegerLiteral protocol. However Float struct also does conform to it and some other types as well. Below I have created my struct that also conforms to that protocol. In the end however Double is chosen at compile time. Why? How is the precedence of method from one extension determined over the method from other extension ?
struct someStruct: ExpressibleByIntegerLiteral{
var i:Int = 0
init(integerLiteral value: Int64){
i = Int(value)
}
}
extension someStruct {
func someFunc() {print("Somestruct someFunc") }
}
extension Double {
func someFunc() { print("Double someFunc") }
}
4.someFunc()
//prints: Double someFunc
Double is one of the types that conforms to the protocol ExpressibleByIntegerLiteral. Since 2 is an integer leteral, the compiler can check which of the types conforming to the protocol has a someFunc() and since only Double does, there is no abiguity in this context.
Double conforms to ExpressibleByIntegerLiteral. In your example, the compiler sees that of the all the types that conform to ExpressibleByIntegerLiteral, only Double contains someFunc(), so it knows to create a Double out of 2.
As you noticed in your second example, this behaviour doesn't define implicit casting between types. It only applies to literals.

Filter function syntax?

This works:
func removeObject<T : Equatable>(object: T, array: [T]) -> Array<T>
{
return array.filter() { $0 != object }
}
let threeThings = ["one", "two", "three"]
twoThings = removeObject("three", threeThings)
However, I'd like to check for inequality with this !==. Then I get error "Type 'T' does not conform to protocol 'AnyObject'"
How can this code be fixed? (I've see the code here but I'd like to learn how to use filter properly).
The identical operator === and its negation !== are only defined for
instances of classes, i.e. instances of AnyObject:
func removeObject<T : AnyObject>(object: T, array: [T]) -> Array<T>
{
return array.filter() { $0 !== object }
}
=== checks if two variables refer to the same single instance.
Note that your code
let threeThings = ["one", "two", "three"]
twoThings = removeObject("three", threeThings)
does still compile and run, but gives the (perhaps unexpected) result
[one, two, three]
The Swift strings (which are value types and not class types) are automatically
bridged to NSString, and the two instances of NSString representing "three"
need not be the same.
If you want to use !== instead of !=, then, instead of the type constraint <T : Equatable> say <T : AnyObject>. All you have to do is listen to what the error message is telling you!
Note that this has nothing to do with using the filter function. It is simply a matter of types. You cannot use a method with an object of a type for which that method is not implemented. !== is implemented for AnyObject so if you want to use it you must guarantee to the compiler that this type will be an AnyObject. That is what the type constraint does.
!== checks for "identity", not "equality". Identity is a property of reference types which all support the AnyObject protocol, and it means that the two variables that you are comparing point to the same actual object, and not just another object with the same value.
That means you can't use === or !== with normal value types, like strings, integers, arrays, etc.
Try typing this into a playground:
let a = "yes"
let b = a
println(a === b)
You should get a message saying that String doesn't conform to the AnyObject protocol, because String is a value type (a struct) and doesn't support AnyObject, so you can't use === with it.
You can use === with any instance of a class, because classes are reference types, not value types.
You could put a constraint on T requiring that it conform to AnyObject.
func removeObject<T : Equatable where T: AnyObject>...
It should work, then, for reference types (including all class instances). But then your function won't work for value types (which include all structs).
Why do you need to check for identity (===) instead of equality (==)?

Swift: How to test a variable is a SequenceType?

My intent is to check if a variable is of SequenceType
Here is the code:
let a = []
a is SequenceType
XCode 6 beta 5 playground flags these errors:
I also tried an alternative syntax:
a.isMemberOfClass(SequenceType)
This time XCode 6 beta 5 playground shows these errors:
I have two questions here:
1) What do these error messages mean in each case?
2) What is the proper to test a is a subclass of a certain type?
You can't dynamically check for SequenceType conformance.
The compiler is trying to say that SequenceType has a typealias Generator: GeneratorType and a protocol with a type requirement (typealias) can only be used as a constraint on generic types, e.g.:
func doSomethingOnSequence <S: SequenceType> (seq: S) {
for i in seq {
println(i)
}
}
doSomethingOnSequence(a)
Since you can use generics there's probably a better way than checking for types with is.
If you still want to try checking against a less generic type you're doing it right (just using the wrong types):
let a: Any = []
a is Range<Int>
a is [String]
// and so on...