Swift - How to write generic max function - swift

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 {}

Related

understanding protocol extensions in swift

I am trying to implement a basic protocol extension like so:
protocol Value {
func get() -> Float
mutating func set(to:Float)
}
extension Value {
static func min(of a:Value, and b:Value) -> Float {
if a < b { //Expression type 'Bool' is ambiguous without more context
return a.get()
}else{
return b.get()
}
}
static func < (a:Value, b:Value) -> Bool {
return a.get() < b.get()
}
}
At the if clause the compiler says:Expression type 'Bool' is ambiguous without more context. Why doesn't this work?
As touched on in this Q&A, there's a difference between operator overloads implemented as static members and operator overloads implemented as top-level functions. static members take an additional (implicit) self parameter, which the compiler needs to be able to infer.
So how is the value of self inferred? Well, it has to be done from either the operands or return type of the overload. For a protocol extension, this means one of those types needs to be Self. Bear in mind that you can't directly call an operator on a type (i.e you can't say (Self.<)(a, b)).
Consider the following example:
protocol Value {
func get() -> Float
}
extension Value {
static func < (a: Value, b: Value) -> Bool {
print("Being called on conforming type: \(self)")
return a.get() < b.get()
}
}
struct S : Value {
func get() -> Float { return 0 }
}
let value: Value = S()
print(value < value) // Ambiguous reference to member '<'
What's the value of self in the call to <? The compiler can't infer it (really I think it should error directly on the overload as it's un-callable). Bear in mind that self at static scope in a protocol extension must be a concrete conforming type; it can't just be Value.self (as static methods in protocol extensions are only available to call on concrete conforming types, not on the protocol type itself).
We can fix both the above example, and your example by defining the overload as a top-level function instead:
protocol Value {
func get() -> Float
}
func < (a: Value, b: Value) -> Bool {
return a.get() < b.get()
}
struct S : Value {
func get() -> Float { return 0 }
}
let value: Value = S()
print(value < value) // false
This works because now we don't need to infer a value for self.
We could have also given the compiler a way to infer the value of self, by making one or both of the parameters take Self:
protocol Value {
func get() -> Float
}
extension Value {
static func < (a: Self, b: Self) -> Bool {
print("Being called on conforming type: \(self)")
return a.get() < b.get()
}
}
struct S : Value {
func get() -> Float { return 0 }
}
let s = S()
print(s < s)
// Being called on conforming type: S
// false
The compiler can now infer self from the static type of operands. However, as said above, this needs to be a concrete type, so you can't deal with heterogenous Value operands (you could work with one operand taking a Value; but not both as then there'd be no way to infer self).
Although note that if you're providing a default implementation of <, you should probably also provide a default implementation of ==. Unless you have a good reason not to, I would also advise you make these overloads take homogenous concrete operands (i.e parameters of type Self), such that they can provide a default implementation for Comparable.
Also rather than having get() and set(to:) requirements, I would advise a settable property requirement instead:
// Not deriving from Comparable could be useful if you need to use the protocol as
// an actual type; however note that you won't be able to access Comparable stuff,
// such as the auto >, <=, >= overloads from a protocol extension.
protocol Value {
var floatValue: Double { get set }
}
extension Value {
static func == (lhs: Self, rhs: Self) -> Bool {
return lhs.floatValue == rhs.floatValue
}
static func < (lhs: Self, rhs: Self) -> Bool {
return lhs.floatValue < rhs.floatValue
}
}
Finally, if Comparable conformance is essential for conformance to Value, you should make it derive from Comparable:
protocol Value : Comparable {
var floatValue: Double { get set }
}
You shouldn't need a min(of:and:) function in either case, as when the conforming type conforms to Comparable, it can use the top-level min(_:_:) function.
You can't write
if a < b {
because a and b have type Value which is NOT Comparable.
However you can compare the float value associated to a and b
if a.get() < b.get() {
If you want to be able to make types that can use operators such as >, <, ==, etc., they have to conform to the Comparable protocol:
protocol Value: Comparable {
func get() -> Float
mutating func set(to: Float)
}
This comes with more restrictions though. You will have to change all the Value types in the protocol extension to Self:
extension Value {
static func min(of a: Self, and b: Self) -> Float {
if a < b { //Expression type 'Bool' is ambiguous without more context
return a.get()
}else{
return b.get()
}
}
static func < (a: Self, b: Self) -> Bool {
return a.get() < b.get()
}
}
The Self types get replaced with the type that implements the protocol. So if I implemented Value on a type Container, the methods signatures would look like this:
class Container: Value {
static func min(of a: Container, and b: Container) -> Float
static func < (a: Container, b: Container) -> Bool
}
As a side note, if you want Value to conform to Comparable, you might want to also add the == operator to the Value extension:
static func <(lhs: Self, rhs: Self) -> Bool {
return lhs.get() < rhs.get()
}

T.RawValue Comparable in Swift is a raw deal?

With Xcode 8.2.1 and Swift 3, if I show the protocol definition for the Error protocol I see this in the generated header:
public protocol Error { }
extension Error { }
// at line 1250:
public func <<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func ><T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func <=<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
public func >=<T where T.RawValue : Comparable>(lhs: T, rhs: T) -> Bool
My question is about the operators that appear immediately under the extension Error { }:
These operators appear to say that default implementations exist for types that have a RawValue subtype that is Comparable.
So I wrote some code in a playground to see if I could use these operators. Here's the first attempt:
struct S<RawValue> {
let v: RawValue
}
let s = S<Int>(v: 0)
let t = S<Int>(v: 1)
s < t // error: Binary operator '<' cannot be applied to two 'S<Int>' operands
In the S struct above, we have a RawValue subtype, and when instantiated as shown in variables s and t as Int the RawValue is comparable. Yet < fails.
Here is attempt #2:
enum E: RawRepresentable {
case value(Int)
init(rawValue: Int) {
self = .value(rawValue)
}
var rawValue: Int {
switch self {
case .value(let rawValue):
return rawValue
}
}
}
let e = E.init(rawValue: 0)
let f = E.init(rawValue: 1)
e < f // error: Binary operator '<' cannot be applied to two 'E' operands
Again, we have a RawValue type that is Comparable, but no joy.
So I guess I'm missing something fundamental here. The Swift "Misc" header tells me that Comparable methods exist for T where T.RawValue: Comparable, but when I try to compare these sorts of Ts it doesn't work.
Any ideas?
Interesting. In Swift 3.1, those overloads show up in the generated header as:
public func <<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func ><T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func <=<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
public func >=<T>(lhs: T, rhs: T) -> Bool where T : _SwiftNewtypeWrapper, T.RawValue : Comparable
which makes a lot more sense, as without constraining T, there's no knowing that it has a RawValue. So it just looks like a visual error in the pre-Swift 3.1 generated header.
_SwiftNewtypeWrapper is a protocol, which according to its header, is:
/// An implementation detail used to implement support importing
/// (Objective-)C entities marked with the swift_newtype Clang
/// attribute.
public protocol _SwiftNewtypeWrapper : RawRepresentable { }
Therefore the overloads you see are used in order to define comparison operations on types that are bridged to Swift by being marked with the swift_newtype Clang attribute (for more info on this attribute, see this article), where their RawValue is Comparable.
For example, the following:
#import <Foundation/Foundation.h>
typedef NSString* _Nonnull Foo __attribute__((swift_newtype(enum)));
static const Foo FooBar = #"bar";
static const Foo FooBaz = #"baz";
static const Foo FooQux = #"qux";
gets bridged to Swift as:
public struct Foo : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
public init(rawValue: String)
public static let bar: Foo
public static let baz: Foo
public static let qux: Foo
}
and you are able to use the various comparison operators with instances of Foo:
func lessThan<T : _SwiftNewtypeWrapper>(lhs: T, rhs: T) -> Bool where T.RawValue : Comparable {
return lhs < rhs
}
let b = Foo.bar
print(lessThan(lhs: b, rhs: b))
(although there appears to be some rough edges around this, for example attempting to use them directly yields an 'ambiguous use of' compiler error)
However, for 'pure Swift' code, the overloads you've found should bare no relevance. Swift types that conform to RawRepresentable with Comparable RawValues don't automatically get < overloads or Comparable conformance – you have to implement that yourself.

Generic Swift Function Error Swift 3.0

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.

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 }

