Generic Swift Function Error Swift 3.0 - swift

func multiply<T: Strideable> (lhs: T, rhs: T) -> T {
return lhs * rhs
}
Why is this returning an error of:
No '*' candidates produce the expected contextual result result type 'T'

Found a work around by extending the * operator to the Double, Int, and Float types.
protocol Numeric {
func *(lhs: Self, rhs: Self) -> Self
}
extension Double: Numeric {}
extension Float: Numeric {}
extension Int: Numeric {}

Look into Strideable protocol, it does not have method ''. If you rather want it so that 'T' can be multiplied to another 'T', you should rather declare it in such a way that 'T' has ''.
func multiply<T: Strideable> (lhs: T, rhs: T) -> T where T:IntegerArithmetic {
return lhs * rhs
}
Or, you can also do as other answer suggests, since with this method you can only use Integers.

Related

Swift - How to write generic max function

I'm new to Swift and I want to write a generic max function which compares the two parameter and returns the larger one, for basic types like Int, Double, etc.
func max<T>(_ num1:T, _ num2:T) -> T {
return (num1 > num2) ? num1 : num2;
}
But I found this does't work, reported that Binary operation '>' cannot be applied to two 'T' operand.
I saw an example about generic add function Here
protocol Summable { static func +(lhs: Self, rhs: Self) -> Self }
extension Int: Summable {}
extension Double: Summable {}
func add<T: Summable>(x: T, y: T) -> T {
return x + y
}
So I think I should have a protocol for my max function, too. So this is my attempt:
protocol Comparable {
static func >(lhs: Self, rhs: Self) -> Self
}
extension Int:Comparable {}
extension Double:Comparable {}
But this doesn't work. I know there is a provided Comparable protocol from Swift, but I want to try it myself. Could you please help?
protocol TempComparable {
static func >(lhs:Self, rhs:Self) -> Bool;
}
func max<T:TempComparable>(_ num1:T, _ num2:T) -> T {
return (num1 > num2) ? num1 : num2;
}
What you need is to create your protocol as the sub-protocol of Comparable and provide a unique name instead of naming it same as an existing Type which causes confusion. And implement the protocol requirements in the extension of your protocol and conform the required types to the protocol. Here's how:
protocol CustomComparable: Comparable {
static func > (lhs: Self, rhs: Self) -> Self
}
extension CustomComparable {
static func > (lhs: Self, rhs: Self) -> Self {
lhs > rhs ? lhs : rhs
}
}
extension Int: CustomComparable {}
extension Double: CustomComparable {}

Overriding / operator for Optionals using generics results in endless loop

