0
object Helper {

  case class IsMap(x: Map[String,Any])
  case class IsT[T](t: T)

  implicit class MapFunctions(val map: Map[String,Any]) {

    def path[T](path : String*) : Option[T] = {

      if(path.size == 1)
        None

      map.get(path.head).get match {
        case IsMap(item) => item.path(path.tail:_*)
        case IsT(item) => Option(item)
        case _ => throw new Exception("Unexpected type encountered in path")
      }
    }
  }
}

I'm still quite new to Scala. I want to to avoid Option(item.asInstanceOf[T]) in the IsT(item) portion of the pattern matching. I am using case classes to pattern match against parameterized types to stop the type erasure. What I want to do is be able to have IsT(item) match only if item is of type T. Running this code doesn't seem to match on it. What am I doing wrong?

Update: Up until tonight, I thought Scala had magically solved some of the nastier problems with type erasure that Java had. I knew there were still times when type erasure was present but I didn't realize it suffered pretty much the same. I played with the TypeTag a little bit. I was excited by the type interference in Scala and the ability to have it infer the type that I was trying to return but having val myType = path("blah", "blah").get screwed this up because the inferred type is Nothing which would cause a casting error. I ended up solving this the same way I had to solve it in java- have the path() method take Class[T] and use that as the parameterized return type. It's unfortunate... somehow I thought Scala was capable of so much more...

Anyways- my new method looks like this:

object Helper {

  implicit class MapFunctions[K,V](val map: Map[K,V]) {

    def path[T<:V](clazz: Class[T], pathParts: K*): Option[T] = {

      if (pathParts.size == 0)
        None
      else {
        map.get(pathParts.head).get match {
          case im: Map[K, V] if pathParts.size > 1 => im.path(clazz, pathParts.tail: _*)
          case i => Option(i.asInstanceOf[T])
        }
      }
    }
  }
}

Oh... and the purpose of this implicit? My team has spent the better part of a week trying to find a good json library in Scala. We've used json4s previously but aren't happy with the fact that it's container object stores a List of Tuple2 instead of a map and we're heaving on access so this isn't going to work for us. We've reverted to using Jackson and just having it deserialize the json to Map[String,Any]. I found myself doing things where I wanted to cascade down the map like a tree into nested objects and this "path" method just seemed reasonable to be able to do that.

Corey J. Nolet
  • 339
  • 1
  • 4
  • 13
  • I tried moving the case classes inside the path() function in hopes that using the T param for the IsT() class would work. I'm still getting the exception at the bottom of the matcher thrown. – Corey J. Nolet Dec 03 '14 at 01:31
  • But you *are* matching against parameterized types with when you have `case IsT(item) =>`, since `IsT` is a parameterized case class. So type erasure is still present, please see related questions and answers like this: http://stackoverflow.com/a/21640639/1697985 – Akos Krivachy Dec 03 '14 at 02:40
  • 1
    Not completely sure I understand what you're trying to do but shouldn't you be returning `Some(item)` instead of `Option(item)`? – benji Dec 03 '14 at 02:57
  • I think this list business is a bit silly (why are you so worried about these extreme performance cases when you're just starting scala? Have you even benchmarked it?), but did you look at spray-json? You can use `ClassTag`s to match runtime classes and avoid the `asInstanceOf`, e.g. `val c: ClassTag[T]; case c(i) => Some(i)` will have type `Some[T]` as expected, though erasure still makes this not entirely safe. You may want to look at shapeless's type-safe `cast` for a more general solution to your problem that solves the erasure issues. – lmm Dec 03 '14 at 10:57
  • I'm sorry- why would you think it's silly to not want to do an iteration/filter of a list every time I want to grab a value? I've posted the question to others asking why the Json4s devs made this decision and I received the same answers. "It's a bit silly" is really not an answer to me. Why is it okay to iterate/filter a list in this manner? Scala doesn't change the fact that I've turned a constant time operation into an N-time one and I'm really not going to accept the the answer that it's insignificant. What am I missing? What optimizations have been done to make this so insignificant? – Corey J. Nolet Dec 04 '14 at 01:56

0 Answers0