How can we create a generic Array Extension that sums Number types in Swift?

Swift lets you create an Array extension that sums Integer's with:
extension Array {
func sum() -> Int {
return self.map { $0 as Int }.reduce(0) { $0 + $1 }
}
}
Which can now be used to sum Int[] like:
[1,2,3].sum() //6
But how can we make a generic version that supports summing other Number types like Double[] as well?
[1.1,2.1,3.1].sum() //fails
This question is NOT how to sum numbers, but how to create a generic Array Extension to do it.
Getting Closer
This is the closest I've been able to get if it helps anyone get closer to the solution:
You can create a protocol that can fulfills what we need to do, i.e:
protocol Addable {
func +(lhs: Self, rhs: Self) -> Self
init()
}
Then extend each of the types we want to support that conforms to the above protocol:
extension Int : Addable {
}
extension Double : Addable {
}
And then add an extension with that constraint:
extension Array {
func sum<T : Addable>(min:T) -> T
{
return self.map { $0 as T }.reduce(min) { $0 + $1 }
}
}
Which can now be used against numbers that we've extended to support the protocol, i.e:
[1,2,3].sum(0) //6
[1.1,2.1,3.1].sum(0.0) //6.3
Unfortunately I haven't been able to get it working without having to supply an argument, i.e:
func sum<T : Addable>(x:T...) -> T?
{
return self.map { $0 as T }.reduce(T()) { $0 + $1 }
}
The modified method still works with 1 argument:
[1,2,3].sum(0) //6
But is unable to resolve the method when calling it with no arguments, i.e:
[1,2,3].sum() //Could not find member 'sum'
Adding Integer to the method signature also doesn't help method resolution:
func sum<T where T : Integer, T: Addable>() -> T?
{
return self.map { $0 as T }.reduce(T()) { $0 + $1 }
}
But hopefully this will help others come closer to the solution.
Some Progress
From #GabrielePetronella answer, it looks like we can call the above method if we explicitly specify the type on the call-site like:
let i:Int = [1,2,3].sum()
let d:Double = [1.1,2.2,3.3].sum()
As of Swift 2 it's possible to do this using protocol extensions. (See The Swift Programming Language: Protocols for more information).
First of all, the Addable protocol:
protocol Addable: IntegerLiteralConvertible {
func + (lhs: Self, rhs: Self) -> Self
}
extension Int : Addable {}
extension Double: Addable {}
// ...
Next, extend SequenceType to add sequences of Addable elements:
extension SequenceType where Generator.Element: Addable {
var sum: Generator.Element {
return reduce(0, combine: +)
}
}
Usage:
let ints = [0, 1, 2, 3]
print(ints.sum) // Prints: "6"
let doubles = [0.0, 1.0, 2.0, 3.0]
print(doubles.sum) // Prints: "6.0"
I think I found a reasonable way of doing it, borrowing some ideas from scalaz and starting from your proposed implementation.
Basically what we want is to have typeclasses that represents monoids.
In other words, we need:
an associative function
an identity value (i.e. a zero)
Here's a proposed solution, which works around the swift type system limitations
First of all, our friendly Addable typeclass
protocol Addable {
class func add(lhs: Self, _ rhs: Self) -> Self
class func zero() -> Self
}
Now let's make Int implement it.
extension Int: Addable {
static func add(lhs: Int, _ rhs: Int) -> Int {
return lhs + rhs
}
static func zero() -> Int {
return 0
}
}
So far so good. Now we have all the pieces we need to build a generic `sum function:
extension Array {
func sum<T : Addable>() -> T {
return self.map { $0 as T }.reduce(T.zero()) { T.add($0, $1) }
}
}
Let's test it
let result: Int = [1,2,3].sum() // 6, yay!
Due to limitations of the type system, you need to explicitly cast the result type, since the compiler is not able to figure by itself that Addable resolves to Int.
So you cannot just do:
let result = [1,2,3].sum()
I think it's a bearable drawback of this approach.
Of course, this is completely generic and it can be used on any class, for any kind of monoid.
The reason why I'm not using the default + operator, but I'm instead defining an add function, is that this allows any type to implement the Addable typeclass. If you use +, then a type which has no + operator defined, then you need to implement such operator in the global scope, which I kind of dislike.
Anyway, here's how it would work if you need for instance to make both Int and String 'multipliable', given that * is defined for Int but not for `String.
protocol Multipliable {
func *(lhs: Self, rhs: Self) -> Self
class func m_zero() -> Self
}
func *(lhs: String, rhs: String) -> String {
return rhs + lhs
}
extension String: Multipliable {
static func m_zero() -> String {
return ""
}
}
extension Int: Multipliable {
static func m_zero() -> Int {
return 1
}
}
extension Array {
func mult<T: Multipliable>() -> T {
return self.map { $0 as T }.reduce(T.m_zero()) { $0 * $1 }
}
}
let y: String = ["hello", " ", "world"].mult()
Now array of String can use the method mult to perform a reverse concatenation (just a silly example), and the implementation uses the * operator, newly defined for String, whereas Int keeps using its usual * operator and we only need to define a zero for the monoid.
For code cleanness, I much prefer having the whole typeclass implementation to live in the extension scope, but I guess it's a matter of taste.
In Swift 2, you can solve it like this:
Define the monoid for addition as protocol
protocol Addable {
init()
func +(lhs: Self, rhs: Self) -> Self
static var zero: Self { get }
}
extension Addable {
static var zero: Self { return Self() }
}
In addition to other solutions, this explicitly defines the zero element using the standard initializer.
Then declare Int and Double as Addable:
extension Int: Addable {}
extension Double: Addable {}
Now you can define a sum() method for all Arrays storing Addable elements:
extension Array where Element: Addable {
func sum() -> Element {
return self.reduce(Element.zero, combine: +)
}
}
Here's a silly implementation:
extension Array {
func sum(arr:Array<Int>) -> Int {
return arr.reduce(0, {(e1:Int, e2:Int) -> Int in return e1 + e2})
}
func sum(arr:Array<Double>) -> Double {
return arr.reduce(0, {(e1:Double, e2:Double) -> Double in return e1 + e2})
}
}
It's silly because you have to say arr.sum(arr). In other words, it isn't encapsulated; it's a "free" function sum that just happens to be hiding inside Array. Thus I failed to solve the problem you're really trying to solve.
3> [1,2,3].reduce(0, +)
$R2: Int = 6
4> [1.1,2.1,3.1].reduce(0, +)
$R3: Double = 6.3000000000000007
Map, Filter, Reduce and more
From my understanding of the swift grammar, a type identifier cannot be used with generic parameters, only a generic argument. Hence, the extension declaration can only be used with a concrete type.
It's doable based on prior answers in Swift 1.x with minimal effort:
import Foundation
protocol Addable {
func +(lhs: Self, rhs: Self) -> Self
init(_: Int)
init()
}
extension Int : Addable {}
extension Int8 : Addable {}
extension Int16 : Addable {}
extension Int32 : Addable {}
extension Int64 : Addable {}
extension UInt : Addable {}
extension UInt8 : Addable {}
extension UInt16 : Addable {}
extension UInt32 : Addable {}
extension UInt64 : Addable {}
extension Double : Addable {}
extension Float : Addable {}
extension Float80 : Addable {}
// NSNumber is a messy, fat class for ObjC to box non-NSObject values
// Bit is weird
extension Array {
func sum<T : Addable>(min: T = T(0)) -> T {
return map { $0 as! T }.reduce(min) { $0 + $1 }
}
}
And here: https://gist.github.com/46c1d4d1e9425f730b08
Swift 2, as used elsewhere, plans major improvements, including exception handling, promises and better generic metaprogramming.
Help for anyone else struggling to apply the extension to all Numeric values without it looking messy:
extension Numeric where Self: Comparable {
/// Limits a numerical value.
///
/// - Parameter range: The range the value is limited to be in.
/// - Returns: The numerical value clipped to the range.
func limit(to range: ClosedRange<Self>) -> Self {
if self < range.lowerBound {
return range.lowerBound
} else if self > range.upperBound {
return range.upperBound
} else {
return self
}
}
}