Scala: Reuse parameter name in extended classe - scala

In this code, the parameter a in B is different from the A.a
class A(var a:String)
class B(a:String) extends A(a) {
println(a) // Use B.a
def p() {
println(a)
}
}
val b=new B("abc")
b.p() // "abc"
b.a="def"
b.p() // "abc" and not "def"
I can rename the parameter in B like this :
class B(_a:String) extends A(_a) {
println(_a) // Use B.a
def p() {
println(a)
}
}
but I would like to maintain the name 'a', for the Scaladoc, and compatibility with the syntax B(a="def").
How I can resolve this scenario ?

You can make the primary constructor private and add a secondary constructor which has a as the name:
class B private (_a:String, ignore: Unit) extends A(_a) {
def this(a) { this(a, ()) }
println(_a) // Use B.a
def p() {
println(a)
}
}
But this seems like it could easily lead to confusion. So I'd look for alternative designs, as the comments to the question suggest.

Related

Why would trait's val be evaluated if it is overridden in class?

scala> trait A { val a = { println("i'm invoked"); "1" } }
defined trait A
scala> class B extends A { override val a = { println("i'm invoked B"); "2" } }
defined class B
scala> (new B).a
i'm invoked
i'm invoked B
res0: String = 2
How can I avoid the val a in trait A being evaluated? I tried using lazy val and that works, but would be interested in knowing if there's an alternative way to do this. Thanks.
As described in this Scala doc:
Initialization of strict vals is done in the following order:
Superclasses are fully initialized before subclasses.
Otherwise, in declaration order.
The clause "fully initialized before" explains why a strict val is evaluated despite being overriden in the subclass.
Besides lazy val, an alternative is to replace val with def in your trait:
trait A { def a = { println("i'm invoked"); "1" } }
class B extends A { override def a = { println("i'm invoked B"); "2" } }
(new B).a
// i'm invoked B
// res1: String = 2

Scala: make an implicit class accessible from classes injecting the class defining it

