Is it possible to split object definion in several files in scala? - scala

I'm writing a facade to use CreateJS lib in scala, like this
object CreateJS
{
sealed trait EventListener extends js.Object
type EventHandler = js.Function
class DisplayObject extends js.Object
{
}
class Container extends DisplayObject
{
def addChild(item:DisplayObject):Unit = ???
def update():Unit = ???
}
#JSName("createjs.Stage")
class Stage(canvasId:String) extends Container with EventListener
// TODO: Is enum done this way ???
object MovieClip
{
#JSName("createjs.MovieClip")
var INDEPENDENT:String = _
#JSName("createjs.SINGLE_FRAME")
var SINGLE_FRAME:String = _
#JSName("createjs.SYNCHED")
var SYNCHED:String = _
}
#JSName("createjs.MovieClip")
class MovieClip(mode:js.String=MovieClip.INDEPENDENT,startPosition:js.Number=0, loop:js.Boolean=true, labels:js.Object = null) extends DisplayObject
{
def addEventListener(eventName:String, target:EventHandler):Unit = ???
var timeline:TimeLine = _
def gotoAndPlay(where:String):Unit = ???
}
class TimeLine extends js.Object
{
def addTween(tween:Tween):Unit = ???
}
#JSName("createjs.Shape")
class Shape(graphics:Graphics = null) extends DisplayObject
#JSName("createjs.Graphics")
class Graphics extends js.Object
{
def beginFill(color:String):Graphics = ???
def drawCircle(x:js.Number, y:js.Number, r:js.Number):Graphics = ???
}
#JSName("createjs.Ticker")
object Ticker extends js.Object
{
def addEventListener(eventName:String, handler:EventHandler):Unit = ???
def addEventListener(eventName:String, stage:Stage):Unit = ???
}
class Tween extends js.Object
{
def get(item:DisplayObject):Tween = ???
def to(state:js.Dynamic, time:js.Number = 0):Tween = ???
}
#JSName("createjs.Tween")
object Tween extends Tween
/* Load queue */
class Plugin extends js.Object
#JSName("createjs.Sound")
object Sound extends Plugin {
def play(soundId:String):Unit = ???
}
#JSName("createjs.LoadQueue")
class LoadQueue(useXHR:Boolean = true, basePath:String="", crossOrigin:String="") extends js.Object
{
def installPlugin(plugin:Plugin):Unit = ???
def on(event:String, handler:EventHandler):Unit = ???
def addEventListener(event:String, handler:EventHandler):Unit = ???
def loadFile(params:js.Dynamic):Unit = ???
def loadManifest(paramList:js.Array[js.Dynamic]):Unit = ???
}
}
This file becomes just a large pile.
In real createJS these are split in 4 files - easel, tween, sound and preload, each extending base createjs object. Is it possible I do this file separation in scala while keeping everything in CreateJS namespace?
(Maybe such port already exist?)

You can split code in different trait, each one responsible for a coherent aspect (and gathering related functions), each trait in a separate file, then have the public singleton facade object exposing all.
For example with trait A implementing function foo and bar in file A.scala, and trait B with functions oof and rab in file B.scala, then facade object can be declared like object Facade extends A with B.
In this way, I would suggest to declare trait as package private, as they are there only to organise code: private[mypackage] trait A { ... }.

Related

Magnolia: Type derivation fails in case of nested type classes

I am trying to create a serializable trait that has a dependency on type class.
package dsl
import zio.schema._
sealed trait Random[A] {
def generate: A
}
object Random {
case object RandomDouble extends Random[Double] {
override def generate: Double = ???
implicit val RandomDoubleSchema: Schema[Random[Double]] = DeriveSchema.gen[Random[Double]]
}
}
sealed trait DummyExpr[A] {
def eval(value: DummyExpr[A]): A
}
object DummyExpr {
case object DummyTrue extends DummyExpr[Boolean] {
override def eval(value: DummyExpr[Boolean]): Boolean = ???
}
case object DummyFalse extends DummyExpr[Boolean] {
override def eval(value: DummyExpr[Boolean]): Boolean = ???
}
case class DummyOperator[A](random: Random[A], predicate: DummyExpr[Boolean]) extends DummyExpr[A] {
override def eval(value: DummyExpr[A]): A = ???
}
}
object main extends App {
val schemaRandom = DeriveSchema.gen[Random[Double]]
val schemaDummy = DeriveSchema.gen[DummyExpr[Double]]
}
Here is a reproducible link https://scastie.scala-lang.org/3PnmF52hSkuduzGP10wTdg
But type derivation for this fails with the error magnolia: could not find any direct subtypes of trait Random
I am using zio-schema which internally uses magnolia. I tried adding implicit Derivation of typeclass too but that didn't help too.

Making OpenGL's int constants typesafe using type classes

