Extend object inside of trait in Scala - scala

I've the following code:
trait AcceptExtractors {
/**
* Common extractors to check if a request accepts JSON, Html, etc.
* Example of use:
* {{{
* request match {
* case Accepts.Json() => Ok(toJson(value))
* case _ => Ok(views.html.show(value))
* }
* }}}
*/
object Accepts {
import play.api.http.MimeTypes
val Json = Accepting(MimeTypes.JSON)
val Html = Accepting(MimeTypes.HTML)
val Xml = Accepting(MimeTypes.XML)
val JavaScript = Accepting(MimeTypes.JAVASCRIPT)
}
}
Is there any way to extend the Accepts object?
Thank you!

Nope.
Objects are single values. If they could be extended, they would not be singletons (*). The class generated to represent them is final, so even if you knew its name (not hard to find out), you could not extend it.
(*) Objects are only truly singletons when defined at global scope or nested strictly within other objects leading back to a global one.

No, but you could make Accepts a trait which you can extend.

Related

How does this case class definition allow infix pattern matching?

I recently wrote a parser using scala's parser combinator library. I decided I was curious about the implementation, and went digging.
While reading through the code, I saw that ~ sequencing used a case class to hold the left and right values.
Attached is the following comment:
/** A wrapper over sequence of matches.
*
* Given `p1: Parser[A]` and `p2: Parser[B]`, a parser composed with
* `p1 ~ p2` will have type `Parser[~[A, B]]`. The successful result
* of the parser can be extracted from this case class.
*
* It also enables pattern matching, so something like this is possible:
*
* {{{
* def concat(p1: Parser[String], p2: Parser[String]): Parser[String] =
* p1 ~ p2 ^^ { case a ~ b => a + b }
* }}}
*/
case class ~[+a, +b](_1: a, _2: b) {
override def toString = "("+ _1 +"~"+ _2 +")"
}
Given that such code as mentioned is certainly possible, and that parsers defined using a ~ b can be extracted into values via { case a ~ b => ... }, how exactly does this un-application work? I am aware of the unapply method in scala, but none is provided here. Do case classes provide one by default (I think yes)? If so, how does this particular case class become case a ~ b and not case ~(a,b)? Is this a pattern that can be exploited by scala programmers?
This differs from objects with unapply in this question because no unapply method exists–or does it? Do case classes auto-magically receive unapply methods?
Do case classes provide [unapply] by default (I think yes)?
Your suspicions are correct. unapply() is one of the many things automatically supplied in a case class. You can verify this for yourself by doing the following:
Write a simple class definition in its own file.
Compile the file only through the "typer" phase and save the results. (Invoke scalac -Xshow-phases to see a description of all the compiler phases.)
Edit the file. Add the word case before the class definition.
Repeat step 2.
Compare the two saved results.
From a Bash shell it might look like this.
%%> cat srcfile.scala
class XYZ(arg :Int)
%%> scalac -Xprint:4 srcfile.scala > plainClass.phase4
%%> vi srcfile.scala # add “case”
%%> scalac -Xprint:4 srcfile.scala > caseClass.phase4
%%> diff plainClass.phase4 caseClass.phase4
There will be a lot of compiler noise to wade through, but you'll see that by simply adding case to your class the compiler generates a ton of extra code.
Some of the things to note:
case class instances
have Product and Serializable mixed in to the type
provide public access to the constructor parameters
have methods copy(), productArity, productElement(), and canEqual().
overrides (provides new code for) methods productPrefix, productIterator, hashCode(), toString(), and equals()
the companion object (created by the compiler)
has methods apply() and unapply()
overrides toString()
If so, how does this particular case class become case a ~ b and not case ~(a,b)?
This turns out to be a nice (if rather obscure) convenience offered by the language.
The unapply() call returns a Tuple that can be patterned to infix notation. Again, this is pretty easy to verify.
class XX(val c:Char, val n:Int)
object XX {
def unapply(arg: XX): Option[(Char, Int)] = Some((arg.c,arg.n))
}
val a XX b = new XX('g', 9)
//a: Char = g
//b: Int = 9

Scala implement inline trait method