I have an implicit class defined in a class injected in other classes like this
class A {
implicit class B(s: String) {
def b = ???
}
}
class C(a: A) {}
Is there a way to access implicit class B (and in particular its method b) from the class C, without importing it explicitly? (Please note that class A could not be a trait since it also injects some classes.)
Solution 1 (import a._)
Well, yes, as already noted in the comments, from your requirements it is not obvious why you wouldn't just import a._ in the body of C:
class A {
implicit class B(arg: String) {
def b: String = ???
}
}
class C(a: A) {
import a._
{
println("hello".b)
}
}
This one line really doesn't hurt anyone.
If you still don't like it, then the problem might be elsewhere. Thus my second proposal.
Solution 2 (separating typeclass-like A-interface from .b-syntax)
This other solution is less about the reduction of number of imports in your code, and it doesn't even keep class B inside A. But it might address another issue that you maybe just can't quite articulate: it separates the functionality provided by A from the syntax provided by B.
The structure of the following snippet is inspired by the design of the Scala Cats library, that follows a very clear policy with the implicit declarations, always separating the typeclass defintions from the syntax.
The main idea is that:
Implementations of AIntf provide actual functionality
B provides only some additional "pimp-my-library"-style methods
and that we want to keep these two things separate.
Here is how to separate them, thereby also avoiding import a._ inside of C. First, you define the interface that describes the functionality provided by A:
trait AIntf {
def usefulOperationOnStrings(s: String): String
}
Then you can implement it by a few different A`s:
class A extends AIntf {
def usefulOperationOnStrings(s: String): String = "<foo>" + s + "</foo>"
}
class A2 extends AIntf {
def usefulOperationOnStrings(s: String): String = s.toUpperCase
}
Note that the object B has disappeared from A. Instead, it is moved in a separate syntax-package, and renamed to A_Ops. The method b is also renamed to a:
object syntax /* should be package, object only for script */ {
object a {
class A_Ops(wrapped: String, ai: AIntf) {
def a: String = ai.usefulOperationOnStrings(wrapped)
}
implicit def everyStringHasAOps(s: String)(implicit ai: AIntf): A_Ops = {
new A_Ops(s, ai)
}
}
}
This is how you use it:
You say in the imports that you want to refer to interface A_Intf
You say in the imports that you want to use the syntax syntax.a._
You declare the a-argument of C as implicit
Then you can just use "string".a syntax inside C without further imports.
In code:
import myproject.AIntf
import myproject.syntax.a._
class C(implicit val a: AIntf) {
{
println("hello".a)
}
}
Now the implementations of AIntf and the syntax .a become independent. You can inject A2 instead of A. Or you can change the syntax from "str".a to "str".somethingEntirelyDifferent.
The full code snippet:
import scala.language.implicitConversions
object myproject /* should be package, object only for script */ {
trait AIntf {
def usefulOperationOnStrings(s: String): String
}
object syntax /* should be package, object only for script */ {
object a {
class A_Ops(wrapped: String, ai: AIntf) {
def a: String = ai.usefulOperationOnStrings(wrapped)
}
implicit def everyStringHasAOps(s: String)(implicit ai: AIntf): A_Ops = {
new A_Ops(s, ai)
}
}
}
class A extends AIntf {
def usefulOperationOnStrings(s: String): String = "<foo>" + s + "</foo>"
}
class A2 extends AIntf {
def usefulOperationOnStrings(s: String): String = s.toUpperCase
}
}
import myproject.AIntf
import myproject.syntax.a._
class C(implicit val a: AIntf) {
{
println("hello".a)
}
}
val c1 = new C()(new myproject.A)
val c2 = new C()(new myproject.A2)
// prints:
// <foo>hello</foo>
// HELLO
Unfortunately, I have no clue what guice is going to do with an implicit argument, have not tried it yet. It might force you to write
class C #Inject()(val a: AIntf) {
implicit aintf: AIntf = a
...
}
which then becomes longer then the simple import mentioned in the first part.
as noted in comment, just import a._:
class A {
implicit class B(s: String) {
def b: String = "hello "+ s
}
}
class C(a: A){
import a._
val hello = "world".b
}
val c = new C(new A)
c.hello // "hello world"

Scala trait extending abstract class, how do I know whether an abstract method has been implemented or not

I am new to scala, and I have the following question
abstract class A {
def foo(): List[String]
}
trait AA extends A {
override def foo(): List[String] = {
// Something like
// If super.foo is implemented, "AA" +: super.foo
// If super.foo is not implemented, List("AA")
}
}
class B extends A with AA {
override def foo(): List[String] = {
// I think the trait will have the implementation, so I should only need to do:
super.foo
}
}
Basically I would like each trait to add one part to the result of foo, so that I can have the final result by mixing multiple such traits. I think I can make the foo method in class A to return empty List, but I am just curious whether there is a way to check whether the method in parent has been implemented or not.
Also, please let me know if there is an anti-pattern.
I think you want the stackable trait pattern.
So you have an abstract class A which declares some method foo(), and you have a "decorator" of that method who says something like "I extend A and I would like to append 'AA' to whatever foo() returns".
abstract class A {
def foo(): List[String]
}
trait AA extends A {
abstract override def foo(): List[String] = "AA" :: super.foo()
}
Note the abstract override, this is the key. It allows us to append some behaviour to an abstract class.
Now let's say we do something like this:
class WithoutImpl extends A with AA {
override def foo(): List[String] = {
super.foo() // fails; needs "abstract override" or implementation
}
}
This fails because everyone is decorating, but noone is actually implementing.
Let's add an implementation trait:
trait AAA extends A {
override def foo(): List[String] = List("AAA")
}
Now we might do:
class WithImpl extends AA with AAA {
def myFoo(): List[String] = {
super.foo() // error! wrong order of initialization
}
}
This will still fail due to the order of mixins. We must first provide an implementation, and then we provide the decorator(s), who will then keep adding behaviours.
class WithImpl extends AAA with AA {
def myFoo(): List[String] = {
super.foo() // works!
}
}
println((new WithImpl().myFoo())) // List("AA", "AAA")
You can add as many decorators as you wish, just pay attention to the order. E.g. if we had BB and CC similarly to AA, we could do:
class WithImpl extends AAA with AA with BB with CC {
def myFoo(): List[String] = {
super.foo() // List(CC, BB, AA, AAA)
}
}

Conditioning on type parameters passed to a class

Suppose I have MyCoolClass which accepts a type parameter T.
Depending on T we want to define aFun in this way:
If ( T is the same type as B ) aFun should be set to () => new B
else If ( T is the same type as C ) aFun should be set to () => new C
otherwise show an error.
class MyCoolClass[T]{
def aFun = ... // fill this part
}
class A {
// something here
}
class B extends A {
// something more here
}
class C extends A {
// yet more things here
}
How would you go about doing this?
You can't do that this way. What you can do is instead restrict Ts in MyCoolClass to require a instance of a type class that would know how to instantiate T:
trait Cons[T] { def cons:T }
class MyCoolClass[T](implicit ev:Cons[T]) {
def aFun = ev.cons
}
Now what we need is define A and B and Cons[A] and Cons[B] (**)
class A
class B
object A { implicit def consA:Cons[A] = new Cons[A] { def cons = new A } }
object B { implicit def consA:Cons[B] = new Cons[B] { def cons = new B } }
Now in the REPL:
scala> new MyCoolClass[A].aFun
res0: A = A#1521d074
scala> new MyCoolClass[B].aFun
res1: B = B#19cdb1cb
(**) If you happen to try that in the REPL remember to copy and paste it in a :paste command, otherwise object A and B won't really be companion objects and this own't work

When to use val or def in Scala traits?

I was going through the effective scala slides and it mentions on slide 10 to never use val in a trait for abstract members and use def instead. The slide does not mention in detail why using abstract val in a trait is an anti-pattern. I would appreciate it if someone can explain best practice around using val vs def in a trait for abstract methods
A def can be implemented by either of a def, a val, a lazy val or an object. So it's the most abstract form of defining a member. Since traits are usually abstract interfaces, saying you want a val is saying how the implementation should do. If you ask for a val, an implementing class cannot use a def.
A val is needed only if you need a stable identifier, e.g. for a path-dependent type. That's something you usually don't need.
Compare:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
If you had
trait Foo { val bar: Int }
you wouldn't be able to define F1 or F3.
Ok, and to confuse you and answer #om-nom-nom—using abstract vals can cause initialisation problems:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
This is an ugly problem which in my personal opinion should go away in future Scala versions by fixing it in the compiler, but yes, currently this is also a reason why one should not use abstract vals.
Edit (Jan 2016): You are allowed to override an abstract val declaration with a lazy val implementation, so that would also prevent the initialisation failure.
I prefer not use val in traits because the val declaration has unclear and non-intuitive order of initialization. You may add a trait to already working hierarchy and it would break all things that worked before, see my topic: why using plain val in non-final classes
You should keep all things about using this val declarations in mind which eventually road you to an error.
Update with more complicated example
But there are times when you could not avoid using val. As #0__ had mentioned sometimes you need a stable identifier and def is not one.
I would provide an example to show what he was talking about:
trait Holder {
type Inner
val init : Inner
}
class Access(val holder : Holder) {
val access : holder.Inner =
holder.init
}
trait Access2 {
def holder : Holder
def access : holder.Inner =
holder.init
}
This code produces the error:
StableIdentifier.scala:14: error: stable identifier required, but Access2.this.holder found.
def access : holder.Inner =
If you take a minute to think you would understand that compiler has a reason to complain. In the Access2.access case it could not derive return type by any means. def holder means that it could be implemented in broad way. It could return different holders for each call and that holders would incorporate different Inner types. But Java virtual machine expects the same type to be returned.
I agree with the other answers about avoiding abstract vals for the reason that it provides more options to implementations.
There are cases where you might need them:
For a path-dependent type (as mentioned by #0__).
Where implementations might be expensive and it is used in a concrete def.
(Are there others? If so please comment and I'll add them in).
The more important things to know is when it is safe to override something with a val and to have a lazy val that does not override something.
Rule 1: Never override a val or def with a non-lazy val unless it is a constructor parameter:
trait TraitWithVal {
// It makes no difference if this is concrete or abstract.
val a: String
val b: String = a
}
class OverrideValWithVal extends TraitWithVal {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideValWithLazyVal extends TraitWithVal {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideValWithConstructorVal(override val a: String = "a") extends TraitWithVal
//class OverrideValWithDef extends TraitWithVal {
// // Compilation error: method a needs to be a stable, immutable value.
// override def a: String = "a"
//}
println((new OverrideValWithVal).b) // null
println((new OverrideValWithLazyVal).b) // a
println((new OverrideValWithConstructorVal).b) // a
The same rule applies to a def:
trait TraitWithDef {
// It makes no difference if this is concrete or abstract.
def a: String
val b: String = a
}
class OverrideDefWithVal extends TraitWithDef {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideDefWithLazyVal extends TraitWithDef {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideDefWithConstructorVal(override val a: String = "a") extends TraitWithDef
class OverrideDefWithDef extends TraitWithDef {
// Ok: b will be "a".
override def a: String = "a"
}
println((new OverrideDefWithVal).b) // null
println((new OverrideDefWithLazyVal).b) // a
println((new OverrideDefWithConstructorVal).b) // a
println((new OverrideDefWithDef).b) // a
You might be wondering whether it would be ok to override a val with another val so long as it isn't used during initialisation. There is at least one edge cases which break this:
trait TraitWithValAndLazyVal {
val a: String = "A"
def b: String = a
}
class OverrideLazyValWithVal extends TraitWithValAndLazyVal {
// Bad: This on its own is ok but not if it is indirectly referenced during initialisation and overridden.
override val a = "a"
val c = b
}
class OverrideValWithVal extends OverrideLazyValWithVal {
override val a = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // a
println((new OverrideValWithVal).c) // null
Given that we already apply this rule to overriding defs then this makes using vals a little more acceptable in my opinion.
If you use a linter to enforce the override keyword and make sure your code never has any override val definitions then you are good.
You might be able to allow final override val but it's possible there are other edge cases that I haven't thought of.
Rule 2: Never use a lazy val that is not overriding another lazy val or def.
As far as I can tell there also is no good reason to have a lazy val that isn't overriding something. All the examples that I can come up with where it is needed, it is needed only because it violates Rule 1 and exposes the edge case I described earlier.
For example:
trait NormalLookingTrait {
def a: String
val b: String = a
}
trait TraitWithAbstractVal extends NormalLookingTrait {
val c: String
}
class OverrideValWithVal extends TraitWithAbstractVal {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // null
println((new OverrideValWithVal).c) // a
So we make b a lazy val:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal2).a) // a
println((new OverrideValWithVal2).b) // a
println((new OverrideValWithVal2).c) // a
Looks ok, except when we go one step further:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
val d = b
}
class OverrideValWithVal3 extends OverrideValWithVal2 {
override val c = "a"
}
println((new OverrideValWithVal3).a) // a
println((new OverrideValWithVal3).b) // null
println((new OverrideValWithVal3).c) // a
println((new OverrideValWithVal3).d) // null
I now get what people mean when they say to only use lazy when it is absolutely necessary and never for delayed initialisation.
It's probably safe to break this rule if the trait / class is final but even that smells fishy.
Always using def seems a bit awkward since something like this won't work:
trait Entity { def id:Int}
object Table {
def create(e:Entity) = {e.id = 1 }
}
You will get the following error:
error: value id_= is not a member of Entity