Equatable alternatives for Void in Swift - swift

I'm trying to add conditional Equatable conformance to a type say Box<T>, if T is Equatable. Since Swift.Void is not Equatable, Box<Void> is not Equatable.
struct Box<T> {
//...
}
extension Box: Equatable where T: Equatable {
}
I can define a new type like below as a solution:
public struct Empty: Equatable {
}
And then use Box<Empty> instead of Box<Void> and that would work. But, wondering if there any alternatives to introducing a new type.
Update:
I tried this but it doesn't work
struct Box<T> {
//...
}
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
extension Box where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
I get an error during compilation: FooBarBaz does not conform to protocol Equatable
enum FooBarBaz: Equatable {
case success(box: Box<Void>)
// case success(box: Box<Int>) compiles as expected.
}
Please note that I'm using Swift 4.1

I get an error during compilation: FooBarBaz does not conform to protocol Equatable
This half-answer focuses on explaining why the approach you've tried yourself will not (yet) work.
There is a limitation, currently, with conditional conformances, that will limit you from using this particular technique to achieve your goal. Citing SE-0143: Conditional conformances, implemented in Swift 4.1:
Multiple conformances
Swift already bans programs that attempt to make the same type conform
to the same protocol twice, e.g.:
...
This existing ban on multiple conformances is extended to conditional
conformances, including attempts to conform to the same protocol in
two different ways.
...
The section overlapping conformances describes some of the
complexities introduced by multiple conformances, to justify their
exclusion from this proposal. A follow-on proposal could introduce
support for multiple conformances, but should likely also cover
related features such as private conformances that are orthogonal to
conditional conformances.
Which wont allow us to construct multiple conditional conformances as e.g.:
struct Box<T> { }
extension Box: Equatable where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
// error: redundant conformance of 'Box<T>' to protocol 'Equatable'
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
On the other hand, if we look at your own example:
struct Box<T> { }
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
extension Box where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
// error: type 'Void' does not conform to protocol 'Equatable'
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>())
Swift accurately identifies that Box<Void> is not Equatable: the extension Box where T == Void will not mean that Box<Void> conforms to Equatable, as it does not leverage a conditional conformance of Box to Equatable when T is Void (it just provides a == method in case T is Void.
Conditional conformances express the notion that a generic type will
conform to a particular protocol only when its type arguments meet
certain requirements.
As a side note, the following example yields expected results:
struct Box<T> { }
extension Box: Equatable where T == () {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>()) // Box<()> is Equatable
whereas, peculiarly, replacing the conditional conformance of Box to Equatable if T == () with the typedef of (), namely Void, crashes the compiler:
struct Box<T> { }
extension Box: Equatable where T == Void {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return true
}
}
func foo<T: Equatable>(_ _: T) { print(T.self, "is Equatable") }
foo(Box<Void>()) // compiler crash
Assertion failed: (isActuallyCanonicalOrNull() && "Forming a CanType
out of a non-canonical type!"), function CanType,
file /Users/buildnode/jenkins/workspace/oss-swift-4.1-package-osx/swift/include/swift/AST/Type.h,
line 393.
...
Edit: apparently is a (now resolved) bug:
SR-7101: Compiler crash when implementing a protocol for an enum using generics

Related

Returning a nil from an optional generic extension

Here's something I'm playing with. The problem is that I have a container class that has a generic argument which defines the type returned from a closure. I want to add a function that is only available if they generic type is optional and have that function return a instance containing a nil.
Here's the code I'm currently playing with (which won't compile):
open class Result<T>: Resolvable {
private let valueFactory: () -> T
fileprivate init(valueFactory: #escaping () -> T) {
self.valueFactory = valueFactory
}
func resolve() -> T {
return valueFactory()
}
}
public protocol OptionalType {}
extension Optional: OptionalType {}
public extension Result where T: OptionalType {
public static var `nil`: Result<T> {
return Result<T> { nil } // error: expression type 'Result<T>' is ambiguous without more context
}
}
Which I'd like to use like this:
let x: Result<Int?> = .nil
XCTAssertNil(x.resolve())
Any idea how to make this work?
I don't think you can achieve this with a static property, however you can achieve it with a static function:
extension Result {
static func `nil`<U>() -> Result where T == U? {
return .init { nil }
}
}
let x: Result<Int?> = .nil()
Functions are way more powerful than properties when it comes to generics.
Update After some consideration, you can have the static property, you only need to add an associated type to OptionalType, so that you'd know what kind of optional to have for the generic argument:
protocol OptionalType {
associatedtype Wrapped
}
extension Optional: OptionalType { }
extension Result where T: OptionalType {
static var `nil`: Result<T.Wrapped?> {
return Result<T.Wrapped?> { nil }
}
}
let x: Result<Int?> = .nil
One small downside is that theoretically it enables any kind of type to add conformance to OptionalType.

Implementing a hash combiner in Swift

I'm extending a struct conform to Hashable. I'll use the DJB2 hash combiner to accomplish this.
To make it easy to write hash function for other things, I'd like to extend the Hashable protocol so that my hash function can be written like this:
extension MyStruct: Hashable {
public var hashValue: Int {
return property1.combineHash(with: property2).combineHash(with: property3)
}
}
But when I try to write the extension to Hashable that implements `combineHash(with:), like this:
extension Hashable {
func combineHash(with hashableOther:Hashable) -> Int {
let ownHash = self.hashValue
let otherHash = hashableOther.hashValue
return (ownHash << 5) &+ ownHash &+ otherHash
}
}
… then I get this compilation error:
/Users/benjohn/Code/Nice/nice/nice/CombineHash.swift:12:43: Protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
Is this something that Swift won't let me do, or am I just doing it wrong and getting an unhelpful error message?
Aside A comment from JAL links to a code review of a swift hash function that is also written by Martin who provides the accepted answer below! He mentions a different hash combiner in that discussion, which is based on one in the c++ boost library. The discussion really is worth reading. The alternative combiner has fewer collisions (on the data tested).
Use the method hash(into:) from the Apple Developer Documentation:
https://developer.apple.com/documentation/swift/hashable
struct GridPoint {
var x: Int
var y: Int
}
extension GridPoint: Hashable {
static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
func hash(into hasher: inout Hasher) {
hasher.combine(x)
hasher.combine(y)
}
}
You cannot define a parameter of type P if P
is a protocol which has Self or associated type requirements.
In this case it is the Equatable protocol from which Hashable
inherits, which has a Self requirement:
public static func ==(lhs: Self, rhs: Self) -> Bool
What you can do is to define a generic method instead:
extension Hashable {
func combineHash<T: Hashable>(with hashableOther: T) -> Int {
let ownHash = self.hashValue
let otherHash = hashableOther.hashValue
return (ownHash << 5) &+ ownHash &+ otherHash
}
}

Swift 2 Generic data structure not conforming to Equatable protocol

I am working on building a flexible data structure in Swift called Node that, by itself, is not tied to any type of content. However, the Payload data within the Node is declared as the following generic Element struct that conforms to the Equatable protocol:
public struct Element<T>: Equatable {
var data: T;
}
public func ==<T:Equatable>(lhs: Element<T>, rhs: Element<T>) -> Bool {
return lhs.data == rhs.data;
}
The constraint is that the Element has to be tied to an equatable class type. The problem I'm having is with the Node containing this Element. The Node would be used in a Dictionary, Array, or any other container type. Here is what I have:
public class Node: Equatable {
var payload: Element<AnyObject>
init(_data: Element<AnyObject>) {
self.payload = _data
}
}
public func ==(lhs: Node, rhs: Node) -> Bool {
return lhs.payload == rhs.payload;
}
Of course, I'm getting the error that AnyObject does not conform to Equatable. Is there any way to constrain the declaration of the payload to only Objects that are equatable? At this point, I don't know what kind of objects may be stored in the payload.
Also just realized I need to put a class check in the == function in Node to make sure the two Node payloads are compatible to be compared--don't need them to be.
Thoughts? Thank you!
In order to constrain payload to a type that is Equatable, you'll need Node to be a generic class so that it can pass along that constraint.
You can specify the constraint in your class declaration:
public class Node<T: Equatable>: Equatable {...}
And then when declaring your payload you can set its Element type to just T:
var payload: Element<T>
When testing the code, I had to also make the generic constraint, T, in Element conform to Equatable. Entire code for reference:
public struct Element<T: Equatable>: Equatable {
var data: T
}
public func ==<T:Equatable>(lhs: Element<T>, rhs: Element<T>) -> Bool {
return lhs.data == rhs.data
}
public class Node<T: Equatable>: Equatable {
var payload: Element<T>
init(_data: Element<T>) {
self.payload = _data
}
}
public func ==<T: Equatable>(lhs: Node<T>, rhs: Node<T>) -> Bool {
return lhs.payload == rhs.payload
}
This will produce the following results:
Node(_data: Element(data: 1)) == Node(_data: Element(data: 1)) // true
Node(_data: Element(data: 1)) == Node(_data: Element(data: 2)) // false

Extend existing (generic) swift class to be hashable

I have some class that i want to put into a dictionary however that class is does not conform to Hashable i cant use it as a key in a Swift dictionary. Since its a class it can be identified by its location in memory and im happy to use that its identifier, the type itself doesnt fall into the value semantics world anyway.
Therefore i declare an extension to make it so
extension SomeGenericType : Hashable {
public var hashValue: Int {
return unsafeAddressOf(self).hashValue
}
}
This seems ok, however Hashable inherhits from Equatable so i need to implement tha too, my first try:
public func ==(lhs: SomeGenericType, rhs: SomeGenericType) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
Errors with
"Reference to generic type 'SomeGenericType' requires arguments in <...>"
...fair enough so lets do that
public func ==<T : SomeGenericType >(lhs: T, rhs: T) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
Now it says
"Reference to generic type 'SomeGenericType' requires arguments in <...>"
Hmm so i can make this work for all SomeGenericType's regardless of what type it gets. Maybe we can just put AnyObject in there?
public func ==<T : SomeGenericType<AnyObject>>(lhs: T, rhs: T) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
Ok now == is happy but apparantly im not implementing Hashable properly as there is now a error on my hashable extension saying:
"Type 'SomeGenericType<T>' does not conform to protocol 'Equatable'"
Ive tried fiddling with a constrained Extension on SomeGenericType but i cant seem to make a constrained extension of a type adopt another protocol, the language grammar doesnt seem to allow it, so Im in a bit of pickle here
Edit, for reference SomeGenericType is defined as follows:
class SomeGenericType<T> {
}
The correct syntax is
public func ==<T>(lhs: SomeGenericType<T>, rhs: SomeGenericType<T>) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
The operands need to be instances of SomeGenericType for the
same type placeholder T.
For Swift 3, use ObjectIdentifier instead of unsafeAddressOf.
This is an older question but I recently run into a similar problem, except I had a struct.
You might want to implement 4 different infix operator functions:
// #1
public func ==<T>(lhs: SomeGenericType<T>, rhs: SomeGenericType<T>) -> Bool {
return lhs === rhs // it's a class right - check the reference
}
// #2
public func !=<T>(lhs: SomeGenericType<T>, rhs: SomeGenericType<T>) -> Bool {
return !(lhs === rhs)
}
// #3
public func ==<T, U>(lhs: SomeGenericType<T>, rhs: SomeGenericType<U>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
// #4
public func !=<T, U>(lhs: SomeGenericType<T>, rhs: SomeGenericType<U>) -> Bool {
return lhs.hashValue != rhs.hashValue
}
Problem solved? The program should use these and not the generic functions from the stdlib.
You could also check everything by it's hashValue. ;)

Type in conformance requirement does not refer to a generic parameter or associated type

In Swift 2 I have the following protocols
protocol Fightable {
// return true if still alive, false if died during fight
func fight (other: Fightable) -> Bool
}
protocol Stats {
var defense: Int { get }
var attack: Int { get }
}
I can implement a protocol extension for Fightable to provide a shared implementation of fight across all value types which conform to Stats if I change the type signature of fight to
func fight (other: Self) -> Bool
and implement an extension as
extension Fightable where Self : Stats {
func fight (other: Self) -> Bool {
return self.defense > other.attack
}
}
The problem with the above implementation is that it requires the value types to be the same (Humans can't fight Goblins). My current goal is to implement a protocol extension that provides a default implementation of fight for any combination of value types as long as they implement Stats.
The following code
extension Fightable where Fightable : Stats {
func fight (other: Fightable) -> Bool {
return self.defense > other.attack
}
}
Produces the error
Type 'Fightable' in conformance requirement does not refer to a generic parameter or associated type
How can I make sure the other Fightable type also conforms to Stats for this extension?
I'm using Xcode 7 beta 1.
I'm sorry but I misunderstood your problem. So if I understand you right (hopefully) it is impossible to get a default implementation of the fight function by a protocol extension (at least with these constraints). Because if you want other conform to Fightable and Stats it isn't the previous function anymore where other could be any Fightable. So it doesn't implement the required function.
As workaround I would suggest (taking your existing code):
protocol Fightable {
// return true if still alive, false if died during fight
func fight (other: Fightable) -> Bool
}
protocol Stats {
var defense: Int { get }
var attack: Int { get }
}
extension Fightable where Self : Stats {
// directly conforming to the protocol
func fight (other: Fightable) -> Bool {
if let otherStat = other as? Stats {
return self.defense > otherStat.attack
}
// providing a good way if other does not conform to Stats
return false
}
}
One way which work's for me is making a typealias in your Fightable protocol. So you can constraint the parameter of the fight function in your protocol extension. Due to this situation you also have to make your fight function generic (Fightable can than only be used as generic constraint).
In code it looks like this:
protocol Fightable {
// make typealias
typealias F = Fightable
// make function generic
func fight<F: Fightable>(other: F) -> Bool
}
protocol Stats {
var defense: Int { get }
var attack: Int { get }
}
// constraint F and Self
extension Fightable where F : Stats, Self: Stats {
func fight(other: F) -> Bool {
return self.defense > other.attack
}
}
// example of an implementation
struct Human: Fightable {
func fight<F: Fightable>(other: F) -> Bool {
return true
}
}