2011-09-29 20 views
16

Soy nuevo en Scala. Me pregunto si es posible definir alguna prioridad con las llamadas a métodos. Por ejemplo, si tengo la cadena de llamadas a métodos:Scala - Precedencia del método

someObject method1 param1 method2 param2 method3 param3 

puede esto ser equivalente a lo siguiente:

someObject.method1(param1).method2(param2.method3(param3)) 

o

someObject method1 param1 method2 (param2 method3 param3) 

así que quiero metodo3 tenga prioridad con respecto method2 ...

La razón por la que quiero hacer esto es porque quiero desarrollar una DSL, por lo que quiero evitar el uso puntos y paréntesis tanto como sea posible. Si ustedes encuentran otra solución para mí, no duden en avisarme.

+2

Es posible que desee leer http://www.manning.com/ghosh/ (DSL en Acción), ya que ayudará a explicar mucho. Cubre Ruby, Scala (principalmente Scala), Clojure y Groovy. –

Respuesta

3

Este comportamiento se define en el capítulo 6.12.3 Infix Operations de The Scala Language Specification.

En resumen: los métodos se invocan de izquierda a derecha de forma predeterminada con algunas excepciones. Estas excepciones solo se introdujeron para admitir la precedencia de los operadores matemáticos. Así que cuando usted tiene dos funciones con nombre * y +:

a + b * c 

Esto siempre será traducido a:

a.+(b.*(c)) 

Aquí el primer nombre de la función controla la precedencia. Sin embargo, para las funciones normales no puedes controlar el orden. Piénselo, esto causaría estragos y un código terriblemente inmanejable.

Ver también (¿no del todo duplicado?): Operator precedence in Scala.

+1

Tenga en cuenta que la especificación es incorrecta - vea http://article.gmane.org/gmane.comp.lang.scala/24402 y http://stackoverflow.com/questions/7022207/why-scala-changed-relative-precedence -of-relational-vs-equality-operators-compar/7022704 # 7022704. – huynhjl

11

Tendrá que utilizar métodos con caracteres de operador especiales para influir en la precedencia según lo implícito en Tomasz. Esto es en parte por qué muchos Scala DSL hacen un uso intensivo de los operadores. También por qué algunos DSL son difíciles de leer si no trabajas con ellos a diario.

Dada método con el uso de sólo letras, dígitos y subrayan - no serán capaces de influir en las cosas, esto es lo que junté para mí después de leer la especificación:

  • Cualquier método que toma un solo parámetro se puede utilizar como un operador infijo: a.m(b) se puede escribir a m b.
  • Cualquier método que no requiera un parámetro se puede utilizar como operador de postfijo: a.m puede escribirse a m.

  • operadores de sufijo tienen menor precedencia que operadores infijos, por lo foo bar baz significa foo.bar(baz) mientras foo bar baz bam significa (foo.bar(baz)).bam y foo bar baz bam bim significa (foo.bar(baz)).bam(bim).

Así que sin saber en absoluto lo que sus firmas de los métodos son, el siguiente código (porque es todos los caracteres alfanuméricos):

someObject method1 param1 method2 param2 method3 param3 

serán analizados como:

someObject.method1(param1).method2(param2).method3(param3) 

Si cambia el nombre method3 a |*| o +:+ o cualquier operador tiene sentido, puede lograr lo que quiere:

someObject method1 param1 method2 param2 |*| param3 
// same as 
someObject.method1(param1).method2(param2.|*|(param3)) 

Por ejemplo, para ver la diferencia:

implicit def pimp(s:String) = new { 
    def |*|(t:String) = t + s 
    def switch(t:String) = t + s 
} 

scala> "someObject" concat "param1" concat "param2" |*| "param3" 
res2: java.lang.String = someObjectparam1param3param2 

scala> "someObject" concat "param1" concat "param2" switch "param3" 
res3: java.lang.String = param3someObjectparam1param2 
+0

Tu respuesta es muy útil :). Pero realmente quiero que mi DSL sea fácil de entender e intuitiva, así que no puedo usar métodos con caracteres no alfanuméricos. ¿Hay alguna manera de mezclar letras y caracteres no alfanuméricos para un nombre de método? – Peter

+0

@ Peter, no de una manera que sea útil. Puede nombrar un método 'foo_?' O 'foo _ #% ^', pero es la primera letra del método que determina la precedencia y si el nombre del método comienza con un carácter de operador, debe estar compuesto enteramente por caracteres de operador. Tenga en cuenta que la DSL aún puede ser intuitiva si usa caracteres especiales, pero debe tener cuidado. Por ejemplo, encuentro que la mayoría de los operadores en http://www.scala-lang.org/api/current/scala/sys/process/ProcessBuilder.html son fáciles de recordar, mientras que tengo dificultades con http: // dispatch .databinder.net/Two + Handlers + Are + Better + Than + One.html. – huynhjl