I am trying to define facade for : https://facebook.github.io/jest/docs/en/api.html#testonlyname-fn
#JSGlobalScope
#js.native
object JestGlobal extends js.Object {
def test(str: String, function: js.Function0[_]): Unit = js.native
#JSName("test.only")
def testOnly(str: String, function: js.Function0[_]): Unit = js.native
def expect[T](in:T) : Matcher[T] = js.native
}
#js.native
trait Matcher[T] extends js.Object {
def toBe(in:T):Unit = js.native
}
Calling a method of the global scope whose name is not a valid
JavaScript identifier is not allowed. [error] See
https://www.scala-js.org/doc/interoperability/global-scope.html for
further information.
Edit:(Answer)
def test : JestTestObject = js.native
#js.native
trait JestTestObject extends js.Object {
def only(str: String, function: js.Function0[_]): Unit = js.native
}
For all practical purposes, there is no such thing as a JS function whose name is test.only. It is much more likely that there is a top-level object whose name is test, and it has a method named only. You can model that as:
#js.native
#JSGlobal("test")
object JestTest extends js.Object {
def only(str: String, function: js.Function0[_]): Unit = js.native
}
You can also use the same object to represent the top-level function whose name is test (because apparently the library is presented so), by adding an apply method:
#js.native
#JSGlobal("test")
object JestTest extends js.Object {
// This is the test(...) function
def apply(str: String, function: js.Function0[_]): Unit = js.native
// This is the test.only(...) function
def only(str: String, function: js.Function0[_]): Unit = js.native
}
Your variant as a self-answer is also valid, but it can be made more idiomatic as follows:
#js.native
#JSGlobalScope
object JestGlobal extends js.Object {
#js.native
object test extends js.Object {
// This is the test(...) function
def apply(str: String, function: js.Function0[_]): Unit = js.native
// This is the test.only(...) function
def only(str: String, function: js.Function0[_]): Unit = js.native
}
def expect[T](in: T): Matcher[T] = js.native
}
Related
Let's say I have this:
trait FormData
case class DepartmentData(id: Long, title: String) extends FormData
and this companion object:
object DepartmentData {
def empty: DepartmentData = ???
def from(value: SomeKnownType): DepartmentData = ???
}
What I would like is to make sure that all the classes implementing the FormData Trait, have the two methods empty and from in their companion object.
I do not think we can do this directly, however try type class solution like so
trait FormData
case class DepartmentData(id: Long, title: String) extends FormData
case class EmployeeData(id: Long, title: String) extends FormData
trait SomeKnownType
trait FormDataFactory[T <: FormData] {
def empty: T
def from(value: SomeKnownType): T
}
object FormDataFactory {
def empty[T <: FormData](implicit ev: FormDataFactory[T]): T = ev.empty
def from[T <: FormData](value: SomeKnownType)(implicit ev: FormDataFactory[T]): T = ev.from(value)
implicit object fooDepartmentData extends FormDataFactory[DepartmentData] {
override def empty: DepartmentData = ???
override def from(value: SomeKnownType): DepartmentData = ???
}
implicit object fooEmployeeData extends FormDataFactory[EmployeeData] {
override def empty: EmployeeData = ???
override def from(value: SomeKnownType): EmployeeData = ???
}
}
Now call
FormDataFactory.empty[DepartmentData]
FormDataFactory.empty[EmployeeData]
Is it possible to define partially parameterize generic implicit class ? For instance assume I have following class
implicit class IoExt[L, R](val io: IO[R]) {
def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] = ???
}
How can I defined something like
type IoExtLocal[R] = IoExt[String, R]
And have IoExtLocal[R] be available as implicit class ?
The motivation is to free client code from specifying type parameter every time wrapped[](..) is called. It gets very verbose.
Just create another implicit class and import necessary one
object ioExt {
implicit class IoExt[L, R](val io: IO[R]) extends AnyVal {
def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] = ???
}
}
object ioExtLocal {
implicit class IoExtLocal[R](val io: IO[R]) extends AnyVal {
def wrapped(errorCode: String): IO[Either[ProcessingResult[String], R]] =
(io: ioExt.IoExt[String, R]).wrapped(errorCode)
}
}
import ioExtLocal._
trait SomeR
val x: IO[SomeR] = ???
x.wrapped(???)
After trying multiple solutions I've found that following works without instantiating helper class on every call to wrapped
trait IoExtTrait[L, R] extends Any {
protected def io: IO[R]
def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] =
io.attempt.map(_.leftMap(ex ⇒ FailureMsg[L](errorCode, Some(ex))))
def wrappedT(errorCode: String): EitherT[IO, ProcessingResult[L], R] =
EitherT(wrapped(errorCode))
}
implicit class IoExtLocalString[R](protected val io: IO[R]) extends AnyVal with IoExtTrait[String, R] {
override def wrapped(errorCode: String) = super.wrapped(errorCode)
}
on the other hand following instantiates helper class on every call
implicit class IoExtLocalString[R](protected val io: IO[R]) extends AnyVal with IoExtTrait[String, R] {}
If anyone know why it happens please let me know. I'm on Scala 2.12.8 (same behavior with 2.13-RC1).
Further conversation at https://github.com/scala/bug/issues/11526 confirmed that allocation happens on both cases. Too bad.
I have tried solutions, described in How to override an implicit value?, but it does not help. Here is a code example.
A definition of TestImplicit abstraction with 2 different implementations (analogue of ExecutionContextExecutor):
trait TestImplicit {
def f(s:String):Unit
}
object TestImplicitImpl1 extends TestImplicit {
override def f(s: String): Unit = println(s"1: $s")
}
object TestImplicitImpl2 extends TestImplicit {
override def f(s: String): Unit = println(s"2: $s")
}
And in the ImplDefinition object a q variable is defined to be used implicitly via import (analogue of ExecutionContext.Implicits.global):
object ImplDefinition {
implicit val q:TestImplicit = TestImplicitImpl1
}
Client that defines a method, accepting TestImplicit implicitly (analogue of scala.concurrent.Future):
trait TestImplicitClient {
def fu(implicit ti:TestImplicit):Unit
}
object TestImplicitClient extends TestImplicitClient {
override def fu(implicit ti: TestImplicit): Unit = {
println("client")
ti.f("param")
}
}
The next step, a client of client, that chooses which implementation of TestImplicit should be used, the decision is done via import (analogue of API that uses Future):
object ClientOfClient {
import somepackage.ImplDefinition.q
def t():Unit =
TestImplicitClient.fu
}
Now in test, I want to use this ClientOfClient.t(), but I need to override implicit, and use TestImplicitImpl2 instead. The main idea behind - implicits should be defined/overridable by the client of API, but not by API itself:
import somepackage.{ClientOfClient, TestImplicit, TestImplicitImpl2}
import org.junit.Test
class ImplTest {
// trying to hide it via import, does not help
import somepackage.ImplDefinition.{q => _,_}
#Test def test(): Unit ={
//trying to hide it via downgrading to non-implicit, does not work either
val q = somepackage.ImplDefinition.q
implicit val ti = TestImplicitImpl2
ClientOfClient.t()
}
}
Each time I run test, I get in the output:
client
1: param
But not expected:
client
2: param
How can I fix it? I need a way to allow clients to override implicits and stay with as simple API as possible. Which means, I do not want to add additional implicit parameter into ClientOfClient.t() method.
As soon as you have a singleton object ClientOfClient with a hard-coded constant TestImplicitImpl1 everywhere, there is essentially nothing you can do. But there are several work-arounds.
1. Use default implicit parameters
object ClientOfClient {
def t()(implicit ti: TestImplicit = ImplDefinition.q): Unit =
TestImplicitClient.fu
}
object ImplTest {
def test(): Unit = {
implicit val ti2 = TestImplicitImpl2
ClientOfClient.t()
}
}
ImplTest.test() // 2: param
2. Supply the implicit through a separate method that can be overridden
If you want to make the implicit overridable, then make ClientOfClient extendable, and create a method (here "cocti") that returns the implicit, instead of importing the implicit directly. You can then override the method (whereas you cannot override an import).
This here produces 2: param in the end of the day:
trait TestImplicit {
def f(s: String): Unit
}
object TestImplicitImpl1 extends TestImplicit {
override def f(s: String): Unit = println(s"1: $s")
}
object TestImplicitImpl2 extends TestImplicit {
override def f(s: String): Unit = println(s"2: $s")
}
object ImplDefinition {
implicit val q: TestImplicit = TestImplicitImpl1
}
trait TestImplicitClient {
def fu(implicit ti: TestImplicit): Unit
}
object TestImplicitClient extends TestImplicitClient {
override def fu(implicit ti: TestImplicit): Unit = {
println("client")
ti.f("param")
}
}
class ClientOfClient {
implicit def cocti: TestImplicit = {
ImplDefinition.q
}
def t():Unit =
TestImplicitClient.fu
}
object ImplTest {
def test(): Unit = {
implicit val ti2 = TestImplicitImpl2
new ClientOfClient {
override def cocti = ti2
}.t()
}
}
ImplTest.test() // 2: param
I am trying to abstract out the json parsing logic that gets triggered for a specific type.
I started out creating a Parser trait as follows:
trait Parser {
def parse[T](payload : String) : Try[T]
}
I have an implementation of this trait called JsonParser which is:
class JsonParser extends Parser {
override def parse[T](payload: String): Try[T] = parseInternal(payload)
private def parseInternal[T:JsonParserLike](payload:String):Try[T] = {
implicitly[JsonParserLike[T]].parse(payload)
}
}
The JsonParserLike is defined as follows:
trait JsonParserLike[T] {
def parse(payload: String): Try[T]
}
object JsonParserLike {
implicit val type1Parser:JsonParserLike[Type1] = new JsonParserLike[Type1]
{
//json parsing logic for Type1
}
implicit val type2Parser:JsonParserLike[Type2] = new JsonParserLike[Type2]
{
//json parsing logic for Type2
}
}
When I try compiling the above, the compilation fails with:
ambiguous implicit values:
[error] both value type1Parse in object JsonParserLike of type => parser.jsonutil.JsonParserLike[parser.models.Type1]
[error] and value type2Parser in object JsonParserLike of type => parser.jsonutil.JsonParserLike[parser.models.Type2]
[error] match expected type parser.jsonutil.JsonParserLike[T]
[error] override def parse[T](payload: String): Try[T] = parseInternal(payload)
Not sure why the implicit resolution is failing here. Is it because the parse method in the Parser trait doesn't have an argument of type parameter T?
I tried another approach as follows:
trait Parser {
def parse[T](payload : String) : Try[T]
}
class JsonParser extends Parser {
override def parse[T](payload: String): Try[T] = {
import workflow.parser.JsonParserLike._
parseInternal[T](payload)
}
private def parseInternal[U](payload:String)(implicit c:JsonParserLike[U]):Try[U] = {
c.parse(payload)
}
}
The above gives me the following error:
could not find implicit value for parameter c: parser.JsonParserLike[T]
[error] parseInternal[T](payload)
[error]
^
Edit: Adding the session from the REPL
scala> case class Type1(name: String)
defined class Type1
scala> case class Type2(name:String)
defined class Type2
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.util.{Failure, Success, Try}
trait JsonParserLike[+T] {
def parse(payload: String): Try[T]
}
object JsonParserLike {
implicit val type1Parser:JsonParserLike[Type1] = new JsonParserLike[Type1] {
override def parse(payload: String): Try[Type1] = Success(Type1("type1"))
}
implicit val type2Parser:JsonParserLike[Type2] = new JsonParserLike[Type2] {
override def parse(payload: String): Try[Type2] = Success(Type2("type2"))
}
}
// Exiting paste mode, now interpreting.
import scala.util.{Failure, Success, Try}
defined trait JsonParserLike
defined object JsonParserLike
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Parser {
def parse[T](payload : String) : Try[T]
}
class JsonParser extends Parser {
override def parse[T](payload: String): Try[T] = parseInternal(payload)
private def parseInternal[T:JsonParserLike](payload:String):Try[T] = {
implicitly[JsonParserLike[T]].parse(payload)
}
}
// Exiting paste mode, now interpreting.
<pastie>:24: error: ambiguous implicit values:
both value type1Parser in object JsonParserLike of type => JsonParserLike[Type1]
and value type2Parser in object JsonParserLike of type => JsonParserLike[Type2]
match expected type JsonParserLike[T]
override def parse[T](payload: String): Try[T] = parseInternal(payload)
As I've already tried to explain in the comments, the problem is that the method
override def parse[T](payload: String): Try[T] = parseInternal(payload)
does not accept any JsonParserLike[T] instances. Therefore, the compiler has no way to insert the right instance of JsonParserLike[T] at the call site (where the type T is known).
To make it work, one would have to add some kind of token that uniquely identifies type T to the argument list of parse. One crude way would be to add a JsonParserLike[T] itself:
import util.Try
trait Parser {
def parse[T: JsonParserLike](payload : String) : Try[T]
}
class JsonParser extends Parser {
override def parse[T: JsonParserLike](payload: String): Try[T] =
parseInternal(payload)
private def parseInternal[T:JsonParserLike](payload:String):Try[T] = {
implicitly[JsonParserLike[T]].parse(payload)
}
}
trait JsonParserLike[T] {
def parse(payload: String): Try[T]
}
object JsonParserLike {
implicit val type1Parser: JsonParserLike[String] = ???
implicit val type2Parser: JsonParserLike[Int] = ???
}
Now it compiles, because the JsonParserLike[T] required by parseInternal is inserted automatically as an implicit parameter to parse.
This might be not exactly what you want, because it creates a hard dependency between Parser interface and the JsonParserLike typeclass. You might want to get some inspiration from something like shapeless.Typeable to get rid of the JsonParserLike in the Parser interface, or just rely on circe right away.
It seems like there is an extra complexity from a mix of different types of polymorphism in both examples. Here is a minimal example of just a type class:
// type class itself
trait JsonParser[T] {
def parse(payload: String): Try[T]
}
// type class instances
object JsonParserInstances {
implicit val type1Parser: JsonParser[Type1] = new JsonParser[Type1] {
def parse(payload: String): Try[Type1] = ???
}
implicit val type2Parser: JsonParser[Type2] = new JsonParser[Type2] {
def parse(payload: String): Try[Type2] = ???
}
}
// type class interface
object JsonInterface {
def parse[T](payload: String)(implicit T: JsonParser[T]): Try[T] = {
T.parse(payload)
}
}
def main(args: Array[String]): Unit = {
import JsonParserInstances._
JsonInterface.parse[Type1]("3")
JsonInterface.parse[Type2]("3")
}
More info:
Chapter on Typeclasses in free Scala with Cats Book
Scala 2.11.4
I have the following trait
trait MyTrait{
def met(msg: String): Unit
}
and class
class MyClass{
def ac(mt: MyTrait) = {
//do some job
}
}
Now, I want to invoke ac as follows:
val myClass = new MyClass
myClass.as((msg: String) => println(msg)) //meaning that just print out Strings to stdout
So, I tried to add implicit conversion to MyTrait:
trait MyTrait {
def met(msgString: String): Unit
implicit def function2MyTrait(f: String => Unit): MyTrait = new MyTraitImpl(f)
private[this] class MyTraitImpl(f: String => Unit) extends MyTrait{
override def met(msgString: String): Unit = f(msgString)
}
}
but it refuses to compile:
Error:(16, 89) type mismatch;
found : String => Unit
required: com.test.trace.MyTrait
I came from Java 8. Is there a way to do such a thing in Scala?
function2MyTrait needs to live in the companion object:
trait MyTrait {
def met(msgString: String): Unit
}
object MyTrait {
implicit def function2MyTrait(f: String => Unit): MyTrait = new MyTraitImpl(f)
private[this] class MyTraitImpl(f: String => Unit) extends MyTrait{
override def met(msgString: String): Unit = f(msgString)
}
}
This will be no longer be necessary in Scala 2.12, as it'll allow using lambdas to implement MyTrait without going through String => Unit.