ScalaJS: Facade for polymorphic object - scala.js

I would like to call, from ScalaJS, a JS function similar to the following:
function parseExpression(s){
if(isNumber(s)) return {lit:s}
else{
return {
left : leftOp(s)
oper : operand(s)
right: rightOp(s)
}
}
}
where the returned object can be of two different shapes, either {lit} or {left, oper, right}
I have defined the following traits in ScalaJS:
#js.native
trait NumLiteral extends js.Object{
val lit:String = js.native
}
#js.native
trait NumOper extends js.Object{
val left : NumLiteral | NumOper = js.native
val oper : String = js.native
val right: NumLiteral | NumOper = js.native
}
then I can declare function parseExpression as Function1[String, NumLiteral | NumOper]
What is the best way of checking if the returned value of parseExpression(someExpressionString) is of type NumLiteral or NumOper? I am free to change the JS and/or the Scala code to achieve the most elegant solution.

I solved it by defining the following in ScalaJS:
trait NumExpr
#JSExport
class NumLiteral(val lit:String) extends NumExpr
#JSExport
class NumOper(val left:NumExpr, val oper:String, val right:NumExpr) extends NumExpr
and then redefining my JS function to:
function parseExpression(s){
return isNumber(s) ?
new NumLiteral(s) :
new NumOper(leftOp(s), operand(s), rightOp(s))
}
This lets me pattern-match on parseExpression(someExpressionString)
Of course, this changes the original JS function, and therefore the original question, but it solved my problem.

Related

Is there are way to create a generic class with a trait or mixin that is a subtype of the type parameter

I am trying to attach extra data to other types, and have a trait similar to:
trait ExtraData {
def getExtraData() : Array[Byte]
}
And I'm currently using it like this:
class ExternalType1WithExtraData(superType:ExternalType1, bytes:Array[Byte]) extends ExternalType1(superType.a,superType.b, ...) with ExtraData {
def getExtraData() : Array[Byte] = bytes
}
class ExternalType2WithExtraData(superType:ExternalType2, bytes:Array[Byte]) extends ExternalType2(superType.z,superType.w, ...) with ExtraData {
def getExtraData() : Array[Byte] = bytes
}
It seems like there would be a generic way to create these classes, but I haven't been able to find it yet.
--- Begin Edit -- Adding desired behavior
Given a function
def sendData(ex : ExternalType1)
I want to be able to pass my enhanced types to that function.
val data:ExternalType1 = ???
val moredata:ExternalType1 = { new ExternalType1 with ExtraData{...} }
sendData(moredata)
--- End Edit
I've tried to do things along these lines but have had no success:
// Compiler wont let me extend T
class WithExtraData[T](bytes:Array[Byte]) extends T with ExtraData{
def getExtraData() : Array[Byte] = bytes
}
:12: error: class type required but T found
class WithExtraDataT extends T with ExtraData{
^
:12: error: illegal inheritance; supertype T
is not a subclass of the superclass Object
of the mixin trait ExtraData
class WithExtraDataT extends T with ExtraData{
// Seems closer, but doesn't work.
class WithExtraData[T](t:T, bytes:Array[Byte]) extends ExtraData {
this : T => t
def getExtraData() : Array[Byte] = bytes
}
:13: warning: a pure expression does nothing in statement position; multiline expressions may require enclosing parentheses
self : T => t
^
defined class WithExtraData
scala> new WithExtraData[String]("hi", new ArrayByte)
:13: error: class WithExtraData cannot be instantiated because it does not conform to its self-type WithExtraData[String] with String
Is there a way to achieve this?
I think that the closest you can reasonably get (at least without macros) is not to extend ExternalType1, but to have an implicit conversion instead:
class WithExtraData[T](val value: T, bytes: Array[Byte]) extends ExtraData {
def getExtraData(): Array[Byte] = bytes
}
object WithExtraData {
implicit def getValue[T](x: WithExtraData[T]): T = x.value
}
Then you can e.g. pass WithExtraData[ExternalType1] whenever ExternalType1 is required.
You basically try to enrich your types with additional type information represented by values if I understand you correct? In that case, the concept you looking for is called Dependent Types
Scala does not support this concept natively (like for example Idris). However, there are some workarounds to get closer.
One example would be to use Shapeless
import shapeless._
import SingletonTypes._
val test1: ^((20 + 50) > 1) = true
test1: Boolean(true) = true
val test2: ^((20 + 50) > 1) = false
<console>:11: error: type mismatch;
found : Boolean(false)
required: Boolean(true)

Understanding implicit conversions

I'm reading Scala documentation of implicit conversions and decided to try it out:
object Main extends App {
val test = TestConversion(100)
test.its
}
class Test[T](val t : T) {
def its = println(t)
}
object Test {
def apply[T](t: T): Test[T] = new Test(t)
}
class TestConversion(v : Int) {
val value = v
}
object TestConversion{
implicit def implicitConversionTest2Int(ict : TestConversion): Test[Int] = Test(ict.value)
def apply(v : Int) = new TestConversion(v)
}
As it's said:
To define your own implicit conversions, you must first import
scala.language.implicitConversions (or invoke the compiler with
-language:implicitConversions). The feature must be explicitly enabled because it has pitfalls if used indiscriminately.
I tried it both in IntelliJ and online IdeOne and I didn't add anything special to make it compile.
What pitfalls it brings and why does it work without any imports?
You don't need to import anything.
The idea is that you can declare implicit conversion function wherever you want in the scope.
For example:
case class Coins(amount:Int)
case class Bills(amount:Int)
object Main {
implicit def billsToCoins(bills:Bills):Coins = Coins(bills.amount * 100)
def printCoins(coins:Coins) = println(s"You have ${coins.amount} coins." )
def main(args:Array[String]): Unit ={
printCoins(Bills(3))
}
}
I have declared here implicit function billsToCoins so it is available in scope of the main function. The only thing needed for the function to act as implicit converter is to have the implicit modifier, compiler will find it and use. You see that the printCoins function takes argument of the Coins type but I was able to pass the value of Bills type and it was successfully created.
Here is the console output:
You have 300 coins.
Process finished with exit code 0

JavaScript object as function parameter

I'm writting a function transpiled with Scala.js that should accept any random JavaScript object.
Ex:
// This has been transpiled using Scala.js
var my_service = new com.myself.Service();
// This is plain JavaScript
var result1 = service({ hello: "yolo" });
var result2 = service({ whatever: "ok", really: { yes: "right", no: "don't" } });
However, I can't find the input type that matches it.
What would be the Scala-function signature to get such a thing?
Could it be used then as a "Scala/JS case class" easily?
Note (if it helps giving a direction for the answers): these objects have, in the real life, an expected schema but it cannot be created as JS object generated from Scala.js since it comes from another consumed service.
Since the objects have an expected schema, its probably easiest to define a facade type:
#js.native
trait Args extends js.Object {
val hello: js.UndefOr[String]
val whatever: js.UndefOr[String]
val really: js.UndefOr[ReallyArgs]
}
#js.native
trait Really extends js.Object {
val yes: String
val no: String
}
def myMethod(args: Args): Unit = {
println(args.hello)
println(args.really.map(_.yes))
}

Scala implicit conversion from parent trait

The following code does not compile:
import scala.language.implicitConversions
trait Base {
class Wrp[+T](val v: T) // wrapper / internal representation
}
trait BooleanOps extends Base {
// implicit conversion
implicit def lift2BooleanOpsCls(x: Boolean): BooleanOpsCls =
new BooleanOpsCls(new Wrp[Boolean](x))
class BooleanOpsCls(wx: Wrp[Boolean]) {
def ||(wy: =>Wrp[Boolean]): Wrp[Boolean] = new Wrp[Boolean](wx.v || wy.v)
}
}
trait MyExample extends BooleanOps {
// test method
def foo(): Wrp[Boolean] = {
val ret: Wrp[Boolean] = false || new Wrp[Boolean](true)
ret
}
}
Output:
MyExample.scala:18: error: type mismatch;
found : MyExample.this.Wrp[Boolean]
required: Boolean
val ret: Wrp[Boolean] = false || new Wrp[Boolean](true)
^
But if I:
1) put the class Wrp outside of Base
or
2) move the body of BooleanOps to MyExample
everything compiles.
Why does not the original example work? If you have some insight in this behavior, help would be appreciated. Thank you.
One issue is the call-by-name nature of the argument in the def ||(wy: =>Wrp[Boolean])
if you rewite it to def ||(wy: Wrp[Boolean]) it works
but I agree that it is weird that it works if you move around Wrp or BooleanOpsCls! Intended or bug of implicit resolution??
The original example will work if you rename the || method. The compiler finds the false.||() method and doesn't bother to look for an implicit that might also work there.
The problem is that there is no single class called Wrp (ignore the T for a moment) -- Base does not define Wrp but rather defines a named subclass of each and every concrete class that extends Base. The implicits are a red herring, too. The error that's the giveaway is the mention of MyExample.this.Wrp -- remember that there is no such class even as MyExample -- val x = new MyExample would have type Object with MyExample.