I've started learning scala and the play framework. I downloaded the sample project from the play framework site. I have a newbie question because I cannot understand the following syntax:
def count = Action { Ok(counter.nextCount().toString) }
What exactly does it do? Action is implemented function in BaseController, where action builder is assigned.
What is the content the beetwen braces for? Wat do the braces mean in this context?
In playframework, requests are handled by Actions. When you invoke Action { ... }, you are actually invoking play.api.mvc.Action helper object to create Action values.
object Action extends ActionBuilder[Request] { ... }
If you look closely to Action object, it extends to play.api.mvc.ActionBuilder trait. This trait contains various overloaded apply methods that creates Action values. Therefore, when you are invoking Action{ ... } you are actually invoking Action.apply({...}) and this apply method is inherited from ActionBuilder trait. If you look into ActionBuilder trait, you will see various higher ordered apply functions.
Now in your case, def count = Action { Ok(counter.nextCount().toString) }
You are actually invoking apply method with default content and no request parameter.
final def apply(block: => Result): Action[AnyContent] = apply(_ => block)
That means, you are providing block { Ok(counter.nextCount().toString) } which return Ok Result.
What is the content the beetwen braces for? Wat do the braces mean in this context?
When you do Action { Ok(counter.nextCount().toString) }, you are actually invoking:
Action.apply(Ok(counter.nextCount().toString))
In scala, apply method is a factory method and therefore you don't have to essentially call apply method, therefore you can also do Action(Ok(counter.nextCount().toString)). Additionally, if your function takes only single parameter, you can replace () brackets with curly braces {}. i.e. you can do Action{Ok(counter.nextCount().toString)}.
I would suggest to look into function literals, higher ordered functions, by-name parameter, method currying etc. So, that you will have more insight in these.
The source code will give you the details:
/**
* Constructs an `Action` with default content, and no request parameter.
*
* For example:
* {{{
* val hello = Action {
* Ok("Hello!")
* }
* }}}
*
* #param block the action code
* #return an action
*/
final def apply(block: => Result): Action[AnyContent] =
apply(BodyParsers.utils.ignore(AnyContentAsEmpty: AnyContent))(_ => block)
It's equivalent to def count = Action.apply(Ok(counter.nextCount().toString))

What's the meaning of new and curly brace (without type to create)?

