How to bind output parameter type to the functon's ouput parameter type - compile error

Say I have these simple classes/objects:

  trait DT[T<: Tuple]
  case class DT1() extends DT[(1,1)]
  object DT2 extends DT[(1,1)]

Using these in the following way works as expected:

  val dt1_0: DT[(1,1)] = new DT[(1,1)] {}
  val dt1_1 = new DT[(1,1)] {}

  def createDT():DT[(1,1)] = DT1()
  val dt1_2 = createDT()

Now say I want to have a generic signature for the create functions:

  def createDT[T <: Tuple, R <: DT[T]]():R = DT1()

I get the error:

error] -- [E007] Type Mismatch Error: /home/VSCodeProjects/pdm_toyadmos/dcase2020/src/examples/djl/autoencoder/SparseEncoder.scala:177:48 
[error] 177 |  def createDT[T <: Tuple, R <: DT[T]]():R = DT1()                 // compile error
[error]     |                                             ^^^^^
[error]     |Found:    examples.djl.autoencoder.SparseEncoder.DT1
[error]     |Required: R
[error]     |
[error]     |where:    R is a type in method createDT with bounds <: examples.djl.autoencoder.SparseEncoder.DT[T]
[error] one error found
[error] one error found

Is this possible? The reason is that I would like to have trait with several methods such the create function. Then I want to extend this trait with specific DTs.

Additionally, this is using OOP style. How would this be done in a more functional style? Maybe this will circumvent the problem above.


That means that the function is able to create any kind of DT for any Tuple type.
So it doesn’t make sense to return just a new DT1.

Maybe it would be easier to explain what is the meta-problem you are trying to solve and why you thought this would be a good solution.

@BalmungSan You are correct ofcourse. The goal is to ensure compile-time consistency among two objects. Working on a micro-example I think I have it nailed down. Here is the example:

  trait DT[T<: Tuple]
  case class DT1() extends DT[(1,1)]
  object DT2 extends DT[(1,1)]

  trait M[T<:Tuple]
  case object M1 extends M[(1,1)]

  trait Exp[T <: Tuple]:
    def load():DT[T]
  end Exp

  object Exp01 extends Exp[Exp01.T]:
    type T = (1,1)

    override def load():DT[T] = DT1()
  end Exp01
  def useDTQ[S <: Tuple, T <: DT[S], U <: M[S]](d: T, m: U) = 
    println(s"$d ~> $m")

  val dt1_3 = Exp01.load()
  useDTQ(dt1_3, M1)

The aim is to ensure that useDTQ uses a DT and an M such that a property, S in this case is the same. I only need the <: constraint on useDTQ, so problem solved.

Maybe the coding of this can be made simpler or clearer?


1 Like

I was under the impression that a case class must have at least one parameter defined. IOW, the 2nd line containing case class DT1() extends DT[(1,1)] should fail to compile, right?

I copied this code and pasted it into Scastie in an attempt to play around with it. However, the Scala 3 compiler seems to be broken as it is returning the error Expected a toplevel definition.

It should work. Try this one. I only added a main.

Awesome! Tysvm. That worked.

And it turns out that a case class can be created with an empty parameters list. I had the fallacious belief that it must have at least one parameter.

What doesn’t work anymore is a case class with no parameter list.

1 Like

IOW, you can have zero parameters, but the empty parenthesis “()” must be explicitly provided.