Scala DSL, Object and infix notation
Asked Answered
E

2

6

in Scala, if I want to implement a DSL, is there a way to do the following:

I have an Object called "Draw" which contains the function def draw(d:Drawable)

how can I make it so that I can import the Object and call it outside the object like:

draw ball

if ball extends the Drawable trait? The problem is that I want to use draw in a kind of infix notation, but I dont want to qualify the function draw by denoting it's implementing class/object.

Encephaloma answered 19/5, 2010 at 18:40 Comment(1)
The following thread may shed some light on it: #1007467 To summarize: only ~, !, - and + can be used for infix or unary operators, but not draw.Marler
M
3

I quickly tried it out, but could quite make it work using an object. There I had to use draw(ball) instead of draw ball, as you wanted:


Welcome to Scala version 2.8.0.RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).

scala> trait Drawable{def doSomething} defined trait Drawable

scala> object Draw {
def draw(d:Drawable) = d.doSomething } defined module Draw

scala> val ball = new Drawable{def doSomething = println("doing ball")} ball: java.lang.Object with Drawable = $anon$1@3a4ba4d6

scala> import Draw._ import Draw._

scala> draw ball :11: error: missing arguments for method draw in object Draw; follow this method with `_' if you want to treat it as a partially applied function draw ball ^

scala> draw(ball) doing ball

However by defining Draw as a class, it did work:


scala> trait Drawable{def doSomething: Unit}
defined trait Drawable

scala> class Draw {
def draw(d:Drawable) = d.doSomething } defined class Draw

scala>

scala> val ball = new Drawable{def doSomething = println("doing ball")} ball: java.lang.Object with Drawable = $anon$1@36a06816

scala> val d = new Draw d: Draw = Draw@7194f467

scala> d draw ball doing ball

I'm not completely sure why this doesn't work the same way with an object, might be a bug or perhaps that's specified behaviour. However I didn't have the time to look it up at the moment.

Michellemichels answered 19/5, 2010 at 19:32 Comment(3)
The problem with your first version is that Scala's "operator notation" needs an explicit receiver, that's why the class example works.Millstone
I think draw(ball) could be acceptable syntax. I would have something like draw(ball) at (x,y,z) on someOpenGlPanel. It is just a test of doing a small DSL anyway :) Thanks for your answer. Btw: maybe one could accept some filler symbol like Draw -> ball or whatever...back to thinking :)Encephaloma
Another option would be to rename the draw method to "the". In this way your example would become: "Draw the ball"Fructification
S
6

You can't do it. Aside from four prefix operators, in any operator notation the first token represents the object.

Stegman answered 19/5, 2010 at 21:2 Comment(1)
Actually, Felix could do it by making draw an object and ball a method of an anonymous class of an implicit conversion that referenced the real object. I doubt he, or anyone else, would prefer that, so +1 for this answer.Logway
M
3

I quickly tried it out, but could quite make it work using an object. There I had to use draw(ball) instead of draw ball, as you wanted:


Welcome to Scala version 2.8.0.RC2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).

scala> trait Drawable{def doSomething} defined trait Drawable

scala> object Draw {
def draw(d:Drawable) = d.doSomething } defined module Draw

scala> val ball = new Drawable{def doSomething = println("doing ball")} ball: java.lang.Object with Drawable = $anon$1@3a4ba4d6

scala> import Draw._ import Draw._

scala> draw ball :11: error: missing arguments for method draw in object Draw; follow this method with `_' if you want to treat it as a partially applied function draw ball ^

scala> draw(ball) doing ball

However by defining Draw as a class, it did work:


scala> trait Drawable{def doSomething: Unit}
defined trait Drawable

scala> class Draw {
def draw(d:Drawable) = d.doSomething } defined class Draw

scala>

scala> val ball = new Drawable{def doSomething = println("doing ball")} ball: java.lang.Object with Drawable = $anon$1@36a06816

scala> val d = new Draw d: Draw = Draw@7194f467

scala> d draw ball doing ball

I'm not completely sure why this doesn't work the same way with an object, might be a bug or perhaps that's specified behaviour. However I didn't have the time to look it up at the moment.

Michellemichels answered 19/5, 2010 at 19:32 Comment(3)
The problem with your first version is that Scala's "operator notation" needs an explicit receiver, that's why the class example works.Millstone
I think draw(ball) could be acceptable syntax. I would have something like draw(ball) at (x,y,z) on someOpenGlPanel. It is just a test of doing a small DSL anyway :) Thanks for your answer. Btw: maybe one could accept some filler symbol like Draw -> ball or whatever...back to thinking :)Encephaloma
Another option would be to rename the draw method to "the". In this way your example would become: "Draw the ball"Fructification

© 2022 - 2024 — McMap. All rights reserved.