-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Disallow equals and hashCode in universal traits #629
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
Comments
@DarkDimius: feel free to explain the rewriting scheme you have in mind that could handle having custom |
Let me illustrate: trait A extends Any {
def equals(other: Object) = false
} becomes trait A extends Any {
def equals(other: Object) = false
}
trait A$extension {
def equals$extension[@specialized T](this: T)(other: Object) = false
} Than if we have class B(val s: Int) extends AnyVal with A we rewrite as we do currently: virtual methods forward to static implementations: class B(val s: Int) extends AnyVal with A {
def equals(other: Object) = B.equals$extension(s)(other)
}
object B extends A$extension We remove previous rules that we had
Instead we handle them the same way how we rewrite calls to normal methods(Step 2 of SIP)
becomes simply
|
Yes, that part makes sense, but things start getting difficult when you have virtual dispatch: trait A extends Any {
def equals(other: Object) = foo
def foo: Boolean = false
}
trait B extends A {
override def foo: Boolean = true
}
class Foo(val x: Int) extends AnyVal with A
class Bar(val x: Int) extends AnyVal with B Can you show how your rewriting would work in that case? |
Those universal traits create additional trait A$extension {
def equals$extension[@specialized T](this: T)(other: Object) = foo$extension(this)
def foo$extension[@specialized T](this: T) = false
}
trait B$extension extends A$extension{
def foo$extension[@specialized T](this: T) = true
} Note that rhs of Foo and Bar companion objects will simply inherit respective traits, as they do in simpler example above. And you'll get the expected behavior. Everything else remains the same |
OK, what about: trait A extends Any {
def isMeter: Boolean = this.isInstanceOf[Meter]
} |
I think my previous example can be dealt with by having a trait A$extension {
def box$[@specialized T]($this: T): Any = sys.error("Should always be overriden")
def isMeter$extension[@specialized T]($this: T): Boolean = box$($this).isInstanceOf[Meter]
}
object Meter extends A$extension {
// Only the box specialized for Int is implemented, because the
// underlying type of Meter is Int
def box$$specializedForInt($this: Int): Meter = new Meter($this)
} |
@DarkDimius : Not in every universal trait, no, and there are many details left to fill to see if this works. |
But I agree that it's something we should experiment with. |
No, I think for now we should restrict universal traits not to have equals On Wed, Jun 3, 2015 at 5:05 PM, Dmitry Petrashko [email protected]
Martin Odersky |
So, I'm getting more and more convinced that we can avoid boxing when calling universal trait methods, but unfortunately it also seems that this won't help us avoid special casing def == (that: Any): Boolean So even if we can rewrite |
If user did define custom equals we need to box, unless we use inlining, or similar approaches. Simply because user could want to have If user didn't define a custom equals we can create an overload, that doesn't, that will do the same as current scheme, as |
Well, so far we have avoided overloading extension methods, I don't know if we want to break this now. Maybe it's better to wait until we decide what we want to do with |
That's not true:
the only problem with overloads in value classes is that changing their order is not a binary compatible change. |
and that's the main reason why extension methods have consecutive numbers in the name:
|
I mean, in your example you will get two extension methods |
@smarter with any method, including
No special rules are required in this proposal. The whole motivation behind this proposal is to make scheme more regular, without introducing new rules. |
OK, but then that means that adding |
onсe again, it's easy to make this be binary compatible: always generate a forwarder. Even if user did define a custom equals, we make an equals, that simply forwards. This is not safe for arbitary classes, but is safe for final ones. |
EDIT: Ah OK, ignore that, I now see that with a forwarder that boxes we should be able to preserve binary compatiblity.
|
Yes, and this situation is fixed by always generating the |
@smarter reopen if I'm wrong but I think we can close this as we can't change this now that 3.0 is out. |
equals
andhashCode
should always be synthesised in value classes so thatnew Meter(3) == new Meter(4)
can be rewritten as3 == 4
, so allowingequals
andhashCode
in universal traits doesn't make much sense.The text was updated successfully, but these errors were encountered: