Search code examples
javascalainheritanceoverridingtraits

Scala - override a class method in a trait


I'm new to Scala (came from Ruby world).

And I was curious about "traits" concept in Scala (which should be ~similar to modules in ruby, if I understand it correctly).

And here's a use case.

Suppose I have a class called User defined like this:

class User {
    def password() : String = "generating a password (default)"
}

And suppose I have a trait SecurePasswords using which I would like to "override" the password method defined in the User class.

trait SecurePasswords {
    def password() : String = "generating a secure password (non-default)"
}

And, suppose, I want it to be applicable to instances of the User class and not to the entire class itself.

val a = new User
val b = new User with SecurePasswords

a.password() # generating a password (default)
b.password() # generating a secure password (non-default)

Now this is an ideal output that I would expect, however, I get different errors like "anonymous class inherits conflicting members ... (Note: this can be resolved declaring etc etc ...)"

Can this be done in Scala or I'm asking too much / doing something really weird? Is it possible to do w/o any additional class definitions, like UserWithSecurePassword extends User

Thank you all in advance!

P.S In case you are wondering "why?", just assume that system would contain a lot of entities that require password (and, potentially, secure password), so the trait could be used in a lot of places.


Solution

  • The conflict between the two method definitions is because you didn't make them the "same method". All you did was make them coincidentally have the same name, arguments, and return type.

    To make them really the same method, so that one can override the other, define them in the same place:

    trait HasPassword {
      def password(): String
    }
    
    class User extends HasPassword {
      override def password(): String = "generating a password (default)"
    }
    
    trait SecurePassword extends HasPassword {
      override def password(): String = "generating a password (non-default)"
    }
    
    new User with SecurePassword
    

    By being defined in the trait HasPassword, and then overridden (instead of doppleganged or duck-typed) in User and SecurePassword, Scala understands that this is truly the same method being redefined. Thus, when you mix in SecurePassword, it can override the password() method in User.