Implement an Equatable Void (None) type
Trying again in Swift 2.0, it seems that Void can be initialized as Void()
:
public enum Result<T, Error: ErrorType> {
case Success(T)
case Failure(Error)
var value: T? {
switch self {
case .Success(let v):
return v
case .Failure(_):
return nil
}
}
/// Constructs a success wrapping a `value`.
public init(value: T) {
self = .Success(value)
}
/// Constructs a failure wrapping an `error`.
public init(error: Error) {
self = .Failure(error)
}
}
enum MyError: ErrorType {
case AnError
}
let result = Result<Void, MyError>(value: Void())
let success = result.value != nil // returns true
let error = result.value == nil // returns false
Equatable alternatives for Void in Swift
I get an error during compilation:
FooBarBaz
does not conform to protocolEquatable
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
How do I define equality for a generic ResultT type?
I don't think that is possible at present. Void
is the type of the
empty tuple ()
, and tuples cannot adopt protocols (a discussion about
that topic starts at [swift-evolution] Synthesizing Equatable, Hashable, and Comparable for tuple types).
A possible workaround (as suggested by @Hamish above) is to use a custom
type instead of Void
:
struct Unit: Equatable {
static var unit = Unit()
public static func ==(lhs: Unit, rhs: Unit) -> Bool {
return true
}
}
let res = Result.success(Unit.unit)
I initially though that once SE-0143 Conditional conformances is implemented then one could define
public enum Result<T> {
case success(T)
case error
}
public extension Result: Equatable where T: Equatable {
public static func ==(lhs: Result, rhs: Result) -> Bool {
// ...
}
}
public extension Result: Equatable where T == Void {
public static func ==(lhs: Result, rhs: Result) -> Bool {
return true
}
}
without the need the make Void
itself Equatable
.
However (again attribution goes to @Hamish) this won't work
because multiple conformances won't be permitted.
Swift Struct doesn't conform to protocol Equatable?
OK, after lots of searching, it's working...
struct MyStruct {
var id: Int
var value: String
init(id: Int, value: String) {
self.id = id
self.value = value
}
var description: String {
return "blablabla"
}
}
extension MyStruct: Equatable {}
func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
let areEqual = lhs.id == rhs.id &&
lhs.value == rhs.value
return areEqual
}
My Struct was in a class, so it didn't work.. I moved this Struct out of my class and now it's good :)
Flutter: Equatable props getter with optional parameter
The base Equatable.props
getter is declared to return a List<Object?>
, not List<Object>
. Fixing your override to match would allow you to store null
.
using Equatable class with flutter_bloc
For comparison of data, we required Equatable
. it overrides ==
and hashCode
internally, which saves a lot of boilerplate code. In Bloc
, we have to extend Equatable
to States and Events
classes to use this functionality.
abstract class LoginStates extends Equatable{}
So, that means LoginStates
will not make duplicate calls and will not going to rebuild the widget if the same state occurs.
Define State:
class LoginInitialState extends LoginStates {}
Define State with props:
props
declared when we want State
to be compared against the values which declared inside props List
class LoginData extends LoginStates {
final bool status;
final String userName;
const LoginData({this.status, this.userName});
@override
List<Object> get props => [this.status, this.userName];
}
If we remove the username from the list and keep a list like [this.status]
, then State
will only consider the status
field, avoiding the username
field. That is why we used props for handling State changes.
Bloc Stream Usage:
As we extending State with Equatable
that makes a comparison of old state data with new state data. As an example let's look at the below example here LoginData will build a widget only once, which will avoid the second call as it is duplicated.
@override
Stream<LoginStates> mapEventToState(MyEvent event) async* {
yield LoginData(true, 'Hello User');
yield LoginData(true, 'Hello User'); // This will be avoided
}
Detail Blog: https://medium.com/flutterworld/flutter-equatable-its-use-inside-bloc-7d14f3b5479b
Java: How to workaround the lack of Equatable interface?
Consider wrapping your foreign class inside your own instead.
public class Foreign {
// undesired equals() and hashCode() implementation
}
public class ForeignWrapper {
private Foreign foreign;
public ForeignWrapper(Foreign foreign) {
this.foreign = foreign;
}
public void equals() {
// your equals implementation, using fields from foreign
}
public int hashCode() {
// your hashCode implementation, using fields from foreign
}
}
Then add new ForeignWrapper(foreign)
to the standard HashSet / HashMap. Not applicable in all situations, but maybe in yours.
Why Swift Tuples can be compared only when the number of elements is less than or equal to 6?
Background: Tuples aren't Equatable
Swift's tuples aren't Equatable
, and they actually can't be (for now). It's impossible to write something like:
extension (T1, T2): Equatable { // Invalid
// ...
}
This is because Swift's tuples are structural types: Their identity is derived from their structure. Your (Int, String)
is the same as my (Int, String)
.
You can contrast this from nominal types, whose identity is solely based off their name (well, and the name of the module that defines them), and whose structure is irrelevant. An enum E1 { case a, b }
is different from an enum E2 { case a, b }
, despite being structurally equivalent.
In Swift, only nominal types can conform to protocols (like Equatble
), which precludes tuples from being able to participate.
...but ==
operators exist
Despite this, ==
operators for comparing tuples are provided by the standard library. (But remember, since there is still no conformance to Equatable
, you can't pass a tuple to a function where an Equatable type is expected, e.g. func f<T: Equatable>(input: T)
.)
One ==
operator has to be manually be defined for every tuple arity, like:
public func == <A: Equatable, B: Equatable, >(lhs: (A,B ), rhs: (A,B )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, >(lhs: (A,B,C ), rhs: (A,B,C )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, >(lhs: (A,B,C,D ), rhs: (A,B,C,D )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable, >(lhs: (A,B,C,D,E ), rhs: (A,B,C,D,E )) -> Bool { ... }
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable, F: Equatable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool { ... }
Of course, this would be really tedious to write-out by hand. Instead, it's written using GYB ("Generate your Boilerplate"), a light-weight Python templating tool. It allows the library authors to implement ==
using just:
% for arity in range(2,7):
% typeParams = [chr(ord("A") + i) for i in range(arity)]
% tupleT = "({})".format(",".join(typeParams))
% equatableTypeParams = ", ".join(["{}: Equatable".format(c) for c in typeParams])
// ...
@inlinable // trivial-implementation
public func == <${equatableTypeParams}>(lhs: ${tupleT}, rhs: ${tupleT}) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
${", ".join("lhs.{}".format(i) for i in range(1, arity))}
) == (
${", ".join("rhs.{}".format(i) for i in range(1, arity))}
)
}
Which then gets expanded out by GYB to:
@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable>(lhs: (A,B), rhs: (A,B)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1
) == (
rhs.1
)
}
@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable>(lhs: (A,B,C), rhs: (A,B,C)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2
) == (
rhs.1, rhs.2
)
}
@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable>(lhs: (A,B,C,D), rhs: (A,B,C,D)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2, lhs.3
) == (
rhs.1, rhs.2, rhs.3
)
}
@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable>(lhs: (A,B,C,D,E), rhs: (A,B,C,D,E)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2, lhs.3, lhs.4
) == (
rhs.1, rhs.2, rhs.3, rhs.4
)
}
@inlinable // trivial-implementation
public func == <A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable, F: Equatable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool {
guard lhs.0 == rhs.0 else { return false }
/*tail*/ return (
lhs.1, lhs.2, lhs.3, lhs.4, lhs.5
) == (
rhs.1, rhs.2, rhs.3, rhs.4, rhs.5
)
}
Even though they automated this boilerplate and could theoretically change for arity in range(2,7):
to for arity in range(2,999):
, there is still a cost: All of these implementations have to be compiled and produce machine code that ends up bloating the standard library. Thus, there's still a need for a cutoff. The library authors chose 6, though I don't know how they settled on that number in particular.
Future
There's two ways this might improve in the future:
There is a Swift Evolution pitch (not yet implemented, so there's no official proposal yet) to introduce Variadic generics, which explicitly mentions this as one of the motivating examples:
Finally, tuples have always held a special place in the Swift language, but working with arbitrary tuples remains a challenge today. In particular, there is no way to extend tuples, and so clients like the Swift Standard Library must take a similarly boilerplate-heavy approach and define special overloads at each arity for the comparison operators. There, the Standard Library chooses to artificially limit its overload set to tuples of length between 2 and 7, with each additional overload placing ever more strain on the type checker. Of particular note: This proposal lays the ground work for non-nominal conformances, but syntax for such conformances are out of scope.
This proposed language feature would allow one to write:
public func == <T...>(lhs: T..., rhs: T...) where T: Equatable -> Bool {
for (l, r) in zip(lhs, rhs) {
guard l == r else { return false }
}
return true
}Which would be a general-purpose
==
operator that can handle tuples or any arity.There is also interest in potentially supporting non-nominal conformances, allowing structural types like Tuples to conform to protocols (like
Equatable
).That would allow one to something like:
extension<T...> (T...): Equatable where T: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
for (l, r) in zip(lhs, rhs) {
guard l == r else { return false }
}
return true
}
}
Filtering array of functions Swift
Non-Nominal Types cannot be filtered. This is because they are not equatable:
i.e. Here are some Non-Nominal Types
Any
Tuples
- soon to be equatableVoid aka () aka Empty Tuple
Functions aka () -> ()
What you could do is create a struct like so:
struct Method: Hashable, Equatable {
var name: String
var method: () -> () // or whatever type you want
init(_ n: String,_ m: @escaping () -> ()) {
name = n
method = m
}
// Equatable
static func == (lhs: Method, rhs: Method) -> Bool {
return lhs.name == rhs.name
}
// Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(name)
}
}
So that the name
is what checks if methods are equal. But so much for structs
.
If you wanted, you could make a similar class
instead to keep track of the reference.
Example code:
func function1() {print("foo")}
func function2() {print("bar")}
var array: [Method] = []
array.append(Method("One", function1))
array.append(Method("Two", function2))
let function: Method
function = Method("One", function1)
var filteredArray: [Method] = []
filteredArray = array.filter { $0 != function}
print(filteredArray.count) // 1
filteredArray.first?.method() // prints "bar"
Related Topics
How Does Swift Disambiguate Type Arguments in Expression Contexts
Covert Realm List to Realm Result
Problem with Frameworks in Command Line Tool
Swift Set UIbutton Setbordercolor in Storyboard
Implementing Undo and Redo in a UItextview with Attributedtext
Shortest Code to Create an Array of Random Numbers in Swift
How to Use This Fetchrequest() in Swift
Occasional Blank Frames After Exporting Asset - Avexportsession
Uibutton Background Color Overlaps Text on Highlight
How to Refer to a Global Type from Within a Class That Has a Nested Type with The Same Name
Arkit/Scenekit on iOS 14 Throws New Warning (Metal)
Why Swift Disallows Weak Reference for Non-Optional Type
#If Canimport(Coreimage) Not Working in Swift Package Manager
I Opened My App in Xcode 10 and Now I Have Errors in 9.4.1: Sdkapplicationdelegate (Facebookcore)
Weird Toolbar with Nested Conditionals Behavior