Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6552931
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T12:31:12+00:00 2026-05-25T12:31:12+00:00

I want to have several data classes which all have an identifier that is

  • 0

I want to have several data classes which all have an identifier that is appointed to be
sufficient for checking object equality.
But this id: I should be used not only for test
of equality but for comparison purposes too.
That’s why a view bound I <% Ordered[I] is claimed in following
base class.

abstract class Ident[I <% Ordered[I]](val id: I)
  extends Equals with Ordered[Ident[I]]
{
  override lazy val hashCode = id.hashCode
  /* canEqual does not work as desired! */
  def canEqual(other: Any) = other match {
    case that: Ident[I] => true /* id < that.id || id > that.id || id == that.id */
    case _              => false
  }
  override def equals(other: Any) = other match {
    case that: Ident[I] => (that canEqual this) && this.id == that.id
    case _              => false
  }
  def _compare(that: Ident[I]): Int = {
    if (that canEqual this) this.id compare that.id else {
      val message = "'%s' and '%s' are not comparable!" format (this, that)
      throw new IllegalArgumentException(message)
    }
  }
  def compare(that: Ident[I]): Int = _compare(that)
}

The compare method is defined only when canEqual is true.

Because derived classes T <: Ident[I] should be Ordered[T] too, an implicit conversion is defined:

object Ident {
  implicit def ident2ordered[I, T <: Ident[I]](other: T): Ordered[T] = {
    new Ordered[T] {
      def compare(that: T): Int = other._compare(that)
    }
  }
}

And here are some derived data classes:

/* should be comparable with all other <: Ident[Int] */
class IntId(i: Int) extends Ident[Int](i)
/* should be comparable only with itself */
class YetAnotherIntId(y: Int) extends Ident[Int](y) {
  override def canEqual(other: Any) = other.isInstanceOf[YetAnotherIntId]
  override def equals(other: Any) = other match {
    case that: YetAnotherIntId => super.equals(that)
    case _                     => false
  }
}
/* should be comparable with all other <: Ident[Long] */
class LongId(j: Long) extends Ident[Long](j)
/* should be comparable with all other <: Ident[String] */
class StringId(s: String) extends Ident[String](s)

And now the noticed (but not always desired) behaviour:

val i12 = new IntId(12)
val i13 = new IntId(13)
i12 canEqual i13 /* => true */
i12 < i13        /* => true */

val y12 = new YetAnotherIntId(12)
val y13 = new YetAnotherIntId(13)
y12 canEqual y13 /* => true */
y12 < y13        /* => true */

i12 canEqual y12 /* => true */
y12 canEqual i12 /* => false */
i12 == y12       /* => false */
y12 == i12       /* => false */

val j12 = new LongId(12L)
val j13 = new LongId(13L)
j12 canEqual j13 /* => true */
j12 < j13        /* => true */

i12 canEqual j12 /* => true  but want false because Int != Long */
j12 canEqual i12 /* => true  '' */
i12 == j12       /* => true  '' */
j12 == i12       /* => true  '' */

val s12 = new StringId("12")
val s13 = new StringId("13")
s12 canEqual s13 /* => true */
s12 < s13        /* => true */

i12 canEqual s12 /* => true  but want false because Int != String */
s12 canEqual i12 /* => true  '' */
i12 == s12       /* => false */
s12 == i12       /* => false */

Thank you, if you’ve read this far, but now the questions:

How can I achieve that Ident[I].canEqual(Ident[J]) is false for I != J without overriding canEqual like in YetAnotherIntId?

It seems that an Ident[I] is an Ident[J] is an Ident[_] which would yield to problems when using this.id and that.id together by commenting out in Ident::canEqual (replacing true with this.id < that.id || this.id > that.id || this.id == that.id).

So, why Ident[Int].canEqual(Ident[Long]) is true? Due to type erasure? Is it possible to “repair” this whith an Manifest? Or is there another possibility to ensure that I == J?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T12:31:13+00:00Added an answer on May 25, 2026 at 12:31 pm

    Type erasure indeed. You must have got some warning on your case that: Ident[I]. It checks you have an Ident[somehing] but not that this something is I (same as in java).
    It is better to check with that: Ident[_] where you have no false assurance.

    You might indeed have a Manifest in your class, and check that the manifests are equals.

    class Ident[I <% Ordered](val id: I)(implicit val manifest: Manifest[I])
      def canEqual(that: Any) = that match {
        case Ident[_] if this.manifest == that.manifest => ...
        case _ => false
      }
    }
    

    I would suggest I : Ordering rather than I % Ordered (in general, not just for your problem). You could then compare the orderings rather than the manifests. Also you should use that to do the equal on the ids too, this way you know it is consistent with ordering

    Edit Regarding your comment.

    I would think this and that having the same Ordering is enough to say canEqual is true. Then, you have this.Odering which the compiler known is an Ordering[I], and that.Ordering which is an ordering on a type the compiler does not known. You will have to use the first one, which will imply an unchecked cast (pattern matching or otherwise) of that.id to I. However, having checked the ordering equality should be enough to ensure the cast is safe (Ordering is invariant)

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have several small classes that are all peers of each other declared and
I have some classes, which have several methods which I don't really want to
I have several different lists I want to call. They all have the same
I have several unordered lists that I want to display like this: <ul> <li><img></li>
I have several sites that I want to link back to the main site
I have several web pages on several different sites that I want to mirror
I have several embedded linux systems that I want to write a 'Who's Online?'
I have several Code Analysis CA1704:IdentifiersShouldBeSpelledCorrectly warnings that I want to suppress. Basically, they
I have several sql queries that I simply want to fire at the database.
I have several templated objects that all implement the same interface: I.E. MyObject<datatype1> obj1;

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.