Swift: method overloads that differ only in return type

I see Swift classes where two methods are defined that differ only in the return type. I'm not used to working in languages ​​where it is allowed (Java, C #, etc.), so I went looking for documentation that describes how this works in Swift. I haven’t found anything anywhere. I would expect a whole section to appear in Swift's book. Where is this documented?

Here is an example of what I am saying (I am using Swift 2, FWIW):

class MyClass { subscript(key: Int) -> Int { return 1 } subscript(key: Int) -> String { return "hi" } func getSomething() -> Int { return 2 } func getSomething() -> String { return "hey" } } 

Test:

  let obj = MyClass() //let x = obj[99] // Doesn't compile: "Multiple candidates fail to match based on result type" let result1: String = obj[123] print("result1 \(result1)") // prints "result1 hi" let result2: Int = obj[123] print("result2 \(result2)") // prints "result2 1" //let x = obj.getSomething() // Doesn't compile: "Ambiguous use of 'getSomething'" let result3: String = obj.getSomething() print("result3 \(result3)") // prints "result3 hey" let result4: Int = obj.getSomething() print("result4 \(result4)") // prints "result4 2" 
+5
source share
3 answers

Where is this documented?

Regarding subscript :

Language Reference / Declarations / Declaration

You can overload the index declaration in the type in which it is declared, if the parameters or return type differ from the one you overloaded.

Language Guide / Subscript / Substring Options

A class or structure can provide as many implementations of customizations as needed, and the corresponding index to be used will be derived based on the value types or values ​​contained in the parentheses of the index at the point at which the index is used.

I cannot find official docs about overload methods or functions. but on Swift Blog:

Override everything with Swift REPL / Redefinition or Overload?

Keep in mind that Swift allows function overloading, even if two signatures differ only in return type.

+7
source

The type of the function is determined by the type of its arguments and the type of the return value, and the compiler can uniquely use named functions by type - from your example:

 subscript(key: Int) -> Int { return 1 } 

... has type (Int) -> Int

 subscript(key: Int) -> String { return "hi" } 

... has type (Int) -> String

- therefore, although they are named the same way, the compiler can determine which one is caused by the way the return value is assigned (or since it is a subscript value, to which value this index is assigned)

continues:

 func getSomething() -> Int { return 2 } 

... has type () -> Int

 func getSomething() -> String { return "hey" } 

... has type () -> String

Note: where you may run into a problem if you do not provide the compiler with enough information to determine which function you are calling, for example. if you just called getSomething() without doing anything with its return value, it will complain about ambiguous use of 'getSomething'

EDIT - oh, now I see in your code example that you really provide an example where this is so :) by assigning the return value to a constant for which you did not specify the type ( let x = getSomething() ) there is not enough information for the compiler to figure out what function you are calling

EDIT EDIT - note that when I start with “the compiler can resolve ambiguous named functions by type”, the names of the functions are defined: (1) the identifier of the function, as well as (2) the identifiers of the names of the external parameters of the function - for example although the following two functions have the same type and function identifier, they are different functions and have different function names, because they differ in identifiers used for their external parameter names:

 func getSomething(thing: String, howMany: Int) -> String 

... is of type (String, Int) -> String and is called getSomething(_:howMany:)

 func getSomething(thing: String, howManyTimes: Int) -> String 

... is of type (String, Int) -> String and is called getSomething(_:howManyTimes:)

+6
source

This is a pretty cool aspect of Swift. I am currently using it in a generic class to have multiple indexes. Here is the playground I created for the seminar:

 import Foundation /* Return Type Differentiation This playground illustrates a rather useful capability of Swift: The ability to differentiate methods by return type; not just argument list. In this example, we will set up multiple subscript() methods for an aggregator/façade class that will access the contained instances in various ways, depending on the return type requested. */ // This class should win the igNoble prize for poitry. struct A { let poem: [String] = ["I'm a little teapot", "bloody and cut.", "This is my handle.", "This is my "] let multiplier: UInt32 = arc4random_uniform(100) // Just a random integer from 0 to 100. } // This class has a few different data types that are set at instantiation time, and one static instance of A class B { let stringProperty: String let intProperty: Int = Int(arc4random_uniform(10)) let objectProperty: A = A() init(_ string: String) { self.stringProperty = string } // This will be used to demonstrate that we don't need to explicitly cast, if we only have one subscript method. subscript(_ ignoredIndex: Int) -> A { return self.objectProperty } } // This class acts as a façade class. It provides an interface to its contained classes as if they were direct subscripts. class C : Sequence { let aArray: [B] init() { self.aArray = [B("hut"),B("butt")] } // You can have multiple subscript() methods, differentiated by return type. subscript(_ index: Int) -> B { return self.aArray[index] } subscript(_ index: Int) -> String { return self.aArray[index].stringProperty } subscript(_ index: Int) -> UInt32 { return (self[index] as A).multiplier } subscript(_ index: Int) -> Int { return self.aArray[index].intProperty } subscript(_ index: Int) -> A { return self.aArray[index].objectProperty } // These are not simple data return subscripts. In fact, there are no Float properties, so that one is made from whole cloth. subscript(_ index: Int) -> Float { return Float(self.aArray[index].intProperty) * Float((self[index] as A).multiplier) } subscript(_ index: Int) -> [String] { var ret: [String] = [] let aInstance: B = self.aArray[index] ret = aInstance[0].poem // No need for explicit casting if we only have one subscript. ret[3] += self[index] + "." // This is allowed, as we know we're a String. return ret } // You can only have one makeIterator() method. func makeIterator() -> AnyIterator<[String]> { var nextIndex = 0 // Return a "bottom-up" iterator for the list. return AnyIterator() { if nextIndex == self.aArray.count { return nil } let ret: [String]! = self.aArray[nextIndex - 1].objectProperty.poem nextIndex += 1 return ret } } // You can have multiple methods with the same input signature, differentiated only by their output signature. func returnIndexedElement(_ atIndex: Int) -> Int { return self[atIndex] // Note no explicit casting is necessary, here. } func returnIndexedElement(_ atIndex: Int) -> UInt32 { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> A { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> B { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> Float { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> String { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> [String] { return self[atIndex] } } let mainObject = C() // First, let test the subscripts. // We have 3 elements, so let aObject1: A = mainObject[0] let aObject2: B = mainObject[0] let aString: String = mainObject[0] let aPoem: [String] = mainObject[0] let aInt: Int = mainObject[0] let aUInt32 = mainObject[0] as UInt32 let aFloat = mainObject[0] as Float // This will not work. You need to specify the type explicitly when using multiple subscripts, differentiated only by return type. // let failObject = mainObject[0] // However, this will work, because the class has only one subscript method defined. let aObject2_Subscript = aObject2[0] let aObject2_Poem = aObject2_Subscript.poem // Next, test the accessor methods. let bObject1: A = mainObject.returnIndexedElement(1) let bObject2: B = mainObject.returnIndexedElement(1) let bString: String = mainObject.returnIndexedElement(1) let bPoem: [String] = mainObject.returnIndexedElement(1) let bInt: Int = mainObject.returnIndexedElement(1) let bUInt32 = mainObject.returnIndexedElement(1) as UInt32 let bFloat = mainObject.returnIndexedElement(1) as Float // This will not work. You need to specify the type explicitly when using multiple methods, differentiated only by return type. // let failObject = mainObject.returnIndexedElement(1) 
0
source

All Articles