简体   繁体   中英

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?

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 eg pass WithExtraData[ExternalType1] whenever ExternalType1 is required.

You basically try to enrich your types with additional type information represented by values if I understand you correct? In that case, the concept you looking for is called Dependent Types

Scala does not support this concept natively (like for example Idris). However, there are some workarounds to get closer.

One example would be to use Shapeless

import shapeless._
import SingletonTypes._

val test1: ^((20 + 50) > 1) = true
test1: Boolean(true) = true

val test2: ^((20 + 50) > 1) = false
<console>:11: error: type mismatch;
 found   : Boolean(false)
 required: Boolean(true)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM