1
votes

In my DSL I want this functionality:

class Test {

  val compA = dependant(true, true)(Component("parameters"))

  //and this shortcut:

  val compB = dependant Component("parameters")
}

where:

def dependant(onEnable: Boolean, onDisable: Boolean)(c: Component): Component = {
   //...
}

def dependant(c: Component): Component = dependant(false, true)(c)

all is fine, however, I cannot use this syntax:

val compB = dependant Component("parameters")

because it says

ambiguous reference to overloaded definition, both method dependant in class Test of type (onEnable: Boolean, onDisable: Boolean)(c: Component)Component and method dependant in class Test of type (c: Component)Component match expected type ?

But if I enclose the parameter in parenthesis:

val compB = dependant(Component("parameters"))

the error is gone. Obviously, the compiler fails in desugarating the parenthesisless case. Is this expected or am I doing something wrong? If this is expected, then Why? How can I reclaim the ability to use the method dependant as a prefix, without parenthesis?

2

2 Answers

2
votes

In dependant Component("parameters") you are trying to use a prefix notation to call the dependant. Scala's support for prefix notation is limited.

See Scala - Prefix Unary Operators.

An alternative is to use a postfix notation (as in Component("parameters") dependant). If you can modify the implementaiton of Componenet, this simply means adding the dependant methods to Component:

class Component(name: String) {
  def dependant: Component = //...
  def dependant(onEnable: Boolean, onDisable: Boolean): Component = {
    //...
  }    
}

class Test {
  val compA = Component("parameters") dependant(true, true)
  val compB = Component("parameters") dependant
}

If you can't modify Component, you can use the "pimp my library idiom". See http://www.decodified.com/scala/2010/12/02/the-quickpimp-pattern.html for a short introduction to this idiom (along with a warning on using an anonymous class as below):

case class Component(name: String)

implicit def toPostifxDependentOps( c: Component ) = new {
  def dependant: Component = dependant(false, true)
  def dependant(onEnable: Boolean, onDisable: Boolean): Component = {
    //...
  }
}

class Test {
  val compA = Component("parameters") dependant(true, true)
  val compB = Component("parameters") dependant
}
2
votes

Writing myObject functionName paraminstead of myObject.functionName(param) works as expected if you propvide an object. If you don't, the compiler will be lost. For example:

scala> println("Hello")
Hello

scala> println "Hello"
<console>:1: error: ';' expected but string literal found.
       println "Hello"
           ^

A possible workaround: create an object to wrap your method:

scala> case class Component(name: String, components: Option[Component] = None)
defined class Component

scala> object depends {def on(c: Component) = Component("dependant", Some(c))}
defined module depends

scala> depends on Component("foo")
res3: Component = Component(dependant,Some(Component(foo,None)))