I've implemented a method withNameOption that returns None if the enumeration member with specific name is not found but I have trouble extracting it to a trait to use it for all the enumerations in the app. At the moment code looks like this:
object FileType extends Enumeration with EnumUtils {
type FileType = Value
def withNameOption(name: String): Option[FileType] = try {
Some(withName(name))
} catch {
case _: NoSuchElementException => None
}
val scala, java, ruby = Value
}
Using this.type wherever possible doesn't typecheck.
I think this is the pattern you're looking for:
trait EnumUtils {
thisenum: Enumeration =>
def withNameOption(name: String): Option[thisenum.type#Value] = try {
Some(thisenum.withName(name))
} catch {
case _: NoSuchElementException => None
}
}
object FileType extends Enumeration with EnumUtils {
type FileType = Value
val scala, java, ruby = Value
}
object Test {
def main(args: Array[String]): Unit = {
println("Python: " + FileType.withNameOption("python"))
println("Scala: " + FileType.withNameOption("scala"))
}
}
What is the specific error you're seeing?
You might prefer to use the "pimp my library pattern" to add this method onto existing Enumerations, rather than using a trait.
Related
I had written a Reads converter in play-json for Option[Option[A]] that had the following behavior:
//given this case class
case class MyModel(field: Option[Option[String]])
//this JSON -- maps to --> this MyModel:
//"{ \"field\": \"value\" }" --> MyModel(field = Some(Some("value")))
//"{ \"field\": null, ... }" --> MyModel(field = Some(None))
//"{ }" --> MyModel(field = None)
So, providing the value mapped to Some[Some[A]], providing null mapped to Some[None] (i.e. Some[Option.empty[A]]), and not providing the value mapped to just None (i.e. Option.empty[Option[A]]). Here's the play-json converter:
def readOptOpt[A](implicit r: Reads[A]): Reads[Option[Option[A]]] = {
Reads[Option[Option[A]]] { json =>
path.applyTillLast(json).fold(
identity,
_.fold(_ => JsSuccess(None), {
case JsNull => JsSuccess(Some(None))
case js => r.reads(js).repath(path).map(a => Some(Some(a)))
})
)
}
}
Now I am converting my play-json code to Circe, but I can't figure out how to write a Decoder[Option[Option[A]] that has the same behavior. That is, I need
def optOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]] = ??? //help!
Any ideas on how I can make this work? Thanks
I figured this out:
There were two problems:
1) How to deal with the case where the field was completely missing from the JSON. Turns out you have to use Decoder.reattempt in your custom decoder, following Circe's decodeOption code, which works.
2) How to have the compiler recognize cases of Option[Option[A]] when your decoder code is sitting in a helper object (or wherever). Turns out if you're using semi-auto derivation, you can create an implicit in the companion object and that will override the defaults:
//companion object
object MyModel {
implicit def myModelOptOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]]] =
MyHelperObject.optOptDecoder
implicit val myModelDecoder: Decoder[MyModel] = deriveDecoder
}
Anyway, I don't think this will be much help to anybody in the future, so unless I get any upvotes in the next few hours I think I'll just delete this.
Edit2: Okay it was answered so I won't delete it. Stay strong, esoteric circe question, stay strong...
An Option[Option[A]] is a bit odd. I understand and mostly agree with the reasoning, but I think it's weird enough that it may warrant just replacing it with your own class (and writing a decoder for that). Something like:
sealed trait OptionalNull[+A] {
def toOption: Option[Option[A]]
}
object NotPresent extends OptionalNull[Nothing] {
override def toOption = None
}
object PresentButNull extends OptionalNull[Nothing] {
override def toOption = Some(None)
}
case class PresentNotNull[A](value: A) extends OptionalNull[A] {
override def toOption = Some(Some(value))
}
This has the additional benefit of not having to worry about implicit precedence and stuff like that. Might simplify your decoder.
Here is another solution I found (This is not my gist):
sealed trait UpdateOrDelete[+A]
case object Delete extends UpdateOrDelete[Nothing]
final case class UpdateOptionalFieldWith[A](value: A) extends UpdateOrDelete[A]
object UpdateOrDelete {
implicit def optionalDecoder[A](implicit decodeA: Decoder[A]): Decoder[UpdateOptionalField[A]] =
Decoder.withReattempt {
// We're trying to decode a field but it's missing.
case c: FailedCursor if !c.incorrectFocus => Right(None)
case c =>
Decoder.decodeOption[A].tryDecode(c).map {
case Some(a) => Some(UpdateOptionalFieldWith(a))
case None => Some(Delete)
}
}
// Random UUID to _definitely_ avoid collisions
private[this] val marker: String = s"$$marker-${UUID.randomUUID()}-marker$$"
private[this] val markerJson: Json = Json.fromString(marker)
implicit def optionalEncoder[A](implicit encodeA: Encoder[A]): Encoder[UpdateOptionalField[A]] =
Encoder.instance {
case Some(Delete) => Json.Null
case Some(UpdateOptionalFieldWith(a)) => encodeA(a)
case None => markerJson
}
def filterMarkers[A](encoder: Encoder.AsObject[A]): Encoder.AsObject[A] =
encoder.mapJsonObject { obj =>
obj.filter {
case (_, value) => value =!= markerJson
}
}
}
The problem is that I have some independent case classes with different fields.
I wanted to write a method that returns instance of the case class of given type with one of parameters changed.
def updateParam[C : ClassTag](c: C, paramName: String, paramValue: Any): C = ...
I took advantage of this answer, but it involves the use of reflection mechanism which is not so beautiful.
Is there a possibility to avoid using reflection or maybe at least hide it under the hood of some library?
If you want to invoke same function on instances of different classes, then it is polymorphism.
If those classes are unrelated, the polymorphism is ad-hoc.
The usual way to implement ad-hoc polymorphism in Scala is by using typeclasses. Here, you can implement the typeclass Copyable:
trait Copyable[C] {
def copy(c: C, paramName: String, value: Any): C
}
and implement your method as follows:
def updateParam[C: Copyable](c: C, paramName: String, paramValue: Any): C = {
implicitly[Copyable[C]].copy(c, paramName, paramValue)
}
Now, if you have two unrelated classes, which somehow ended up unrelated despite the fact that you want to use them in the same context:
case class Foo(paramName: String, foo: Int)
case class Bar(paramName: String, bar: Option[Double])
you can provide type-classes that make them Copyable:
implicit object FooIsCopyable extends Copyable[Foo] {
def copy(f: Foo, paramName: String, value: Any): Foo = {
if (paramName == "paramName") {
f.copy(paramName = value.asInstanceOf[String])
} else if (paramName == "foo") {
f.copy(foo = value.asInstanceOf[Int])
} else {
throw new IllegalArgumentException("Foo has no param `" + paramName + "`")
}
}
}
implicit object BarIsCopyable extends Copyable[Bar] {
def copy(b: Bar, paramName: String, value: Any): Bar = {
if (paramName == "paramName") {
b.copy(paramName = value.asInstanceOf[String])
} else if (paramName == "bar") {
b.copy(bar = value.asInstanceOf[Option[Double]])
} else {
throw new IllegalArgumentException("Bar has no param `" + paramName + "`")
}
}
}
and then use your method like this:
val f = Foo("hello", 42)
val b = Bar("bye", Some(58.0))
println(updateParam(f, "paramName", "hello, world"))
println(updateParam(b, "paramName", "obey"))
which then prints:
Foo(hello, world,42)
Bar(obey,Some(58.0))
However, while you can do this, it's not entirely clear why you would want to. How did it happen that Foo and Bar end up in the same situation, so that you end up with essentially duck-typing, requiring method copy? Maybe you should eliminate the root-cause in the first place.
You might also want to take a look at lenses.
I'm trying to come up with a CSV Parser that can be called like this:
parser parse "/path/to/csv/file" using parserConfiguration
Where the parser will be a class that contains the target case class into which the CSV file will be parsed into:
class CSVParser[A] {
def parse(path: String) = Source.fromFile(fromFilePath).getLines().mkString("\n")
def using(cfg: ParserConfig) = ??? How do I chain this optionally???
}
val parser = CSVParser[SomeCaseClass]
I managed to get up to the point where I can call:
parser parse "/the/path/to/the/csv/file/"
But I do not want to run the parse method yet as I want to apply the configuration using the using like DSL as mentioned above! So there are two rules here. If the caller does not supply a parserConfig, I should be able to run with the default, but if the user supplies a parserConfig, I want to apply the config and then run the parse method. I tried it with a combination of implicits, but could not get them to work properly!
Any suggestions?
EDIT: So the solution looks like this as per comments from "Cyrille Corpet":
class CSVReader[A] {
def parse(path: String) = ReaderWithFile[A](path)
case class ReaderWithFile[A](path: String) {
def using(cfg: CSVParserConfig): Seq[A] = {
val lines = Source.fromFile(path).getLines().mkString("\n")
println(lines)
println(cfg)
null
}
}
object ReaderWithFile {
implicit def parser2parsed[A](parser: ReaderWithFile[A]): Seq[A] = parser.using(defaultParserCfg)
}
}
object CSVReader extends App {
def parser[A] = new CSVReader[A]
val sss: Seq[A] = parser parse "/csv-parser/test.csv" // assign this to a val so that the implicit conversion gets applied!! Very important to note!
}
I guess I need to get the implicit in scope at the location where I call the parser parse, but at the same time I do not want to mess up the structure that I have above!
If you replace using with an operator with a higher precedence than parse you can get it to work without needing extra type annotations. Take for instance <<:
object parsedsl {
class ParserConfig
object ParserConfig {
val default = new ParserConfig
}
case class ParseUnit(path: String, config: ParserConfig)
object ParseUnit {
implicit def path2PU(path: String) = ParseUnit(path, ParserConfig.default)
}
implicit class ConfigSyntax(path: String) {
def <<(config: ParserConfig) = ParseUnit(path, config)
}
class CSVParser {
def parse(pu: ParseUnit) = "parsing"
}
}
import parsedsl._
val parser = new CSVParser
parser parse "path" << ParserConfig.default
parser parse "path"
Your parse method should just give a partial result, without doing anything at all. To deal with default implem, you can use implicit conversion to output type:
class CSVParser[A] {
def parse(path: String) = ParserWithFile[A](path)
}
case class ParserWithFile[A](path: String) {
def using(cfg: ParserConfig): A = ???
}
object ParserWithFile {
implicit def parser2parsed[A](parser: ParserWithFile[A]): A = parser.using(ParserConfig.default)
}
val parser = CSVParser[SomeCaseClass]
ZeroC Ice for Java translates every Slice interface Simple into (among other things) a proxy interface SimplePrx and a proxy SimplePrxHelper. If I have an ObjectPrx (the base interface for all proxies), I can check whether it actually has interface Simple by using a static method on SimplePrxHelper:
val obj : Ice.ObjectPrx = ...; // Get a proxy from somewhere...
val simple : SimplePrx = SimplePrxHelper.checkedCast(obj);
if (simple != null)
// Object supports the Simple interface...
else
// Object is not of type Simple...
I wanted to write a method castTo so that I could replace the second line with
val simple = castTo[SimplePrx](obj)
or
val simple = castTo[SimplePrxHelper](obj)
So far as I can see, Scala's type system is not expressive enough to allow me to define castTo. Is this correct?
Should be able to do something with implicits, along these lines:
object Casting {
trait Caster[A] {
def checkedCast(obj: ObjectPrx): Option[A]
}
def castTo[A](obj: ObjectPrx)(implicit caster: Caster[A]) =
caster.checkedCast(obj)
implicit object SimplePrxCaster extends Caster[SimplePrx] {
def checkedCast(obj: ObjectPrx) = Option(SimplePrxHelper.checkedCast(obj))
}
}
Then you just bring things into scope where you want to use them:
package my.package
import Casting._
...
def whatever(prx: ObjectPrx) {
castTo[SimplePrx](prx) foreach (_.somethingSimple())
}
...
You can get something like what you want with structural types:
def castTo[A](helper: { def checkedCast(o: Object): A })(o: Object) = {
helper.checkedCast(o)
}
class FooPrx { }
object FooPrxHelper {
def checkedCast(o: Object): FooPrx = o match {
case fp : FooPrx => fp
case _ => null
}
}
scala> val o: Object = new FooPrx
o: java.lang.Object = FooPrx#da8742
scala> val fp = castTo(FooPrxHelper)(o)
fp: FooPrx = FooPrx#da8742
I have a helper method:
def controlStructure[T <: SomeObject](exceptions: Class[_]*)(body: => T) = {
try {
val tempObject = body
tempObject.callSomeMethod
Some(tempObject)
} catch {
case e if (exceptions.contains(e.getClass)) => None
}
}
called with:
controlStructure[MySomeObject](classOf[Exception]) { getMySomeObjectSomehow }
the main point of which is to call the 'callSomeMethod' on the entity passed in (for example loaded from ORM), it incidentally wraps things up in exception handling too.
I would now like to add a new method which does the same thing but for a collection (java.util.List) of T.
I am unsure of the syntax, and structures to work with a collection of T in the method signature, and abstract type param definitions.
Thanks for your help.
With a scala list, you are wanting something like this (I think):
def controlStructure[T <: SomeObject](exceptions: Class[_]*)(body: => List[T]) = {
try {
val tempObject = body
tempObject.foreach { _.callSomeMethod() }
Some(tempObject)
}
catch {
case e if (exceptions.contains(e.getClass)) => None
}
}
I haven't worked with Java lists in scala, so I'm guessing you could do it with java.util.List like this:
def controlStructure[T <: SomeObject](exceptions: Class[_]*)(body: => java.util.List[T]) = {
import scala.collection.JavaConversions._
try {
val tempObject = body
tempObject foreach { _.callSomeMethod() }
Some(tempObject)
}
catch {
case e if (exceptions.contains(e.getClass)) => None
}
}
There's no pass by name vararg in Scala. You have to pass a function if you want this. See this ticket of an enhancement request to this effect.
Thanks for your help Mitch. It turns out the answer is in this case to specify the return type of the method, as java.util.List[T], as for once Scala is not using its magic type inference to sort everything out.