Reading Martin's book, chapter about equality Object equality chapter one may notice that properly implementing equals in scala (as actually in any other language) is not very straightforward. However scala is extremely powerful and agile, and I cannot believe it could not simplify things a bit. I know that scala generates proper equals for case classes, so I wonder why couldn't it generate simplifications for normal classes?
To show my point, I wrote an example of how would I see this should look like. It probably has flaws, and I had to use ClassTag which I know is very wrong for such basic thing as equals due to performance (any tip how could I do it without ClassTag?), but thinking that scala can generate proper equals for case classes, I'd say it should be able to generate proper code for normal classes, giving that developer provides the Key which should be used to compare objects.
trait Equality[T] extends Equals {
val ttag: ClassTag[T]
def Key: Seq[Any]
def canEqual(other: Any): Boolean = other match {
case that: Equality[_] if that.ttag == ttag => true
case _ => false
}
override def equals(other: Any): Boolean =
other match {
case that: Equality[T] => canEqual(that) && Key == that.Key
case _ => false
}
override def hashCode = Key.foldLeft(1)((x, y) => 41 * x + y.hashCode)
}
Then you can use it like this:
class Point(val x: Int, val y: Int)(implicit val ttag: ClassTag[Point]) extends Equality[Point]{
override def Key: Seq[Any] = Seq(x, y)
}
I'm not very much into ClassTags, so I might have made it wrong, but it seems to be working. Still that's not what I am asking - I want to know is there any serious reasons, why scala itself do not simplify implementing equality checks?
It is an interesting idea, and I can see from a comment that scalaz has something like this. I'm not sure I have a complete answer, but some factors to consider are:
Case classes are a bit unique in that you're not supposed to inherit from them. Assuming they're not sub-classed, canEqual isn't even required.
There's something elegant about the idea that even '+' in scala is a function not a 'language feature.' It's not necessarily better to have this as a language feature instead of a library (and there are a number of utilities even in Java to help with implementing hashcode/equals). The existing "equals" method isn't a language feature, it's just a method on the parent class Object, inherited from Java.
Scala does still need to play-nice with Java, and that could be one barrier to radically changing how equals works. Interface requirements can't be imposed on existing Java classes that scala might want to inherit from.
When you do consider what the syntax might look like if it were a language feature, I'm not sure what could actually be eliminated or changed.
For example, the developer still has to specify the Key you suggest. Also, to be able to support, for example, anonymous subclasses and trait mix-ins where canEqual won't change, with a language feature you'd still need to explicitly define your class tag.
Maybe the analysis could be more interesting if you provide what, syntactically, it might look like if it were a language feature instead of a helper library. I might be missing some aspects of how this would work.
There is no such thing "proper equals" since it depends on the use cases.
For simple cases what you suggest may work, but in such case, using case class with also work. The problem is that while for simple Data classes it works, the same isn't true for other cases. For example, when there are inheritance - what is the right thing to do? if class have private members - does it should be part of the equals?? does public getters should be ? What will happen when when there are cyclic dependencies ?
One of the main reasons for the case classes cannot be inherit by other case class is the equality.
Related
Is there really no simple idiomatic way of checking whether an object is a certain class, other than using .isInstanceOf[ClassName] or a full match expression?
A match for a single class may avoid the need for using .AsInstanceOf (when necessary for acting on class-unique members), but is very verbose in general and in requiring to explicitly cover for the default case...
Perhaps there would be some library for working with class hierarchies that simplifies assigning classes to objects and checking for them, to bypass the scala core class matcher limitations. I even considered implementing my own type assignment, hierarchies and checking solution, using plain collections, rather than using scala classes, for rich hierarchical type modeling that feels more idiomatic.
No, there is not. The syntax was deliberately made verbose because having to use this feature often indicates a bad design.
It is possible, however, to write a function yourself:
implicit class WithAs[T](x: T) {
import scala.reflect._
def as[O: ClassTag]: Option[O] = x match {
case o: O => Some(o)
case _ => None
}
}
live demo
We are pretty familiar with implicits in Scala for now, but macros are pretty undiscovered area (at least for me) and, despite the presence of some great articles by Eugene Burmako, it is still not an easy material to just dive in.
In this particular question I'd like to find out if there is a possibility to achieve the analogous to the following code functionality using just macros:
implicit class Nonsense(val s: String) {
def ##(i:Int) = s.charAt(i)
}
So "asd" ## 0 will return 'a', for example. Can I implement macros that use infix notation? The reason to this is I'm writing a DSL for some already existing project and implicits allow making the API clear and concise, but whenever I write a new implicit class, I feel like introducing a new speed-reducing factor. And yes, I do know about value classes and stuff, I just think it would be really great if my DSL transformed into the underlying library API calls during compilation rather than in runtime.
TL;DR: can I replace implicits with macros while not changing the API? Can I write macros in infix form? Is there something even more suitable for this case? Is the trouble worth it?
UPD. To those advocating the value classes: in my case I have a little more than just a simple wrapper - they are often stacked. For example, I have an implicit class that takes some parameters, returns a lambda wrapping this parameters (i.e. partial function), and the second implicit class that is made specifically for wrapping this type of functions. I can achieve something like this:
a --> x ==> b
where first class wraps a and adds --> method, and the second one wraps the return type of a --> x and defines ==>(b). Plus it may really be the case when user creates considerable amount of objects in this fashion. I just don't know if this will be efficient, so if you could tell me that value classes cover this case - I'd be really glad to know that.
Back in the day (2.10.0-RC1) I had trouble using implicit classes for macros (sorry, I don't recollect why exactly) but the solution was to use:
an implicit def macro to convert to a class
define the infix operator as a def macro in that class
So something like the following might work for you:
implicit def toNonsense(s:String): Nonsense = macro ...
...
class Nonsense(...){
...
def ##(...):... = macro ...
...
}
That was pretty painful to implement. That being said, macro have become easier to implement since.
If you want to check what I did, because I'm not sure that applies to what you want to do, refer to this excerpt of my code (non-idiomatic style).
I won't address the relevance of that here, as it's been commented by others.
This is purely a coding-style question.
A function I'm calling returns an Option, and I want to take a specific action if it's equal to None.
Say, for example, that I'm trying to create a default user at boot time if it doesn't already exist. I'd call a function that attempts to find a user that matches the default one, and returns an Option[User].
If that return value is None, I'd like to run some user creation code. If not, I'm done.
I'm wondering what's the most idiomatic Scala syntax for this. What I have so far is:
def getUser(name: String): Option[User] = ...
getUser("admin") getOrElse createUser("admin", "ChangeThisNow!")
getUser("admin") match {
case None => createUser("admin", "ChangeThisNow!")
case _ =>
}
if(getUser("admin") == None) createUser("admin", "ChangeThisNow!")
The first solution seems like the most functional one, but I can't help but feel that there might be better ones - possibly by using partially applied functions, which I admit I'm still a bit fuzzy about.
Since in your case the goal is to cause a side effect, I'd use a conditional to stress that, instead of using getOrElse.
if (getUser("admin").isEmpty)
createUser("admin", "ChangeThisNow!")
Remember that scala is a multi-paradigm language.
In addition to syntax, you want to consider concepts such as cohesion (single responsibility) and so you can consider the composition of your objects in addition to the actual idioms you use in the syntax.
The OO way might be to decorate the object/class that getUser belongs to in to put that concern of creating the user in a wrapper so that other code that calls the getUser function never has to deal with that concern. This fits nicely with open/closed principle and single responsibility. This is a bit of an anemic domain model anti-pattern here but may show how OO can be used to extend the conversation into actual design.
Either pattern matching or getOrElse are reasonable solutions. Generally if statements aren't used against Monads like the option - at least not that I see.
Either way, I beleive the expression should return the result even if there are side effects (user creation).
case class User(name: String)
class UserService {
def getUser(name: String): Option[User] = ???
def createUser(name: String): User = ???
}
class UserServiceDecorator extends UserService {
override def getUser(name: String): Option[User] =
Some(super.getUser(name).getOrElse(super.createUser(name)))
}
Really the best way to do this is to assign the result to a meaningful variable name so your future code doesn't need to know if createUser was called or not.
val user = getUser("admin").getOrElse(createUser("admin", "ChangeThisNow!"))
This way you can use the user variable regardless of if you've created a new user or not.
As far as I understand value classes in Scala are just there to wrap primitive types like Int or Boolean into another type without introducing additional memory usage. So they are basically used as a lightweight alternative to ordinary classes.
That reminds me of Haskell's newtype notation which is also used to wrap existing types in new ones, thus introducing a new interface to some data without consuming additional space (to see the similarity of both languages consider for instance the restriction to one "constructor" with one field both in Haskell and in Scala).
What I am wondering is why the concept of introducing new types that get inlined by the compiler is not generalized to Haskell's approach of having zero-overhead type wrappers for any kind of type. Why did the Scala guys stick to primitive types (aka AnyVal) here?
Or is there already a way in Scala to also define such wrappers for Scala.AnyRef types?
They're not limited to AnyVal.
implicit class RichOptionPair[A,B](val o: Option[(A,B)]) extends AnyVal {
def ofold[C](f: (A,B) => C) = o map { case (a,b) => f(a,b) }
}
scala> Some("fish",5).ofold(_ * _)
res0: Option[String] = Some(fishfishfishfishfish)
There are various limitations on value classes that make them act like lightweight wrappers, but only being able to wrap primitives is not one of them.
The reasoning is documented as Scala Improvement Process (SIP)-15. As Alexey Romanov pointed out in his comment, the idea was to look for an expression using existing keywords that would allow the compiler to determine this situation.
In order for the compiler to perform the inlining, several constraints apply, such as the wrapping class being "ephemeral" (no field or object members, constructor body etc.). Your suggestion of automatically generating inlining classes has at least two problems:
The compiler would need to go through the whole list of constraints for each class. And because the status as value class is implicit, it may flip by adding members to the class at a later point, breaking binary compatibility
More constraints are added by the compiler, e.g. the value class becomes final prohibiting inheritance. So you would have to add these constraints to any class who want to be inlineable that way, and then you gain nothing but extra verbosity.
One could think of other hypothetical constructs, e.g. val class Meter(underlying: Double) { ... }, but the advantage of extends AnyVal IMO is that no syntactic extensions are needed. Also all primitive types are extending AnyVal, so there is a nice analogy (no reference, no inheritance, effective representation etc.)
Case classes in Scala are standard classes enhanced with pattern-matching, equals, ... (or am I wrong?). Moreover they require no "new" keyword for their instanciation. It seems to me that they are simpler to define than regular classes (or am I again wrong?).
There are lots of web pages telling where they should be used (mostly about pattern matchin). But where should they be avoided ? Why don't we use them everywhere ?
There are many places where case classes are not adequate:
When one wishes to hide the data structure.
As part of a type hierarchy of more than two or three levels.
When the constructor requires special considerations.
When the extractor requires special considerations.
When equality and hash code requires special considerations.
Sometimes these requirements show up late in the design, and requires one to convert a case class into a normal class. Since the benefits of a case class really aren't all that great -- aside from the few special cases they were specially made for -- my own recommendation is not to make anything a case class unless there's a clear use for it.
Or, in other words, do not overdesign.
Inheriting from case classes is problematic. Suppose you have code like so:
case class Person(name: String) { }
case class Homeowner(address: String,override val name: String)
extends Person(name) { }
scala> Person("John") == Homeowner("1 Main St","John")
res0: Boolean = true
scala> Homeowner("1 Main St","John") == Person("John")
res1: Boolean = false
Perhaps this is what you want, but usually you want a==b if and only if b==a. Unfortunately, the compiler can't sensibly fix this for you automatically.
This gets even worse because the hashCode of Person("John") is not the same as the hashCode of Homeowner("1 Main St","John"), so now equals acts weird and hashCode acts weird.
As long as you know what to expect, inheriting from case classes can give comprehensible results, but it has come to be viewed as bad form (and thus has been deprecated in 2.8).
One downside that is mentioned in Programming in Scala is that due to the things automatically generated for case classes the objects get larger than for normal classes, so if memory efficiency is important, you might want to use regular classes.
It can be tempting to use case classes because you want free toString/equals/hashCode. This can cause problems, so avoid doing that.
I do wish there were an annotation that let you get those handy things without making a case class, but maybe that's harder than it sounds.