lets take a look at the following code snippet:
func / <T>(lhs: T?,rhs: T?) throws -> T? {
switch (lhs,rhs) {
case let (l?,r?):
return try l/r
default:
return nil
}
}
let x : Double? = 2
let y : Double? = 2
let z = try! x/y
I created a generic function that expects two optional parameters. If I run this code it leads to an endless loop because try l/r uses func / <T>(lhs: T?,rhs: T?) to divide the values. Can anyone explain why dividing two none optional double values results in a function call to the method I wrote and not the default / operator definition for Double?
If I extend Double by an extension that requires a static / operator for that class everything works like a charm:
protocol Dividable {
static func /(lhs: Self, rhs: Self) -> Self
}
extension Double: Dividable {}
func / <T:Dividable>(lhs: T?,rhs: T?) throws -> T? {
switch (lhs,rhs) {
case let (l?,r?):
return l/r
default:
return nil
}
}
let x : Double? = 2
let y : Double? = 2
let z = try! x/y
The binary arithmetic for e.g. Double is not implemented using concrete Double types, but rather as default generic implementations for types conforming to FloatingPoint:
swift/stdlib/public/core/FloatingPoint.swift.gyb
Within the block of your custom / function, the compiler does not know that the typeholder T conforms to FloatingPoint, and the overload resolution of l/r will resolve to the method itself (since the FloatingPoint implementions, while being more specific, are not accessible to the more general non-constrained type T in your custom implementation).
You could workaround this by adding FloatingPoint as a type constraint also to your own custom method:
func /<T: FloatingPoint>(lhs: T?, rhs: T?) throws -> T? {
switch (lhs, rhs) {
case let (l?, r?):
return try l/r
default:
return nil
}
}
Likewise, the binary arithmetic for integer types are implemented as default generic implementations constrained to types conforming to the internal protocol _IntegerArithmetic, to which the public protocol IntegerArithmetic conforms.
swift/stdlib/public/core/IntegerArithmetic.swift.gyb
You can use the latter public protocol to implement an overload of your custom operator function for integer types.
func /<T: IntegerArithmetic>(lhs: T?, rhs: T?) throws -> T? {
switch (lhs, rhs) {
case let (l?, r?):
return try l/r
default:
return nil
}
}
Finally, you might want to consider why you'd want this function to throw. N also ote that there are ways to simplify you implementations when dealing with exactly two optional values that you want to operate on only in case both differ from nil. E.g.:
func /<T: FloatingPoint>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { l in rhs.map{ l / $0 } }
}
func /<T: IntegerArithmetic>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { l in rhs.map{ l / $0 } }
}
Of, if you prefer semantics over brevity, wrap your switch statement in a single if statement
func /<T: FloatingPoint>(lhs: T?, rhs: T?) -> T? {
if case let (l?, r?) = (lhs, rhs) {
return l/r
}
return nil
}
func /<T: IntegerArithmetic>(lhs: T?, rhs: T?) -> T? {
if case let (l?, r?) = (lhs, rhs) {
return l/r
}
return nil
}
Your function signature doesn't let the compiler know anything about the type of lhs and rhs, other than that they're the same type. For example you could call your method like this:
let str1 = "Left string"
let str2 = "Right string"
let result = try? str1 / str2
This will result in an infinite loop because the only method that the compiler knows called / that takes in 2 parameters of the same type (in this case String) is the one that you've declared; return try l/r will call your func / <T>(lhs: T?,rhs: T?) throws -> T? method over and over again.
As you mentioned in your question, you will need a protocol that your parameters must conform to. Unfortunately there is no existing Number or Dividable protocol that would fit your needs, so you'll have to make your own.
Note that division will crash when the denominator is 0 and will not throw an error, so you should be able to remove the throws keyword from your function so that it is:
func / <T:Dividable>(lhs: T?, rhs: T?) -> T?
Edit to clarify further
If you think about what the compiler knows at that point I think it makes more sense. Once inside the function all the compiler knows is that lhs and rhs are of type T and optional. It doesn't know what T is, or any of its properties or functions, but only that they're both of type T. Once you unwrap the values you still only know that both are of type T and non-optional. Even though you know that T (in this instance) is a Double, it could be a String (as per my example above). This would require the compiler to iterate over every possible class and struct to find something that supports your method signature (in this case func / (lhs: Double, rhs: Double) -> Double), which it simply can't do (in a reasonable time), and would lead to unpredictable code. Imagine if you added this global method and then every time / was used on something existing (such as Float(10) / Float(5)) your method was called, that would get pretty messy and confusing pretty quickly.

Function with generic type