I found the following definition in Scala Saddle and just want to be sure I understood it correctly. There is an object defining an implicit function that exposes some HDF5 I/O functionality to the Frame type so that the writeHdfFile function becomes available to any Frame:
object H5Implicits {
/**
* Provides enrichment on Frame object for writing to an HDF5 file.
*/
implicit def frame2H5Writer[RX: ST: ORD, CX: ST: ORD, T: ST](frame: Frame[RX, CX, T]) = new {
/**
* Write a frame in HDF5 format to a file at the path provided
*
* #param path File to write
* #param id Name of the HDF group in which to store frame data
*/
def writeHdfFile(path: String, id: String) {
H5Store.writeFrame(path, id, frame)
}
} // end new
}
However, I have never seen the = new { syntax before. Does it mean it is creating and returning a new function each time? why would that make more sense as opposed to simply doing = {
Its a new anonymous class with 1 function.
In this case its used to provide syntax to the frame: Frame[RX, CX, T].
With this helper class in scope you can write.
frame.writeHdfFile(...)
Without this technique you would need to write.
writeHdfFile(frame, ...)
Normally this is done with a implicit class rather than a implicit def like that.
One benefit of this technique is that you can add helper methods to a class without changing them directly. Note how writeHdfFile is not defined on Frame
This is done pretty similar to how type classes are implemented in scala.
it is creating an anonymous class. You can learn more about anonymous classes in scala here

Scala type signature failing with subclasses

I have the following exception hierarchy defined:
/**
* Base class for all exceptions in this library
*/
trait MyAkkaHttpException {}
/**
* Thrown when there is a problem persisting data to a datastore
*/
case class PersistenceException(message: String)
extends Exception(message: String) with MyAkkaHttpException
/**
* Thrown when validation on an object fails
* #param errors
*/
case class ValidationException(message: String, errors: List[String])
extends Exception(message: String) with MyAkkaHttpException
And the following code:
class ContactFormService(contactFormPersistor: ContactFormPersistor) {
def handleForm(contactForm: ContactForm): ValidationNel[MyAkkaHttpException, String] = {
contactForm.validate() match {
case Success(_) => contactFormPersistor.persist(contactForm)
case Failure(e) =>
new ValidationException(message = "Error validating contact form",
errors = e.toList).failureNel[String]
}
}
}
contactFormPersistor.persist returns ValidationNel[PersistenceException, String]
contactForm.validate() returns ValidationNel[String, Boolean]
The problem is handleForm won't accept that PersistenceException and ValidationException are subclasses of MyAkkaHttpException. What do I need to do to make it correctly realise that those return types are valid subclasses?
Try changing ValidationNel[MyAkkaHttpException, String] to Validation[NonEmptyList[MyAkkaHttpException], String]. As someone pointed out in the comments, it's only the type alias that is not covariant in the first type argument.
type ValidationNel[E, +X] = Validation[NonEmptyList[E], X]
Otherwise, NonEmptyList and Validation are both covariant in all their arguments.
EDIT:
This might depend on your version of scalaz. As far as the latest available that I can browse, it looks like ValidationNel is no longer covariant in both arguments, but it previously was. There is probably a good reason for this change: be prepared to not be able to use Scalaz's functions for ValidationNel.
Either is covariant over both the left and right, so I've just switched to that instead.
The problem is you need covariance on the first type parameter of ValidationNel and this particular shortcut of Validation was not designed with this covariance in mind*
Based on the information i gathered from our comment exchange, i believe this is the correct way forward. Declare your own alias (or use the type directly)
type MyValidationNel[+E, +X] = Validation[NonEmptyList[E], X]
*) I do however have a feeling there was a reason behind not having covariance on the E param (as scalaz normally is know to do things with a reason)

Scala case class copy with dynamic named parameter

For scala case class with number of parameters (21!!)
e.g. case class Car(type: String, brand: String, door: Int ....)
where type = jeep, brand = toyota, door = 4 ....etc
And there is a copy method which allow override with named parameter: Car.copy(brand = Kia)
where would become type = jeep, brand = Kia, door = 2...etc
My question is, is there anyway I can provide the named parameter dynamically?
def copyCar(key: String, name: String) = {
Car.copy("key" = "name") // this is something I make up and want to see if would work
}
Is scala reflection library could provide a help here?
The reason I am using copy method is that I don't want to repeat the 21 parameters assignment every time when I create a case class which only have 1 or 2 parameter changed.
Many Thanks!
FWIW, I've just implemented a Java reflection version: CaseClassCopy.scala. I tried a TypeTag version but it wasn't that useful; TypeTag was too restrictive for this purpose.
def copy(o: AnyRef, vals: (String, Any)*) = {
val copier = new Copier(o.getClass)
copier(o, vals: _*)
}
/**
* Utility class for providing copying of a designated case class with minimal overhead.
*/
class Copier(cls: Class[_]) {
private val ctor = cls.getConstructors.apply(0)
private val getters = cls.getDeclaredFields
.filter {
f =>
val m = f.getModifiers
Modifier.isPrivate(m) && Modifier.isFinal(m) && !Modifier.isStatic(m)
}
.take(ctor.getParameterTypes.size)
.map(f => cls.getMethod(f.getName))
/**
* A reflective, non-generic version of case class copying.
*/
def apply[T](o: T, vals: (String, Any)*): T = {
val byIx = vals.map {
case (name, value) =>
val ix = getters.indexWhere(_.getName == name)
if (ix < 0) throw new IllegalArgumentException("Unknown field: " + name)
(ix, value.asInstanceOf[Object])
}.toMap
val args = (0 until getters.size).map {
i =>
byIx.get(i)
.getOrElse(getters(i).invoke(o))
}
ctor.newInstance(args: _*).asInstanceOf[T]
}
}
It is not possible using case classes.
Copy method generated at compile time and named parameters handled on compile time to. There is no possibility to do it ar runtime.
Dynamic may help to solve your issue: http://hacking-scala.tumblr.com/post/49051516694/introduction-to-type-dynamic
Yes, you would need to use reflection to do that.
It is a bit involved, because copy is a synthetic method and you'll have to invoke the getters for all fields except the one you want to replace.
To give you an idea, the copy method in this class does exactly that, except using an argument index instead of name. It calls the companion object's apply method, but the effect is the same.
I'm a bit confused - how is the following not what you need?
car: Car = ... // Retrieve an instance of Car somehow.
car.copy(type = "jeep") // Copied instance, only the type has been changed.
car.copy(door = 4) // Copied instance, only the number of doors has changed.
// ...
Is it because you have a lot of parameters for the initial instance creation? In that case, can you not use default values?
case class Car(type: String = "Jeep", door: Int = 4, ...)
You seem to know about both these features and feel that they don't fit your need - could you explain why?