Scala - override class method in attribute

I am new to Scala (came from the world of Ruby).

And I was curious about the concept of “traits” in Scala (which should be ~ like modules in ruby, if I understand it correctly).

And here is a precedent.

Suppose I have a class called User defined as follows:

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

And suppose I have a SecurePasswords feature in 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 this to apply to instances of the User class, and not to the entire class.

 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 the ideal conclusion that I would expect, however, I get various errors, such as " anonymous class inherits conflicting members ... (Note: this can be resolved declaring etc etc ...) "

Can this be done in Scala, or am I asking / doing something really strange too much? Is it possible to do without any additional class definitions, e.g. UserWithSecurePassword extends User

Thank you all in advance!

PS If you are wondering “why?”, Just assume that the system will contain many objects that require a password (and possibly a secure password), so this symptom can be used in many places.

+6
source share
5 answers

The conflict between the two method definitions is that you did not make them "the same method." All you did was that they coincided with the same names, arguments, and return type.

To make them truly one and the same method so that you can override another, 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 

HasPassword in the trait, and then redefining (instead of doppleganged or duck-typed) in User and SecurePassword , Scala realizes that this is really the same method that is being redefined. That way, when you mix in SecurePassword , it can override the password() method in User .

+11
source

In addition to my previous answer - a completely different way to get what you want is to pass the password function to 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 the default argument to avoid the need to specify a password function in the default case.

+5
source

I'm not sure what will be for this. Why not just use the User, in Ruby, "mixin" property of SecurePasswords and override the password in it for the class definition?

Coming from Ruby, this may be harder to get, but Scala is a compiled language, and it is usually not recommended to change class definitions dynamically / on the fly like this. Think of the Scala type system as a way to test your code. The more you delay code interpretation at runtime, the less reliable and secure your code becomes. This is one of the strengths of Scala / Java / Haskell / ... (insert a compiled typed language) - the type system can catch many errors at compile time. Use it to your advantage, do not fight it.

I would consider using implicit parameters and how they can be linked / used with tags.

Also, without the broader context of what you are trying to execute in your code using this template, this is hard to understand, but this link may be useful to you if you are trying to implement some kind of adapter template.

http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html

+1
source

You can provide different password rules for each instance as follows - but you need to specify an explicit sign in each case (default or safe):

  abstract class User { def password(): String } trait SecurePasswords { def password(): String = "generating a secure password (non-default)" } trait DefaultPasswords { def password(): String = "generating a password (default)" } val a = new User with DefaultPasswords val b = new User with SecurePasswords a.password() // generating a password (default) b.password() // generating a secure password (non-default) 

Update: However, I think Dan Getz's answer is probably closer to what you originally requested

+1
source

Note. Regarding the error message, pending issue 128 "there is no ambiguity error when inheriting a conflicting element from the default Java method"

It must be enabled in scala 2.12.x commit 3a3688f64

SD-128 fix override errors for default methods

Checking the inheritance of two conflicting members was incorrect for default methods, resulting in a missing error message.

We also did not give out the "need" to override the "modifier" when overriding by default.

0
source

Source: https://habr.com/ru/post/977904/


All Articles