2

In my application, I have a closed set of operations that return a corresponding set responses as shown below.

sealed trait OperationCompletionResponse {
    val state: Int
}
case class ExecutionStartedResponse(state: Int) extends OperationCompletionResponse
case class UpdateRecordedResponse(state: Int) extends OperationCompletionResponse
case class ExecutionTerminatedResponse(state: Int) extends OperationCompletionResponse

sealed trait Operation {
    type R
    def createResponse(state: Int): R
}

case class StartExecutionOperation() extends Operation {
    type R = ExecutionStartedResponse
    override def createResponse(state: Int): ExecutionStartedResponse = ExecutionStartedResponse(state)
}

case class RecordUpdateOperation() extends Operation {
    type R = UpdateRecordedResponse
    override def createResponse(state: Int): UpdateRecordedResponse = UpdateRecordedResponse(state)
}

case class TerminateExecutionOperation() extends Operation {
    type R = ExecutionTerminatedResponse
    override def createResponse(state: Int): ExecutionTerminatedResponse = ExecutionTerminatedResponse(state)
}

As far as my understanding of type members and type projection go, I can do the following. They're perfectly valid statements according to scala compiler

val esr:StartExecutionOperation#R = ExecutionStartedResponse(1)
val teo:TerminateExecutionOperation#R = ExecutionTerminatedResponse(-1)
val ruo:RecordUpdateOperation#R = UpdateRecordedResponse(0)

However, I would now like to use them in a function; which is often more useful. Now, how would I specify the output type as a dependent type?

def updateState[O <: Operation](operation: O) = operation match {
    case StartExecutionOperation() =>  ExecutionStartedResponse(1)
    case TerminateExecutionOperation() => ExecutionTerminatedResponse(-1)
    case RecordUpdateOperation() => UpdateRecordedResponse(0)
}

More specifically, I do not want the return type of the function in my case to be OperationCompletionResponse but something like Operation#R or operation.R

How can I accomplish that?

Viswanath
  • 881
  • 7
  • 20

1 Answers1

2

The path-dependent type of updateState will be directly linked to the type of operation. You don't want to match operation in the body, because this will never give you the type R you're looking for.

You defined exactly one operation that gives you this R and that's createResponse. Because createResponse expects an integer argument, you have to somehow give it in updateState. It appears you have some default state for each of the operations, so you could define that def defaultState: Int Operation and then have

def updateState(op: Operation): op.R = op.createResponse(op.defaultState)` 

If this doesn't answer you question, please edit it to be more specific about what exactly you are trying to achieve with this state.

francoisr
  • 3,812
  • 1
  • 24
  • 44
  • I do not have a default state. The integer values there are for demonstration purposes.Nevetheless, The most important point here is that one shouldn't use pattern match otherwise the dependent type would be lost so, I'll be pleased to accept your answer. – Viswanath Mar 28 '19 at 16:06