-
-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adopted ==
in favour of isEqual(to:)
#2730
Conversation
Moved `public func ==(_:_:) -> Bool` into type extensions as static functions to properly adopt the `Equatable` protocol. All instances of `isEqual(to:)` have been replaced with `==`, but the `isEqual(to:)` methods remain for compatibility with objective-c
Codecov Report
@@ Coverage Diff @@
## master #2730 +/- ##
==========================================
+ Coverage 19.64% 20.27% +0.63%
==========================================
Files 113 113
Lines 13792 13644 -148
==========================================
+ Hits 2709 2767 +58
+ Misses 11083 10877 -206
Continue to review full report at Codecov.
|
|
||
return lhs.isKind(of: type(of: rhs)) | ||
&& (lhs.data?.isEqual(rhs.data) ?? true) | ||
&& lhs.y == rhs.y |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems you replaced if fabs(lhs.x - rhs.x) > Double.ulpOfOne
with lhs.x == rhs.x
. Any support material? Want to be cautious about this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. The Swift core says it implements ==
for FloatingPoint
according to IEEE 754-2008. Unfortunately I can't quote this due to the nature of IEEE documents, but we should be fine using the built in ==
and not have to rely on ulpOfOne
.
} | ||
|
||
return lhs.isKind(of: type(of: rhs)) | ||
&& (lhs.data?.isEqual(rhs.data) ?? true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should be careful with this ?? true
. what if lhs.data
is nil
when rhs.data
is nil
, or rhs.data
is not nil
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will fix it now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thought, do we want to include the data
property in the equality test at all? I can see an argument for either side, but I think equality can omit data
. Testing identity (===
) will compare data
inherently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure why data is included here. But @danielgindi is missing :(
Why can't we just keep the old conditions like
&& lhs.data !== rhs.data
&& !lhs.data!.isEqual(rhs.data)
ideally data will not be nil, if it's nil we will get the exception, but the new code will cover it up by returning false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!==
shouldn't be used. Equality and identity are two different things. Also, my next step is to turn ChartDataEntry
into a struct which means it's impossible to to test identity.
The new condition I just added tests equality with data properly. I think for now, we should just accept that data
will be tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The final section of this API Doc explains the difference between equality and identity, and why identity should not be considered when implementing Equatable
. There is an argument to be made for the first check (if lhs === rhs { return true }
), because it allows a quick escape without having to check each parameter individually (though I still disagree with it. I'm curious to see the performance of that identity check vs simply checking the equality of the ivars).
In the example you gave with LineChartData
and BarChartData
, using ===
would return true
on those entries and using ==
would also return true
.
With data there are 5 possible scenarios
lhs, rhs
1. nil, nil
2. val1, nil
3. nil, val1
4. val1, val2
5. val1, val1
using lhs.data?.isEqual(rhs.data) ?? false
will provide the correct result in cases 2, 3, 4, and 5. In order to account for case 1, we must also check to see if they are both nil
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To address your other point, there are a few areas where Charts has some issues (e.g. large data sets, performance with real time data, some API oddities). It is also clearly not a Swift project. I understand the language has evolved quite a bit since it's original release, but there are some key areas (e.g. why do ChartData
and ChartDataSets
not conform to the appropriate Collection
and Equatable
protocols? Why is ChartDataEntry
[and ideally ChartData
and ChartDataSets
] a class and not a struct?) that could use enhancements to make it feel more like a Swift library.
I get the impression from the readme that this is supposed to be a community project. It's fine that the lead maintainer is away to be with their family. It's been a few months now without him though, so how long do we wait until we choose someone else to lead the project? Ideally more than one person so as to not fall in the same trap of having nobody qualified to make bigger decisions again? From reading responses to issues and PRs, it seems nobody currently reviewing them really has sufficient knowledge of Swift to make a decision on more fundamental changes to the framework (which will be required to handle larger datasets).
The frustrating part isn't that someone doesn't have time to look at a given PR, it's that even if they do nothing will happen. For example: this is a pretty simple PR that doesn't change the usage or performance of the framework, and is something that is required to make the framework "more Swifty" and (I can't say required) is a helpful step in making the framework be much more performant. With the exception of missing the case when both lhs.data
and rhs.data
are nil
, there is no reason for it not to be accepted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please allow me to find spare time to digest a little. You are giving too much information for me :) but that's good swift expert is helping us
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for your second reply, yes it's bothering us (me) that we all have work to do and not having time to track the swift evolution. It could be lazy or just too many family errands. I am currently the only active person reviewing issues and PRs. But I am not swift expert and for those swift specific improvements, I need to find a time sit down and digest first. If it's small changes, I could merge for sure. But for very big changes, especially that will remove the support to objc usage, this gonna take time.
You are welcome on board to help us. You can try gitter or send emails to @danielgindi. We need to find out a solution for how to embrace swift better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for the first point regards the code, sure we have if lhs === rhs { return true }
already, but ChartDatEntry
's data
is AnyObject?
first. Checking identify first will avoid checking equatable if they are not same class at first, right? If we don't use identity check, then we need to make sure equatable protocol works in any scenario
return true | ||
} | ||
return lhs.isKind(of: type(of: rhs)) | ||
&& (lhs.data?.isEqual(rhs.data) ?? true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after we come to agreement, this needs change too
The requested changes have been made... |
This change looks ok for me but i'd like to add this after swift 4 support is merge. Should be soon! |
@petester42 if lhs.data !== rhs.data here? My concern is in extreme cases different data class may be passed through, and they have the same entries... Like a BarData and LineData hold the same entries |
That wouldn't be true though right? |
My bad, |
@petester42 What are your thoughts on removing |
Depends on what the intent of the equality should be. The equality to me should be that the objects are the same. If there is need to compare only part of the object like x and y values then some compare function should exists like |
Can this be merged now that we've moved to swift 4? |
|
||
if !lhs.isKind(of: type(of: rhs)) | ||
// MARK: Equatable | ||
extension ChartDataEntry/*: Equatable*/ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is equatable commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because NSObject
adopts Equatable
and you can't declare conformance twice. When Obj-C support is dropped, then we will need to uncomment it.
{ | ||
if lhs === rhs | ||
// MARK: Equatable | ||
extension ChartDataEntryBase/*: Equatable*/ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is equatable commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because NSObject
adopts Equatable
and you can't declare conformance twice. When Obj-C support is dropped, then we will need to uncomment it.
{ | ||
if lhs === rhs | ||
// MARK: Equatable | ||
extension Highlight /*: Equatable*/ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is equatable commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because NSObject
adopts Equatable
and you can't declare conformance twice. When Obj-C support is dropped, then we will need to uncomment it.
@jjatie I still have issues with this. If tests could be added for this change that would be great since it would be fairly easy to add. |
@petester42 I'm not sure what tests you want exactly. I'll write one for the equality/inequality of the couple types that are now using |
According to [Apple](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID35) >Swift provides default implementations of the == and === operators and adopts the Equatable protocol for objects that derive from the NSObject class. The default implementation of the == operator invokes the isEqual: method, and the default implementation of the === operator checks pointer equality. You should not override the equality or identity operators for types imported from Objective-C.
@petester42 I have reverted back to According to Apple
It appears I made a horrible merge, bringing back things from before Swift 4 was adopted, so I will submit a new PR (#3002) |
can this be closed if you replaced with a new one? |
Moved
public func ==(_:_:) -> Bool
into type extensions as static functions to properly adopt theEquatable
protocol.All instances of
isEqual(to:)
have been replaced with==
, but theisEqual(to:)
methods remain for compatibility with objective-c