I have a function that can calculate the sum of numbers in array with condition like so:
func sumOfArrayWithCondition(array: [Int], filter: (element: Int) -> Bool) -> Int {
var result = 0
for i in 0..<array.count where filter(element: array[i]) {
result += array[i]
}
return result
}
Now I want it to work with Int, Float, Double type. I have tried, but didn't work.
protocol Addable {
func +(lhs: Self, rhs: Self) -> Self
}
extension Int: Addable {}
extension Double: Addable {}
extension Float: Addable {}
func sumOfArrayWithCondition<T: Addable>(array: [T], filter: (element: T) -> Bool) -> T {
var result = 0
for i in 0..<array.count where filter(element: array[i]) {
result += array[i] // <-------- Error here
}
return result // <-------- Error here
}
But it says:
Binary operator '+=' cannot be applied to operands of type 'Int' and 'T'
So how to do it.
Any helps would be appreciated. Thanks.
First issue is that the compiler is inferring the type Int for the var result because you don't declare a type and initialize it with 0. But you need result to be of type T.
First, in order to initialize result as an instance of type T with the value 0, you need to specify that Addable is also IntegerLiteralConvertible, which is already true for Int, Double and Float. Then you can declare result as type T and go from there.
As Rob pointed out, you also need to add the += function to your protocol if you want to be able to use it.
So the final code that achieves what you are looking for is:
protocol Addable : IntegerLiteralConvertible {
func +(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int: Addable {}
extension Double: Addable {}
extension Float: Addable {}
func sumOfArrayWithCondition<T: Addable>(array: [T], filter: (element: T) -> Bool) -> T {
var result:T = 0
for i in 0..<array.count where filter(element: array[i]) {
result += array[i]
}
return result
}
As Rob said, result is an Int. But there's no need to create that method at all. You're wanting to call that like so, based on your method signature:
let sum = sumOfArrayWithCondition(myArray, filter: myFilter)
instead, all you have to do is use existing methods provided by swift:
let sum = myArray.filter(myFilter).reduce(0) { $0 + $1 }

Is it possible to define [Int] * Int using custom operator in Swift?

I want to define a new operator and multiply each element of the array [Int] by Int, such as [3, 2, 10] * 10.
However, because Int is neither protocol nor class (it's struct), I first defined the following:
protocol Numeric {}
extension Int: Numeric {}
extension Double: Numeric {}
extension Float: Numeric {}
And then, I tried defining the operator, like:
func *<T: Numeric> (left: [T], right: T) -> [T] {
var newArray: [T] = []
for i in left {
newArray.append(i * right)
}
return newArray
}
However, this spits out an error: Cannot convert value of type 'T' to expected argument type '[_]'.
I'm not sure what the type [_] means, which I don't expect, but I guess the problem comes from that I don't have an operator defined that takes T and T, both of which are Numeric in this case.
So I defined another operator, like:
func *<T: Numeric> (left: T, right: T) -> T {
return left * right
}
However, while this has been compiled without problems, the runtime error occurred with a lot of a lot of static * infix <A where ...> (A, A) -> A.
I'm not sure why this operator was executed so many times, but now I wonder if it is possible in the first place to define a custom * operator, although the Int does already have * operator defined.
So is it still possible to define [Int] * Int operator in Swift?
You have to require the multiplication operation in the Numeric
protocol:
protocol Numeric {
func *(lhs: Self, rhs: Self) -> Self
}
Otherwise the multiplication in newArray.append(i * right) is
not defined.
Your
func *<T: Numeric> (left: T, right: T) -> T {
return left * right
}
(which calls itself recursively, resulting in a stack overflow) is then not needed.
The implementation of your new operator itself can be simplified
(as already described in a now deleted answer) to
func *<T: Numeric> (left: [T], right: T) -> [T] {
return left.map { $0 * right }
}

Mathematical sign as function parameter

Can I somehow send the mathematical sign (+, -, *) as function parameters? I want to call reduce() function for different sign.
In swift signs are functions name for a specified mathematic operation. To pass sign as parameter the parameter type must be function that takes two numbers and return a number. If you command + click on any sign you will see its definition as follow :
public func +(lhs: UInt8, rhs: UInt8) -> UInt8
public func +(lhs: Int8, rhs: Int8) -> Int8
public func +(lhs: UInt16, rhs: UInt16) -> UInt16
public func +(lhs: Int16, rhs: Int16) -> Int16
public func +(lhs: UInt32, rhs: UInt32) -> UInt32
public func +(lhs: Int32, rhs: Int32) -> Int32
public func +(lhs: UInt64, rhs: UInt64) -> UInt64
public func +(lhs: Int64, rhs: Int64) -> Int64
public func +(lhs: UInt, rhs: UInt) -> UInt
public func +(lhs: Int, rhs: Int) -> Int
In your case your reduce function should look as the following one
func reduce(sign: (Int,Int)->Int) -> Int{
return sign(2,3)
}
reduce(*)
reduce(-)
func doSomeCalculation(_ fun:((Int, Int) -> Int)) -> Int {
return fun(12,13)
}
doSomeCalculation(+) // 25
doSomeCalculation(-) // -1
The same can be done for UInt, the IntXX, etc.
+ is basically simply a function that takes two arguments and returns the sum of it. Since functions are objects like any other you can pass them around as such.
The same way you can pass + into reduce.
Yes, you can send any binary operator to the reduce() function, providing the original value and the elements in the collection are of the same type, and thus the operator can be applied.
Think at operators as functions/closures and you'll understand why this is possible in Swift. In fact operators are just like functions - they are named closures.
Also think at the way new operators can be added - you define a function with the operator name that takes a number of parameters equal to the operator arity.
Thus, the following is syntactically correct, and provides the expected output (6):
[1,2,3].reduce(0, combine: +)
Send as a Character, then switch to identify:
func acceptASign(sign: Character) {
switch sign {
case "+":
//do some addition
case "-":
//do some subtraction
case "*":
//do some multiplication
case "/":
//do some division
default:
break;
}
}