Can anybody explain please, what is going on here:
struct Test {
var value: Int
}
// -----------------------------------
protocol Test1: Equatable {
var value: Int { get set }
}
extension Test1 {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.value == rhs.value + 1
}
}
// -----------------------------------
protocol Test2: Equatable {
var value: Int { get set }
}
extension Test2 {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.value == rhs.value + 2
}
}
// -----------------------------------
extension Test: Test1 {}
extension Test: Test2 {}
let a = Test(value: 5)
let b = Test(value: 5)
print(a == b) // true, which is unexpected
If conforms only to Test1 or only to Test2 it works as expected.
Conforming to Test1 and Test2. At first I thought that the order will matter. But looks like it just cancels each other! Without any warnings. Which is very counterintuitive.
Note: Test conforms to Equatable not because of the two extensions you provided, but because of the auto-generated Equatable implementation. As you said, if there were only those two extensions, it would be ambiguous which == is the Equatable implementation.
Neither of the == in the Test1 or Test2 protocol extensions are called. Instead, the auto-generated Equatable implementation is called. As you may recall, a == operator is auto-generated for types whose properties are all Equatable, and is declared to conform to Equatable itself.
This is because members declared in extensions use static binding, so when there are multiple versions of the same member available, the version declared in the extension will only be chosen if the compile time type is the extension's type. For example:
protocol P { }
class C : P { func f() { print("C") } }
extension P { func f() { print("P") } }
C().f() // C
(C() as P).f() // P
In a == b, both a and b are Test, so none of the extension operators gets chosen. However, since Test1 and Test2 both use Self, you can only use them as generic constraints, and can't cast to them either. Therefore, I don't think you will be able to call the == declared in the extensions at all.
Anyway, if you want to see an error message saying that there are duplicate == operators available:
struct Test {
var value: Int
var x: Any? // now there is no auto-generated Equatable implementation!
}
error: type 'Test' does not conform to protocol 'Equatable' extension
Test: Test1 {} ^
note: candidate exactly matches
static func == (lhs: Self, rhs: Self) -> Bool {
^
note: candidate exactly matches
static func == (lhs: Self, rhs: Self) -> Bool {
^
If you remove one of the extensions, then Test conforms to Equatable because of the extension, as there is no more ambiguity. Therefore, the auto-generated implementation isn't auto-generated anymore, and there is only one == to choose from - the one declared in the extension.
class Test {
var count: Int;
init(count: Int) {
self.count = count;
}
}
extension Test: Comparable {
static func <(lhs: Test, rhs: Test) -> Bool {
return lhs.count > rhs.count
}
}
When I write this extension everything work okay but when i change < to > compiler error return
Type 'Test' does not conform to protocol 'Equatable'
Comparable extension required write < this function
What is this reason?
If you look at the docs for Comparable, you can see that it inherits from Equatable.
Equatable requires == to be implemented:
static func ==(lhs: Test, rhs: Test) -> Bool {
return lhs.count == rhs.count
}
I should also mention that count does not have an initial value. So you need to add an initializer for Test or a initial value to count.
EDIT:
If you look at the docs for Comparable, you'll find this bit:
Types with Comparable conformance implement the less-than operator (<)
and the equal-to operator (==). These two operations impose a strict
total order on the values of a type, in which exactly one of the
following must be true for any two values a and b:
a == b
a < b
b < a
So you must implement < and == but > is unnecessary. That's why it doesn't work when you only have >.
I just read Brent Simmon's post on a problem he is having with Swift and I thought I had the answer: generic protocol conformance.
The problem he's having is that he has a protocol, Value, that conforms to Equatable. He has another protocol, Smashable, that requires the function valueBySmashingOtherValue. He has a struct, Bar, that does in fact conform to Smashable and Value.
In a subsequent function that takes a generic type T, a Bar is returned. The Swift type system complains that 'Bar' is not convertible to 'T'.
Here's what I thought would work:
protocol Value: Equatable { }
protocol Smashable {
func valueBySmashingOtherValue<T: Value, Smashable>(value: T) -> T
}
struct Bar: Smashable, Value {
func valueBySmashingOtherValue<T: Value, Smashable>(value: T) -> T {
return value;
}
}
func ==(lhs: Bar, rhs: Bar) -> Bool {
return false
}
struct Foo {
func valueBySmashingOtherValue<T: Value, Smashable>(value: T) -> T {
return Bar()
}
}
Make the generic type T conform to Value and Smashable. Bar does in fact conform to these, so the type system should be fine with you returning it.
But it isn't. Why?
While it is true that Bar conforms to Value and Smashable it is not the only type that meets those criteria. I could create a new type (using latest Swift syntax):
struct NotBar: Smashable, Value {
func valueBySmashingOtherValue<T:Value where T:Smashable>(value: T) -> T {
return value;
}
}
func ==(lhs: NotBar, rhs: NotBar) -> Bool {
return true
}
If I passed an instance of NotBar into Foo.valueBySmashingOtherValue, then I would expect a NotBar in return. The compiler knows this so it does not allow you to return a Bar.
I implemented a helper to have an array of unowned references:
class Unowned<T: AnyObject>
{
unowned var value : T
init (value: T) { self.value = value }
func get() -> T { return self.value }
}
Now, it is possible to do [ Unowned<Foo> ]. However, I'm not satisfied with having the additional get() method to retrieve the underlying object. So, I wanted to write a custom binary operator, e.g. --> for being able to do
for unownedFoo in ArrayOfUnownedFoos
{
var bar : Int = unownedFoo-->method()
}
My current approach is to define
infix operator --> { }
func --><T> (inout lhs: Unowned<T>, inout rhs: () -> Int) -> Int
{
}
The idea I had behind this is:
lhs is obvisouly the object I get out of the array, on which I want to perform the call on
rhs is the method I desire to call. In this case method() would not take no parameters and return an Int, and therefore
The return value is int.
However, the following problems / uncertainties arise:
Is this the correct approach?
Are my assumptions above correct?
How can I call the provided closure rhs on the instance of the extracted Unowned<T>, e.g. (pseudocode) lhs.value.rhs(). If method() was static, I could do T.method(lhs.value), but then I would have to extract the name of the method somehow to make it more generic.
Maybe, a postfix operator is rather simple.
postfix operator * {}
postfix func *<T>(v:Unowned<T>) -> T {
return v.value
}
// Usage:
for unownedFoo in ArrayOfUnownedFoos {
var bar : Int = unownedFoo*.method()
}
Use something like:
func --> <T:AnyObject, V> (lhs: Unowned<T>, rhs: (T) -> V) -> V
{
return rhs (lhs.get())
}
and then use it as:
for unownedFoo in ArrayOfUnownedFoos
{
var bar : Int = unownedFoo-->{ (val:Int) in return 2*val }
}
Specifically, you don't want to use method() as that itself is a function call - which you probably don't want unless method() is actually returning a closure.
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
}
}
}