2

My function gets another function (which is mapping input type to output type) as parameter:

type Handled[S,R] = S => R

def myFunc[S,R](value: S, handled: Handled[S,R] = defaultHandled): R = {
  handled(value)
}

I need to write defaultHandled function which will get input type and return it as is.

So by default i want to map input type to output type where input type is the same as output type. This function should simply pass input to output for any input type. How to do it?

3 Answers 3

5

While technically this is possible:

type Handled[S, R] = S => R

def defaultHandled[S, R](x: S): R = x.asInstanceOf[R]

def myFunc[S, R](value: S, handled: Handled[S, R] = defaultHandled[S, R] _): R = {
  handled(value)
}

myFunc[Int, Int](1)

It's not type safe and generally not a good idea. For example, if you try to call myFunc with different type parameters while still relying on default handled value, you'll get runtime exception:

myFunc[Int, String](1)

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

Scala way to address this is to have handled as implicit parameter. In this case you can supply default implementation which compiler will use it possible.

type Handled[S, R] = S => R

implicit def defaultHandled[S]: Handled[S, S] = identity

def myFunc[S, R](value: S)(implicit handled: Handled[S, R]): R = {
  handled(value)
}

myFunc(1) // compiles and works

myFunc[Int, String](1) // compilation error: Error:(11, 21) No implicit view 
                       // available from Int => String.
                       //myFunc[Int, String](1)
                       //            ^
Sign up to request clarification or add additional context in comments.

Comments

2

I'd say that for this specific case there is a simple solution which achieves exactly the result you want: just replace the default parameter by an overload.

type Handled[S,R] = S => R

def myFunc[S,R](value: S, handled: Handled[S,R]): R = {
  handled(value)
}

def myFunc[S](value: S): S = value

Comments

0

If S and R are two arbitrary types (that don't depend on each other) then I guess it's impossible (without run-time casting). You should provide defaultHandled for every S, R. And s => s is of type S => S, not S => R for arbitrary R.

But if type R depends on type S then you can consider doing the following:

  trait Handled[S] {
    type R
    def apply(s: S): R
  } 
  object Handled {
    type Aux[S, R0] = Handled[S] {type R = R0}
    def apply[S, R0](f: S => R0): Aux[S, R0] = new Handled[S] {
      override type R = R0
      override def apply(s: S): R = f(s)
    }
  }


  def myFunc[S](value: S, handled: Handled[S] = Handled[S, S](s => s)): handled.R = {
    handled(value)
  }

Here Handled[S] (on contrary to Handled.Aux[S, R]) is an existential type.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.