What class is this Builder pattern extending?

I found an interesting scala implementation of Builder pattern, but I can't understand what a few lines mean:
case class Built(a:Int, b:String){}
trait Status
trait Done extends Status
trait Need extends Status
class Builder[A<:Status,B<:Status] private(){
private var built = Built(0,"")
def setA(a0:Int)={
built = built.copy(a=a0)
this.asInstanceOf[Builder[Done,B]]
}
def setB(b0: String) = {
built = built.copy(b = b0)
this.asInstanceOf[Builder[A,Done]]
}
def result(implicit ev: Builder[A,B] <:< Builder[Done,Done]) = built
}
object Builder{
def apply() = new Builder[Need,Need]
}
1) What does private() mean in class Builder[A<:Status,B<:Status] private() class declaration?
2) What is the meaning of implicit ev: Builder[A,B] <:< Builder[Done,Done] in result function?
1)
The private means that the primary constructor for Builder can not be accessed from outside.
Since there are no other constructors, the only way to get an instance is through the companion object with the apply method.
Example:
val builder = Builder()
2)
You have methods in Builder to set both parameters for the Built case-class.
The method result gives you the constructed Built-instance. The evidence makes sure that you have set both parameters and will not allow you to create an instance if you didn't do it.
Example (I did not test this, so please correct me if I am wrong):
val builderA = Builder().setA(3)
val resultA = builderA.result //should not compile because this is Builder[Done, Need]
val builderAB = builderA.setB("hello") //now this is Builder[Done, Done]
val resultAB = builderAB.result //should compile and yield Built(3, "hello")
For your first question, the keyword private in this position means the constructor for the class is private.