3

I have the following code and I wonder if the nasty thing could be removed. Override doesn't work if I add implicit parameter.

class FromEnumFormat[T <: Enum[T]] extends JsonFormat[T] {
  override def read(json: JsValue): T = readit(json)

  def readit(json: JsValue)(implicit m: Manifest[T]): T = {

    val EnumerationClass = m.runtimeClass.asInstanceOf[Class[T]]

    json match {
      case s: JsString if EnumerationClass.getEnumConstants.map(_.toString.toLowerCase).contains(s) => Enum.valueOf(EnumerationClass, s.value.toUpperCase()).asInstanceOf[T]
      case unknown => deserializationError(s"unknown Status: $unknown")
    }
  }

  override def write(obj: T): JsValue = JsString(obj.name().toLowerCase)
}

Is there a way how to get rid of this line

override def read(json: JsValue): T = readit(json)

The question is essentially: Are the implicit parameters part of method signature?

UPDATE: Code doesn't compile. So correct solution should be:

class FromEnumFormat[T<: Enum[T]] extends JsonFormat[T] {

 implicit val m: Manifest[T] = ???

  override def read(json: JsValue): T = {

    val EnumerationClass  = m.runtimeClass.asInstanceOf[Class[T]]

    json match {
      case s :JsString if EnumerationClass.getEnumConstants.map(_.toString.toLowerCase).contains(s) => Enum.valueOf(EnumerationClass ,s.value.toUpperCase()).asInstanceOf[T]
      case unknown => deserializationError(s"unknown Status: ${unknown}")
    }
  }

  override def write(obj: T): JsValue = {JsString(obj.name().toLowerCase)}
}

The question is how to access Manifest? I am using Scala 2.10

UPDATE: Find that the issue is with scala reflection not with implicits and overrides, hence closing this question.

3 Answers 3

2

To answer your question, yest, implicit parameters are part of method signature. However, as it is implicit, this means you can call the def readit(json: JsValue)(implicit m: Manifest[T]): T function without mentioning it, as long as it has been declared somewhere in the code :

implicit val manifest = /* whatever a Manifest is*/
readit(jsonValue)

Could you please provide an example of what you'd like to do ?

Sign up to request clarification or add additional context in comments.

6 Comments

Yea, tried that. But wasn't able to find the way how to get Manifest :-)
That's another problem :) You absolutely need a reference it to make it work.
Actually, does the code that you provided compile ?
Actually NO, "No Manifest available for T." As there is no Manifest value available in the scope
So that means that "call through" doesn't make any sense
|
2

Your final solution is nearly correct, but it has m in the wrong place, it should be a class parameter instead:

class FromEnumFormat[T<: Enum[T]](implicit m: Manifest[T]) extends JsonFormat[T] {

  override def read(json: JsValue): T = {

    val EnumerationClass  = m.runtimeClass.asInstanceOf[Class[T]]

    json match {
      case s :JsString if EnumerationClass.getEnumConstants.map(_.toString.toLowerCase).contains(s) => Enum.valueOf(EnumerationClass ,s.value.toUpperCase()).asInstanceOf[T]
      case unknown => deserializationError(s"unknown Status: ${unknown}")
    }
  }

  override def write(obj: T): JsValue = {JsString(obj.name().toLowerCase)}
}

This way the compiler can insert it when creating a FromEnumFormat with a specific enum:

val format = new FromEnumFormat[TimeUnit]

If you want to create a generic FromEnumFormat[T], though, you'll have to pass implicit m: Manifest[T] as an argument:

def doSomethingWithFormat[T <: Enum[T]](implicit m: Manifest[T]) = {
  val format = new FromEnumFormat[T]
  ...
}

Comments

1

Implicit parameters are not exactly part of the signature. But So you cannot add an implicit parameter by means of overloading.

Here's why. Multiple parameter list syntax is just a syntactic sugar. The code

def readit(json: JsValue)(implicit m: Manifest[T]): T = ???

gets desugared to

def readit(json: JsValue): Function1[Manifest[T], T] = {
  def inner(implicit m: Manifest[T]): T = ???
  inner
}

So as you see the real type of readit just doesn't match the type of read, thus it is not a proper override.

UPD.

As Alexey pointed out formally multiple parameter list contributes to type signature (see section 4.6 Function Declarations and Definitions of scala spec).

A function declaration has the form def fpsig: T, where f is the function's name, psig is its parameter signature and T is its result type.

A parameter signature consists of an optional type parameter clause [tps], followed by zero or more value parameter clauses (ps1)…(psn).

5 Comments

"Implicit parameters are not exactly part of the signature." Yes, they are.
@AlexeyRomanov, would you mind elaborating a bit? You've seen my arguments, I would like to see yours.
Well, you can just look at the definition of signature in section 4.6 of scala-lang.org/files/archive/spec/2.11/…. The "desugaring" is also incorrect (e.g. readit[Int](value) in the first case would have type Int, in the second it would be Manifest[Int] => Int).
Ok, point taken. Thank you for the reference. As for the "incorrect desugaring" let's refer to the section 3.9 Function Types of the same spec to find the confirmation that Manifest[T] => T is a shorthand for (Manifest[T]) => T which is in turn shorthand for Function1[Manifest[T], T].
Er, yes. My point is that Manifest[Int] => Int is different from Int. If it was the desugaring, expressions referring to both versions of readit should have the same type and result.

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.