I'm tying to create a typesafe wrapper around lwjgl. Most importantly, I want it to be a compile time error to pass the wrong constants to a function, e.g. calling glEnable(GL_ARRAY_BUFFER). This whould be rather easy if it weren't for different contexts supporting different constants for the same function.
I figured I'd use type classes to model which constants can be passed to which function. I've got a solution but admittedly it's a bit ugly and fails to apply a certain implicit:
trait GlConst { val glConst: Int }
trait GlConstCompanion[C <: GlConst] { val instance: C }
class GlDepthTest private () extends GlConst { val glConst = GL_DEPTH_TEST }
object GlDepthTest extends GlConstCompanion[GlDepthTest] {
val instance = new GlDepthTest
}
class GlLineSmooth private () extends GlConst { val glConst = GL_LINE_SMOOTH }
object GlLineSmooth extends GlConstCompanion[GlLineSmooth] {
val instance = new GlLineSmooth
}
class GlArrayBuffer private () extends GlConst { val glConst = GL_ARRAY_BUFFER }
object GlArrayBuffer extends GlConstCompanion[GlArrayBuffer] {
val instance = new GlArrayBuffer
}
// type class for arguments to glEnable
trait GlEnableCap[T <: GlConst] extends GlConst
object GlContext33 {
implicit object GlDepthTestIsEnableCap extends GlEnableCap[GlDepthTest] {
val glConst = GlDepthTest.instance.glConst
}
implicit object GlLineSmoothIsEnableCap extends GlEnableCap[GlLineSmooth] {
val glConst = GlLineSmooth.instance.glConst
}
def glEnable[T <: GlConst : GlEnableCap](t: T): Unit = println(implicitly[GlEnableCap[T]].glConst)
}
object Test extends App {
import GlContext33._
implicit def constComp2Const[C <: GlConst](cc: GlConstCompanion[C]): C = cc.instance
// works
glEnable(GlDepthTest.instance)
// fails to apply implicit glConstComp2Comp
glEnable(GlDepthTest)
// fails intentionally
glEnable(GlArrayBuffer)
}
Is there a way to get the implicit to work? Or is there an even better way to wrap OpenGL's constants?
As a rule of thumb, don't use implicits if you don't have to.
In this case you can solve it just as well using only type bounds:
// Start writing your ScalaFiddle code here
val GL_DEPTH_TEST = 1
val GL_LINE_SMOOTH = 1
val GL_ARRAY_BUFFER = 1
trait GlConstCap
trait GlEnableConstCap extends GlConstCap
trait GlBufferConstCap extends GlConstCap
trait GlConst[C <: GlConstCap] { val value: Int }
object GlDepthTest extends GlConst[GlEnableConstCap] {
val value = GL_DEPTH_TEST
}
object GlLineSmooth extends GlConst[GlEnableConstCap] {
val value = GL_LINE_SMOOTH
}
object GlArrayBuffer extends GlConst[GlBufferConstCap] {
val value = GL_ARRAY_BUFFER
}
object GlContext33 {
def glEnable[T <: GlConst[GlEnableConstCap]](t: T): Unit = println(t.value)
}
object Test extends App {
import GlContext33._
// works
glEnable(GlDepthTest)
// fails to apply implicit glConstComp2Comp
glEnable(GlDepthTest)
// fails intentionally
glEnable(GlArrayBuffer)
}
Try it out!
Note: You might want to add contravariance to C in GlConst if you want to create deeper inheritance structures of GlConstCap.
I hope this helps.

Spray: Overriding functions in Traits

