Open TomasMikula opened 9 years ago
Not currently. There is (or at least was) a difference in design philosophy between Spire (which encourages symbolic infix operators) and Algebird (which discourages them). I would be open to adding operators here if @johnynek and @avibryant want them.
Since Cats already add symbolic operators for Algebra type classes, would distributing symbolic operators in a separate JAR be an acceptable compromise?
@TomasMikula Sure -- I would be happy to add an algebra-syntax
module that provides this functionality. I think it's just a matter of waiting and seeing how the other stakeholders feel about the idea.
We can revisit this, but the goals have drifted a bit on what Algebra is.
I think it is kind of a reference implementation of modeling algebra with scala. It could also be the base for algebird and spire (but it seems progress is slow there), and if we dream, we can imagine algebra being scala.algebra and making it into the standard library.
The counter argument to the above is that such coupling causes a lot of binary compatibility issues. You have some core library that everyone depends on and now you need to be REALLY sure you don't break binary compatibility almost ever. Alternatively, you have adapter implicit methods that can wrap a Spire Monoid in an Algebra Monoid, etc...
Finally, alebra seems focused (in my mind) on building a strong base for abstraction. Spire seems to be (mostly) about high performance mathematics with scala, Algebird is (mostly) about modeling sketch/approximation algorithms algebraically (so they can be plugged in generally to scalding/spark/summingbird).
The binary compatibility keeps me up at night (literally sometimes) because we deal with a giant monorepo at Twitter and we see these kinds of pains a lot.
That said, +1 to algebra-syntax. No issues there.
Thanks for the comment. I'm having some trouble understanding what you are implying, though.
I think it is kind of a reference implementation of modeling algebra with scala. It could also be the base for algebird and spire (but it seems progress is slow there), and if we dream, we can imagine algebra being scala.algebra and making it into the standard library.
The counter argument to the above is that such coupling causes a lot of binary compatibility issues. You have some core library that everyone depends on and now you need to be REALLY sure you don't break binary compatibility almost ever.
Are you saying that in order to avoid binary compatibility issues, one option for Algebra's future is to stay just an experimental project / reference implementation and not base production code on it? That certainly takes the burden off of Algebra, but then what good is Algebra if it's not supposed to be used in production?
Finally, alebra seems focused (in my mind) on building a strong base for abstraction. Spire seems to be (mostly) about high performance mathematics with scala, Algebird is (mostly) about modeling sketch/approximation algorithms algebraically (so they can be plugged in generally to scalding/spark/summingbird).
Is this to say that striving for the ideal of having both abstraction and high performance is futile?
@TomasMikula Here's my 2¢:
algebra-core
is currently used in Cats. So I am already committed to using it in production, and it is intended to be useful.algebra-core
). Whether or not Algebird moves over remains to be seen, but at least Cats and Spire will be using these type classes.algebra-std
instances, at least not initially. This is to preserve the existing behavior for Spire users. It would be too much effort to try to shoehorn every one of Spire's instances into Algebra, so for now we aren't going to try. Similarly Spire would probably continue using its own syntax, at least initially.algebra-core
does a great job at this. We hadn't necessarily agreed on syncing up implementations.algebra-std
was written, originally, was as a reference implementation to help verify that our laws (i.e. algebra-laws
) were useful. The Rat
class there is definitely a toy, and not meant for production use. Please use spire.math.Rational
(or another type) instead! :smile: Does this makes sense? I think that in terms of libraries programming to an Algebra interface (algebra-core
), it is 100% production-ready. As far as using Algebra in a stand-alone way (without rolling your own syntax, instances, algorithms, etc) it is still immature (and making it mature may not be our primary goal).
just to be clear, I'm not saying algebra should not be used in production, what I am saying is that we really haven't solved the diamond dependency problem on the JVM, and it is particularly acute with core libraries. So, imagine a giant code base (10s of millions of lines), and you add a new core dependency to several projects (that previously had no common dependencies), now all of a sudden, you have made your satisfiability problem much harder since all downstream of this core have to be upgraded in lock-step.
All of that is not that relevant to people building smaller apps, or those outside of monorepos where their entire system does not have to be on the same version of code (PS: I'm not a huge monorepo fan for this issue of it wanting to swallow the world).
So, the anxiety situation I have is this: someone wants to use @travisbrown finagle + cats stuff. And it's great. And then, algebird depends on algebra. Now, at Twitter, we have to upgrade algebird + (finagle + cats) at the same time (in the same PR) if algebra has any binary incompatibilities. This problem becomes more and more compounded as algebra and cats get adopted.
This is kind of the same reason we are still on scala 2.10 (though big progress to moving towards 2.11), because we have to switch all of twitter at one go. The more core libraries we have with many dependencies, the more we see this problem.
All of the above is just anxiety. If I actually did a bit more work on this project, I would have already implemented the MIMA check, and we could just be SUPER conservative about ever breaking binary compatibility on algebra-core. Then we'd probably be okay, and algebird would feel safe basing off algebra. But at this point, algebird is kind of mission critical at Twitter, and we have to be careful about taking dependencies there.
Thank you @non and @johnynek, makes sense. For the record, I'm mostly interested in Algebra's type classes and laws, less so in the instances. (Btw, for law checking, I'm not very happy with Discipline, but that's for another conversation.)
@johnynek I am already over-subscribed, but I will totally try to get MiMA working for algebra. To some extent I think we can hopefully just freeze algebra-core
, and as long as that is the only dependency, things should be fine. But I hear you about dependency pain.
Regarding freezing algebra-core
, is there a chance to revisit the return type of Order#compare
and PartialOrder#partialCompare
being Int
and Double
, respectively. I assume this has to do with optimizing the Order[Int]
instance so that compare(a, b)
reduces to a simple a-b
, but otherwise seems like a slap in the face of type safety.
Ironically it's not safe to use a - b
with signed values, because 0 - Int.MinValue
would be Int.MinValue
, which has the wrong sign.
The rationale in Spire is that we want generic code to operate as efficiently as direct code, and the return type for the various compare
methods in Java/Scala is Int
(except for Float
and Double
, which are actually partial orderings anyway). It would be easy to create parallel methods that use compare
and partialCompare
but return some kind of ADT, but I would be very reluctant to refactor Order
and PartialOrder
in terms of those methods.
What about a value class wrapping the Int
and/or objects (LT
, EQ
, GT
) for pattern matching?
case class Cmp(raw: Int) extends AnyVal {
def isLt = raw < 0
def isLte = raw <= 0
def isEq = raw == 0
def isGte = raw >= 0
def isGt = raw > 0
}
object Cmp {
object LT {
def apply = Cmp(-1)
def unapply(x: Cmp): Boolean = x.isLt
}
object EQ {
def apply = Cmp(0)
def unapply(x: Cmp): Boolean = x.isEq
}
object GT {
def apply = Cmp(1)
def unapply(x: Cmp): Boolean = x.isGt
}
implicit def cmpEq: Eq[Cmp] = new Eq[Cmp] {
def eqv(x: Cmp, y: Cmp): Boolean = (x, y) match {
case (LT(), LT()) => true
case (EQ(), EQ()) => true
case (GT(), GT()) => true
case _ => false
}
}
}
Hi,
is there a plan to add symbolic infix operators as in Cats?