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.
Related
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 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()
}
I'm new to Swift and was trying to write a private enum that conforms Equatable. Here is a simplified representation of my code:
class Baz {
/* Other members in class Baz */
private enum Test: Equatable {
case Foo
case Bar
}
private func == (lhs: Test, rhs: Test) -> Bool {
//comparison
}
}
On the line of the "==" method, the compiler is complaining "Operators are only allowed at global scope". And when I change enum Test and "==" method to public then move the "==" out of the class, then the errors go away.
My question is what is the correct way to implement the "==" method for a private enum?
Any help is appreciated.
========
Edit:
Thanks all for helping me out. I didn't specify that my private enum and function above are in a class.. (Code is updated)
While perhaps not immediately useful for you, it's worth noting that as of beta 5, in Swift 3 you can make this a static func within the type. See the Xcode 8 Beta Release Notes, which says
Operators can be defined within types or extensions thereof. For example:
struct Foo: Equatable {
let value: Int
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.value == rhs.value
}
}
Such operators must be declared as static (or, within a class, class final), and have the same signature as their global counterparts.
This works with enum types, too. Thus:
private enum Test: Equatable {
case foo
case bar
static func ==(lhs: Test, rhs: Test) -> Bool {
// your test here
}
}
And this even works when this Test is implemented within another type.
I tried in a Playground and it works for me:
private enum Test: Equatable {
case Foo
case Bar
}
private func ==(lhs: Test, rhs: Test) -> Bool {
return true
}
class A {
func aFunc() {
let test: Test = .Foo
let test2: Test = .Foo
if (test == test2) {
print("Hello world")
}
}
}
let a = A()
a.aFunc() // Hello world
Can you edit your question with your code? So I can edit my answer to suit your problem.
There's nothing wrong with what you did:
private enum Test: Equatable {
case Foo
case Bar
}
private func ==(lhs: Test, rhs: Test) -> Bool {
// Put logic here
}
private let test = Test.Foo
private let test2 = Test.Foo
if (test == test2) {
print("Hello world")
}
See this article for details.
I created a class which is meant to be used as an "abstract class" (only to be subclassed, not instantiated directly). Since Swift doesn't support this, is has to be emulated using e.g. fatalError in body of abstract method.
My abstract class has to be equatable. So I thought, I use fatalError in equals method:
class MySuperClass:Equatable {
}
func ==(lhs: MySuperClass, rhs: MySuperClass) -> Bool {
fatalError("Must override")
}
class MySubClass:MySuperClass {
let id:Int
init(_ id:Int) {
self.id = id
}
}
func ==(lhs: MySubClass, rhs: MySubClass) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass(1)
let b = MySubClass(2)
let c = MySubClass(2)
a == b
b == c
And this works. I have the little problem though that my subclass has a type parameter. Now the example looks like this:
class MySuperClass:Equatable {
}
func ==(lhs: MySuperClass, rhs: MySuperClass) -> Bool {
fatalError("Must override")
}
class MySubClass<T>:MySuperClass {
let id:Int
init(_ id:Int) {
self.id = id
}
}
func ==<T>(lhs: MySubClass<T>, rhs: MySubClass<T>) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
a == b
b == c
And now it crashes, because it doesn't "see" the overriding equals, and it executes only equals in the superclass.
I know Swift has some issues concerning overrides using generic types. I thought though that this was limited to interaction with obj-c. This looks at least like a language deficiency, or bug, why would equals of generic class B not override equals of class A, if B is a subclass of A?
As Airspeed suggests the problem is that operator's implementation is not a part of class/struct implementation => hence, inheritance does not work there.
What you can do is to keep the logic inside of the class implementation and make operators use it. E.g. the following will do what you need:
class MySuperClass: Equatable {
func isEqualTo(anotherSuperClass: MySuperClass) -> Bool {
fatalError("Must override")
}
}
func == (lhs: MySuperClass, rhs: MySuperClass) -> Bool {
return lhs.isEqualTo(rhs)
}
class MySubClass<T>:MySuperClass {
let id: Int
init(_ id: Int) {
self.id = id
}
override func isEqualTo(anotherSuperClass: MySuperClass) -> Bool {
if let anotherSubClass = anotherSuperClass as? MySubClass<T> {
return self.id == anotherSubClass.id
}
return super.isEqualTo(anotherSuperClass) // Updated after AirSpeed remark
}
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
a == b
b == c
... as you can see == operator is defined only once and it uses MySuperClass's method to figure out whether its two arguments are equal. And after that .isEqualTo() handles the rest, including the use of inheritance mechanism on MySubClass level.
UPD
The benefit of above approach is that the following will still work:
let a2: MySuperClass = a
let b2: MySuperClass = b
let c2: MySuperClass = c
a2 == b2
b2 == c2
... i.e. regardless of the variable type at compile-time the behaviour will be determined by the actual instance type.
In overloading resolution, non-generic functions always have priority over generic ones, so the lesser rule that functions taking subclasses precede ones taking superclasses isn't taken into account.
A possible solution is to make the superclass == generic too. That way the rules for choosing between two generic functions kick in, and in this case the more specific one is the one taking specific classes parameterized by T:
func ==<T: MySuperClass>(lhs: T, rhs: T) -> Bool {
// bear in mind, this is a question of compile-time overloading,
// rather than overriding
fatalError("Must override")
}
func ==<T>(lhs: MySubClass<T>, rhs: MySubClass<T>) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
// no longer asserts
a == b
b == c
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
}
}
}