How to Find the Operator Definition in Swift

How can I find the operator definition in Swift?

Update for Xcode 13: Unfortunately, this does not work in Xcode 13 anymore. There is currently no way to “jump” to the definition of an operator.

Previous answer for Xcode 11: You can select the operator in the Xcode source editor, and choose "Navigate -> Jump to definition" from the menu, or press CMD+CTRL+J.

(This was broken in Xcode 10, but works again in Xcode 11, which is currently in beta.)

What does the ?= operator do in Swift?

This question is a quite interesting topic in Swift language.

In other programming languages, it is closed to operator overloading whereas in Swifty terms, it is called Custom Operators. Swift has his own standard operator, but we can add additional operator too. Swift has 4 types of operators, among them, first 3 are available to use with custom operators:

  • Infix: Used between two values, like the addition operator (e.g. 1 + 2)
  • Prefix: Added before a value, like the negative operator (e.g. -3).
  • Postfix: Added after a value, like the force-unwrap operator (e.g. objectNil!)
  • Ternary: Two symbols inserted between three values.

Custom operators can begin with one of the ASCII characters /, =, -, +, !, *, %, <, >, &, |, ^, ?, or ~, or one of the Unicode characters.

New operators are declared at a global level using the operator keyword, and are marked with the prefix, infix or postfix modifiers:

Here is a sample example in the playground[Swift 4].

 infix operator ?=

func ?= (base: inout String, with: String)
{
base = base + " " + with
}

var str = "Stack"
str ?= "Overflow"
print(str)

Output:

Stack Overflow

Please check the topic name Advanced operator in apple doc.

How can I get access or overridden the = operator in Swift?

You can not override the assignment operator (=), from the Swift Programming Language book

NOTE
It isn’t possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) can’t be overloaded.

Quote from this chapter

Difference between == and ===

In short:

== operator checks if their instance values are equal, "equal to"

=== operator checks if the references point the same instance, "identical to"

Long Answer:

Classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. Class references stay in Run Time Stack (RTS) and their instances stay in Heap area of Memory. When you control equality with == it means if their instances are equal to each other. It doesn't need to be same instance to be equal. For this you need to provide a equality criteria to your custom class. By default, custom classes and structures do not receive a default implementation of the equivalence operators, known as the “equal to” operator == and “not equal to” operator != . To do this your custom class needs to conform Equatable protocol and it's static func == (lhs:, rhs:) -> Bool function

Let's look at example:

class Person : Equatable {
let ssn: Int
let name: String

init(ssn: Int, name: String) {
self.ssn = ssn
self.name = name
}

static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.ssn == rhs.ssn
}
}

P.S.: Since ssn(social security number) is a unique number, you don't need to compare if their name are equal or not.

let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")

if person1 == person2 {
print("the two instances are equal!")
}

Although person1 and person2 references point two different instances in Heap area, their instances are equal because their ssn numbers are equal. So the output will be the two instance are equal!

if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}

=== operator checks if the references point the same instance, "identical to". Since person1 and person2 have two different instance in Heap area, they are not identical and the output the two instance are not identical!

let person3 = person1

P.S: Classes are reference types and person1's reference is copied to person3 with this assignment operation, thus both references point the same instance in Heap area.

if person3 === person1 {
print("the two instances are identical!")
}

They are identical and the output will be the two instances are identical!

Swift optionals and equality operator

Swift has an equality operator taking two optionals values
(of an Equatable base type):

public func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

The implementation can be found at Optional.swift:

public func == <T: Equatable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l == r
case (nil, nil):
return true
default:
return false
}
}

and it does what one would expect: The operands are equal if they
are both nil, or if they are both not nil and the unwrapped
values are equal.

Similar comparison operators < etc taking optionals have been
removed in Swift 3, compare
SE-0121 Remove Optional Comparison Operators:

Remove the versions of <, <=, >, and >= which accept optional operands.

Variants of == and != which accept optional operands are still useful, and their results unsurprising, so they will remain.

So this works as expected:

let b: Bool? = nil
print(b == true) // prints "false"

But as matt pointed out, this can not be done with implicitly unwrapped
optionals, here the left operand will be unwrapped:

let b: Bool! = nil
print(b == true) // crashes

Swift : Custom operator to update dictionary value


var d = ["first" : 10 , "second" : 33]

d["second"]?++

The operator could be implemented like this:

prefix operator +> {}
prefix func +> <I : ForwardIndexType>(inout i: I?) {
i?._successorInPlace()
}

var dict = ["a":1, "b":2]

+>dict["b"]

dict // ["b": 3, "a": 1]

Although I'm not sure how it would give you a frequencies function - I mean, if it's building a dictionary, it's not going to have any keys to begin with, so there won't be anything to increment. There are a bunch of cool ways to do it, though. Using the postfix ++, you can do this:

extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self {
result[element]?++ ?? {result.updateValue(1, forKey: element)}()
}
return result
}
}

Airspeed Velocity tweeted another cool way:

extension Dictionary {
subscript(key: Key, or or: Value) -> Value {
get { return self[key] ?? or }
set { self[key] = newValue }
}
}

extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self { ++result[element, or: 0] }
return result
}
}

Or, using an undocumented function:

extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for el in self {result[el]?._successorInPlace() ?? {result[el] = 1}()}
return result
}
}

Overloading ?? operator with Result type

You're expression let result = r ?? d does not match the function signature of your overload, and hence it doesn't know that it's your function that you want to call (and calls the regular nil coalescing operator instead).

Let's take a look at the signature:

func ??<T>(result: Result<T>, handleError: ErrorType -> T) -> T { ...

You use the first argument in your call almost correctly, it should be of type Result<T>, however not an optional. The 2nd parameter in your custom ?? function, however, is a closure, a function taking type ErrorType and returning generic T (in our example: String), and the second argument in your call must be of such a closure type. Hence, your two Result<String> instances r and d should not be used together with your custom ?? operator, but on their own together with the appropriate closure.

Define your two example instances of Result<String>---one containing an error and one containing a success---as

var r:Result<String> = Result<String>.Success("A-Ok")
var d:Result<String> = Result<String>.Error(LookupError.CapitalNotFound)

Now, to conform to your ?? function signature in our calls to it, we construct the right hand side of your expression to be a closure as follows:

var result = r ?? {
err in
switch err as! LookupError {
case .CapitalNotFound: return "Couldn't find capital"
case .PopulationNotFound: return "Couldn't find population"
}
}
print(result) /* A-Ok */

result = d ?? {
err in
switch err as! LookupError {
case .CapitalNotFound: return "Couldn't find capital"
case .PopulationNotFound: return "Couldn't find population"
}
}
print(result) /* Couldn't find capital */

Ok, now we actually call your ?? overload. These expressions above, however, looks quite messy, especially if we want to call our custom ?? operator frequently.

Instead of posting the same closure each time you perform your error check, we can create a handle to the closure that we make use of instead. The handle is used---just like the closure above---as the right hand side argument in the call to your custom ?? operator:

func myStringErrHandler () -> (ErrorType -> String) {
return { (err: ErrorType) -> (String) in
switch err as! LookupError {
case .CapitalNotFound: return "Couldn't find capital"
case .PopulationNotFound: return "Couldn't find population"
}
}
let errHandle = myStringErrHandler()

var result = r ?? errHandle
print(result) /* A-Ok */

result = d ?? errHandle
print(result) /* Couldn't find capital */

This could probably be done even neater, but you get the gist of it: we must make sure our call and its arguments conform to the signature of our custom function.



Related Topics



Leave a reply



Submit