I'm using Spray and have a Base Route trait which defines a number of functions that should be implemented...
trait ServiceBaseRoute extends HttpService {
def function1():Type
def function2():Type
lazy val serviceBaseRoute = ...
I then mixin this trait to a number of other traits...
trait MyRoute1 extends HttpService
with ServiceBaseRoute {
override def function1():Type = {...}
override def function2():Type = {...}
val myRoute1 = serviceBaseRoute
and...
trait MyRoute2 extends HttpService
with ServiceBaseRoute {
override def function1():Type = {...}
override def function2():Type = {...}
val myRoute2 = serviceBaseRoute
Finally I construct the top level of the route as follows...
trait V1Routes extends HttpService
with MyRoute1
with MyRoute2 {
val v1Routes =
pathPrefix("v1") {
authenticate(...) {
myRoute1 ~ myRoute2
}
}
Compiles fine etc... However when I run this the function overrides of MyRoute2 override those defined in MyRoute1. I am thinking this is because I don't have actual instances of MyRoute1 and MyRoute2 as they are being simply mixed in and since MyRoute2 is added in after MyRoute1 its values overwrite those of MyRoute1?
So what would be the best way to implement this preserving the overrides defined in each trait?
Do I need to define MyRoute1 and MyRoute2 as objects instead?
Thanks
Based on your comments, the aim is to have distinct routes in MyRoute1 and MyRoute2, where each is created by customizing serviceBaseRoute. Since ServiceBaseRoute is customized by two functions, you could make serviceBaseRoute a higher order function and pass the implementations of the two functions to it in the sub traits:
trait ServiceBaseRoute extends HttpService {
def serviceBaseRoute(f1: () => Type, f2: () => Type)= ???
}
trait MyRoute1 extends HttpService
with ServiceBaseRoute {
def f1ImplA(): Type = ???
def f2ImplA(): Type = ???
val myRoute1 = serviceBaseRoute(f1ImplA, f2ImplA)
}
trait MyRoute2 extends HttpService
with ServiceBaseRoute {
def f1ImplB(): Type = ???
def f2ImplB(): Type = ???
val myRoute2 = serviceBaseRoute(f1ImplB, f2ImplB)
}
trait V1Routes extends HttpService
with MyRoute1
with MyRoute2 {
val v1Routes =
pathPrefix("v1") {
authenticate(...)
{
myRoute1 ~ myRoute2
}
}
}

Using trait method in the class constructor

I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}

What is the suggested way to instantiate a js.Object for API wrappers

For the following javascript API wrapper:
#JSName("React")
object React extends js.Object {
def createClass(init: ReactClassInit): ReactClassBuilder = ???
}
What is the suggested what to instantiate the following trait
trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, js.Any]
}
Currently I am doing the following:
val * = js.Dynamic.literal
val init = *(render = new js.ThisFunction0[js.Dynamic, js.Any] {
override def apply(thisArg: js.Dynamic): js.Any = {
React.DOM.div(null, "Hello ", thisArg.props.name)
}
}).asInstanceOf[ReactClassInit]
val HelloMessage = React.createClass(init)
What I don't like about this approach is that there is no type-safety
ensuring that ReactClassInit is instantiated properly.
(Here is all of the code to put things into a better context)
//Work in progress React wrapers
#JSName("React")
object React extends js.Object {
def createClass(init: ReactClassInit): ReactClassBuilder = ???
def renderComponent(cls: ReactClassInstance, mountNode: HTMLElement) = ???
val DOM: ReactDOM = ???
}
trait ReactDOM extends js.Object {
def div(huh: js.Any, something: js.String, propsOrWhat: js.Any) = ???
}
trait ReactClassInstance extends js.Object
trait ReactClassBuilder extends js.Object {
def apply(args: js.Object): ReactClassInstance
}
trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, js.Any]
}
#JSExport
object ReactTodo {
//Some helpers I use.
val * = js.Dynamic.literal
#JSExport
def main() {
helloJonT()
}
//Ideal Typed Example
def helloJonT() {
val init = *(render = new js.ThisFunction0[js.Dynamic, js.Any] {
override def apply(thisArg: js.Dynamic): js.Any = {
React.DOM.div(null, "Hello ", thisArg.props.name)
}
}).asInstanceOf[ReactClassInit]
val HelloMessage = React.createClass(init)
React.renderComponent(HelloMessage(*(name = "Jon").asInstanceOf[js.Object]), document.getElementById("content"))
}
}
Currently, the recommended approach is very close to what you are doing, except that the use of js.Dynamic.literal should be encapsulated in the companion object of your trait (ReactClassInit in your case). You can provide a type-safe apply method in that companion object like this:
trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, js.Any]
}
object ReactClassInit {
def apply(render: js.ThisFunction0[js.Dynamic, js.Any]): ReactClassInit = {
js.Dynamic.literal(
render = render
).asInstanceOf[ReactClassInit]
}
}
which you can then use with:
val init = ReactClassInit(render = { (thisArg: js.Dynamic) =>
React.DOM.div(null, "Hello ", thisArg.props.name)
})
Of course this is still globally unsafe. But there is only one point in your code where you use a cast, and more importantly it is close to the definition of the type. So it is more likely that if you update one, you will update the other.
I know this is not a completely satisfactory solution. But so far in our design of Scala.js we have not yet found a really good solution to this problem.
Two side notes:
1) I strongly advise against using new js.ThisFunctionN { def apply }! It is an accident that this notation works at all. Simply use a lambda like I showed in my example. If the target type is typed as a js.ThisFunctionN already (like in my code), it'll work just like that. If, as was the case in your code, the target type is js.Any (or Any), you'll need to ascribe your lambda with : js.ThisFunction (without digit) to make sure that the compiler treats it as a this-function and not a (non-this-)function, but that's all. To make it clearer, here is how it would have looked with your code:
val init = *(render = { (thisArg: js.Dynamic) =>
React.DOM.div(null, "Hello ", thisArg.props.name)
}: js.ThisFunction).asInstanceOf[ReactClassInit]
2) You probably want your function to be typed as returning Any (or _) instead of js.Any:
trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, Any]
}
Typically when you use js.Any in the result type of js.(This)Function, you mean any value, not any JS value. And Scala's type inference works best with Any in that location.