Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there are way to create a generic class with a trait or mixin that is a subtype of the type parameter

I am trying to attach extra data to other types, and have a trait similar to:

trait ExtraData {
  def getExtraData() : Array[Byte]
}

And I'm currently using it like this:

class ExternalType1WithExtraData(superType:ExternalType1, bytes:Array[Byte]) extends ExternalType1(superType.a,superType.b, ...) with ExtraData {
  def getExtraData() : Array[Byte] = bytes
}

class ExternalType2WithExtraData(superType:ExternalType2, bytes:Array[Byte]) extends ExternalType2(superType.z,superType.w, ...) with ExtraData {
  def getExtraData() : Array[Byte] = bytes
}

It seems like there would be a generic way to create these classes, but I haven't been able to find it yet.

--- Begin Edit -- Adding desired behavior

Given a function

def sendData(ex : ExternalType1)

I want to be able to pass my enhanced types to that function.

val data:ExternalType1 = ???
val moredata:ExternalType1 = { new ExternalType1 with ExtraData{...} }
sendData(moredata)

--- End Edit

I've tried to do things along these lines but have had no success:

// Compiler wont let me extend T
class WithExtraData[T](bytes:Array[Byte]) extends T with ExtraData{
  def getExtraData() : Array[Byte] = bytes
}

:12: error: class type required but T found class WithExtraDataT extends T with ExtraData{ ^ :12: error: illegal inheritance; supertype T is not a subclass of the superclass Object of the mixin trait ExtraData class WithExtraDataT extends T with ExtraData{

// Seems closer, but doesn't work.
class WithExtraData[T](t:T, bytes:Array[Byte]) extends ExtraData {
  this : T => t
  def getExtraData() : Array[Byte] = bytes
}

:13: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses self : T => t ^ defined class WithExtraData

scala> new WithExtraData[String]("hi", new ArrayByte) :13: error: class WithExtraData cannot be instantiated because it does not conform to its self-type WithExtraData[String] with String

Is there a way to achieve this?

like image 339
Austin Harris Avatar asked Dec 05 '25 20:12

Austin Harris


1 Answers

I think that the closest you can reasonably get (at least without macros) is not to extend ExternalType1, but to have an implicit conversion instead:

class WithExtraData[T](val value: T, bytes: Array[Byte]) extends ExtraData {
  def getExtraData(): Array[Byte] = bytes
}

object WithExtraData {
  implicit def getValue[T](x: WithExtraData[T]): T = x.value
}

Then you can e.g. pass WithExtraData[ExternalType1] whenever ExternalType1 is required.

like image 176
Alexey Romanov Avatar answered Dec 08 '25 14:12

Alexey Romanov