-
Notifications
You must be signed in to change notification settings - Fork 8
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
Add Comparison trait. #24
Conversation
loc: SourceLocation): Expectations = eql(expected, found) | ||
loc: SourceLocation): Expectations = eql(expected, found)(eqA, showA, loc) | ||
|
||
def diff[A]( |
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.
What do you think about adding a new function vs modifying the existing ones?
Adding a new function to the API (diff
or a different name) is the simplest approach to compatibility.
We could modify the signatures of the existing expect
and same
functions to replace Eq
and Show
with Comparison
, but it would be difficult to keep the same behaviour. They currently use default implicit parameters to infer the Show
and Eq
traits.
The closest we could get is:
object Comparison {
implicit def fromEqAndToString(
implicit val eq: Eq[A],
show[A]: Show[A] = Show.fromToString): Comparison[A] = ???
}
def eql[A](
expected: A,
found: A)(
implicit comparison: Comparison[A], // finds Comparison.fromEqAndToString
loc: SourceLocation): Expectations = ???
def same[A](
expected: A,
found: A)(
implicit comparison: Comparison[A] = Comparison.fromUniversalEqAndToString,
loc: SourceLocation): Expectations = ???
but same
wouldn't respect a custom Show
instance.
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.
Repeating the discord convo for posterity : I'm fine the suggestion, despite it breaking bincompat and behaviour on this.
import cats.Show | ||
import com.eed3si9n.expecty._ | ||
|
||
trait Comparison[A] { |
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.
This could potentially extend Eq
as a Comparison
instance does imply an Eq
instance (and should satisfy Eq
laws).
I'm not sure if the inheritance would play well with implicit searches.
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.
Interesting question.
I think Comparison
should not necessarily imply Eq
, because you could have comparisons that verify if an instance A
is contained in another A
and I think that'd be a legitimate use. However there could be a more refined EqComparison
that would imply Eq
. In that case, the MTL treatment of having the implication reified as a def eqInstance: Eq[A]
instead of OO-inheritance would probably be the right course of action, in order to avoid implicit search problems.
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.
That's an interesting case. In that vein, Comparison
is a general predicate that has a string representation on failure? It doesn't have any laws associated with it.
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.
In that vein, Comparison is a general predicate that has a string representation on failure? It doesn't have any laws associated with it.
I think so, yes
import com.eed3si9n.expecty._ | ||
|
||
trait Comparison[A] { | ||
def diff(expected: A, found: A): Option[String] |
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.
This result type could be more explicit, if we wanted:
sealed trait Result
object Result {
case object Success extends Result
case object Failure(diff: String) extends Result
}
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 that's a good idea. There should however be a couple builders in the companion object, for convenience :
def ???[A](f : (A, A) => Option[String]) : Comparison[A]
// and maybe :
def ???[A](f: PartialFunction[(A, A), String]) : Comparison[A]
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 went with instance
to align with Eq.
8d1568f
to
a20eed9
Compare
implicit eqA: Eq[A] = Eq.fromUniversalEquals[A], | ||
showA: Show[A] = Show.fromToString[A], | ||
loc: SourceLocation): Expectations = eql(expected, found) | ||
implicit loc: SourceLocation): Expectations = eql(expected, found)( |
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.
Mmm what if we still passed the comparison as an implicit parameter with the default ? Now that I think a bit more about it, the default instance was the main motivation for having a distinction in the previous version between same
and eql
, whilst still allowing for injectable behaviour. Retaining this property would be valuable I think
implicit comparisonA: Comparison[A] = Comparison.fromEq(Eq.fromUniversalEquals, Show.fromToString)
This PR adds a
Comparison
trait as referenced in #15 .It still needs docs and tests, but I want to discuss the API before moving on to them.