Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - Extending a reference type without subclassing it

Tags:

java

scala

I have a Java class that I would like to subclass. The subclass is to add convenience methods only - it could all be done using external methods, because I only look at the public fields, and I don't modify anything.

If the base class was a value type, I'd use value wrappers - extends AnyVal. But the base class is a Java reference type. Is there any better way to subclass it other than extending it?

like image 426
SRobertJames Avatar asked Nov 11 '14 16:11

SRobertJames


1 Answers

To address your second paragraph specifically, the type you wrap with a value class can be a reference type and you still avoid the extra object allocation that would normally be involved in the wrapping. For example, if you've got these implicit classes:

implicit class MyInt(val underlying: Int) extends AnyVal {
  def inc: Int = underlying + 1
}

implicit class MyString(val underlying: String) extends AnyVal {
  def firstChar: Char = underlying.charAt(0)
}

implicit class MyNonValueClassString(val underlying: String) {
  def firstCharNonValueClass: Char = underlying.charAt(0)
}

And this code that uses them:

println(42.inc)
println("hello".firstChar)
println("hello".firstCharNonValueClass)

You can compile with -Xprint:flatten to see the desugared version (reformatted here for clarity):

scala.this.Predef.println(
  scala.Int.box(Demo$MyInt.this.inc$extension(Demo.this.MyInt(42)))
);

scala.this.Predef.println(
  scala.Char.box(
    Demo$MyString.this.firstChar$extension(Demo.this.MyString("hello"))
  )
);

scala.this.Predef.println(
  scala.Char.box(
    Demo.this.MyNonValueClassString("hello").firstCharNonValueClass()
  )
);

As you can see, the firstChar call doesn't involve a new object.

like image 171
Travis Brown Avatar answered Nov 01 '22 22:11

Travis Brown