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.
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
.
In addition to my previous answer - a completely different way to get what you want is to pass the password function into the User class, rather than using traits:
class User(pw: ()=>String=default) {
def password = pw
}
val default = () => "generating a password (default)"
val secure = () => "generating a secure password (non-default)"
val a = new User()
val b = new User(secure)
a.password() // generating a password (default)
b.password() // generating a secure password (non-default)
As shown, you can use a default argument to avoid having to specify the password function in the default case.
I'm not sure what the use case would be for this. Why not just have the User, in Ruby terms, 'mixin', the SecurePasswords trait and override password within it's class definition?
Coming from Ruby, this might be more difficult to get, but Scala is a compiled language and it's generally not a good idea to change class definitions dynamically/on-the-fly like this. Think of the type system in Scala as a way of testing your code. The more you defer code interpretation to runtime, the less testable/safe your code becomes. This is one of the strengths of Scala/Java/Haskell/... (insert compiled typed language) - the type system can catch a lot of errors at compile time. Use this to your advantage, don't fight against it.
I would look into the use of implicit parameters and how they can relate/be used with traits.
Also, without the broader context of what you are trying to accomplish in your code with this pattern, it's hard to know, but this link might prove useful to you if you are trying to implement some sort of adapter pattern.
http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With