« Return to Thread: equals in case class does not seem to be working...

Re: equals in case class does not seem to be working...

by Kevin Wright-4 :: Rate this Message:

Reply to Author | View in Thread

IIRC, the way that immutable accessors are generated is by simply defaulting to the "val" prefix on all constructor args.

In this case, by explicitly using "var" you override this default behaviour, so that the mutable accessors will be generated instead of the immutable defaults, not in addition to them.

Behind the scenes, val arg1 will be expanded to (in Java)

class User {
    private String arg1;

    void User(String arg1) {
        this.arg1 = arg1;
    }

    String arg1() { return this.arg1; }
}

Using a var does exactly the same, but also adds the method:

void arg1_=(String arg1) {
    this.arg1 = arg1;
}

This isn't the exact encoding of the name (due to the = symbol), but that would just confuse the issue :)


The reason your example fails is that the generated equality method on case classes only works with constructor parameters, so that arg1 will be compared ("with args" != "without args") and field1 is simply ignored.  Of course, you can always override that as well, but doing so could cause a lot of other problems.


On Wed, Jul 8, 2009 at 7:40 AM, Alexandre <alexmsmartins@...> wrote:
Not really but thanks none the less.
I had that version at the beginning and only took the "var" from the
constructor's args as an experiment.
Besides, as Naftoli Gugenhem ponted out "Case classes define immutable
fields.as well as a generated equals method". In your example you are
also generating mutable fields. You're simply generating them in a
different place than me.

To try that for yourself just run the code of this shell session.

-------------------------------------------------------------------------------
scala> case class User(arg1:String) { var field1 = arg1
    | def this() = {
    | this("without args")
    | }
    | }
defined class User

scala> val u1 = User("with args")
u1: User = User(with args)

scala> val u2 = new User()
u2: User = User(without args)

scala> u2.field1 = "with args"

scala> u1 == u2
res0: Boolean = false

scala> u1.field1 == u2.field1
res1: Boolean = true



On Wed, Jul 8, 2009 at 6:50 AM, Kevin
Wright<kev.lee.wright@...> wrote:
> You'd have more luck in making the constructor args into vars:
> case class User(
>     var userName : String,
>     var password : String,
>     var firstName : String,
>     var lastName : String,
>     var emailAddress : String ) extends DataModel
> {
>     def this() = ...
>     ...
>     ...
> }
>
> Not tried this myself on case classes, but can't think of any reason why it
> wouldn't work :)
>
> On Wed, Jul 8, 2009 at 2:51 AM, Naftoli Gugenhem <naftoligug@...>
> wrote:
>>
>> Case classes define immutable fields, as well as a generated equals
>> method. The fact that you defined additional mutable fields does not change
>> the generated equals method.
>>
>> -------------------------------------
>> Alexandre<alexmsmartins@...> wrote:
>>
>> Hi to you all
>>
>> First of all I'm a less than a year scala hobbyist (e. g. user) and
>> this is my first post to this list. So bare with me. :)
>> I was trying to do unit testing and I thought that using
>> assertEquals() in Junit 4 with objects from the same case class with
>> exactly the same content wold cut it. Yet, I run into some troubles
>> and ended up doing this small snippet in the scala shell that shows me
>> it does not work.
>> Am I doing anything wrong or is this to be expected?
>> If it is to be expected could you explain/point to some reading that
>> makes it clear why.
>>
>> Thanks in advance
>> Alexandre Martins
>>
>>
>> ------------------------------------------------------------------------------------------
>>
>> scala> import scala.xml.Node
>> import scala.xml.Node
>>
>> scala> import scala.xml.Elem
>> import scala.xml.Elem
>>
>> scala> import scala.reflect.BeanProperty
>> import scala.reflect.BeanProperty
>>
>> scala> import scala.reflect.BeanProperty
>> import scala.reflect.BeanProperty
>>
>> scala> import java.util.Date
>> import java.util.Date
>>
>> scala> import scala.reflect.BeanInfo
>> import scala.reflect.BeanInfo
>>
>> scala> /**
>>    |  * Represents a user of WikiModels
>>    |  */
>>
>> scala> @BeanInfo
>>    | case class User(usrName:String,
>>    |            pssword:String,
>>    |            frstName:String,
>>    |            lstName:String,
>>    |            mail:String ) extends DataModel {
>>    |
>>    |     var userName = usrName
>>    |     var password = pssword
>>    |     var firstName = frstName
>>    |     var lastName = lstName
>>    |     var emailAddress = mail
>>    |
>>    |     def this() = {
>>    |         this("","","","","")
>>    |     }
>>    |
>>    |     /**
>>    |      * generates a XML representation of the user, excluding password
>>    |      * @return the XML representing the user
>>    |      */
>>    |     def toXML:Node =
>>    |     <user>
>>    |         <username>{userName}</username>
>>    |         <!--<password>{password}</password>-->
>>    |         <firstName>{firstName}</firstName>
>>    |         <lastName>{lastName}</lastName>
>>    |         <email>{emailAddress}</email>
>>    |     </user>
>>    |
>>    |     def extractXML(xml:Node):Unit = {
>>    |         xml match {
>>    |             case <username>{contents}</username> =>
>> this.userName = contents.text
>>    |             case <firstName>{contents}</firstName> =>
>> this.firstName = contents.text
>>    |             case <lastName>{contents}</lastName> =>
>> this.lastName = contents.text
>>    |             case <email>{contents}</email> => this.emailAddress
>> = contents.text
>>    |             case <user>{c @ _ *}</user> => for (val child <- c)
>> extractXML(child)
>>    |             case _ => { }
>>    |         }
>>    |     }
>>    | }
>> defined class User
>>
>> scala> var u = User("alex","alexp","Alexandre",
>> "Martins","alexmsmartins@...")
>> u: User = User(alex,alexp,Alexandre,Martins,alexmsmartins@...)
>>
>> scala> var d = new User()
>> d: User = User(,,,,)
>>
>> scala> u == d
>> res2: Boolean = false
>>
>> scala> u
>> res3: User = User(alex,alexp,Alexandre,Martins,alexmsmartins@...)
>>
>> scala> d
>> res4: User = User(,,,,)
>>
>> scala> d.extractXML(  u.toXML)
>>
>> scala> d.password = u.password
>>
>> scala> d.password
>> res18: String = alexpscala> d
>> res7: User = User(,,,,)
>>
>> scala> d.toXML == u.toXML
>> res8: Boolean = true
>>
>> scala> d == u
>> res9: Boolean = false
>
>

 « Return to Thread: equals in case class does not seem to be working...