2012-04-19 20 views
33

¿Existe una mejor práctica para uno sobre el otro? He estado leyendo el libro Scala por Odersky, et al. y parece que el infijo se usa para muchas de las funciones de la API de colecciones, mientras que el punto está reservado para las funciones definidas por el programador.Scala - infijo vs notación de puntos

Respuesta

43

yo personalmente no tienen ninguna regla dura y rápida para esto, pero que tienden a utilizar la notación infija únicamente con los nombres de métodos simbólicos, y la notación de puntos para los alfanuméricos.

notación infija hace que sea incómodo para modificar código más tarde. Aquí hay unos ejemplos.

Imagine que tiene esta línea de código:

xs filter { f } map { g } 

Supongamos que en algún punto de este último en el tiempo que necesita para añadir un toList al final. Lo pones así:

xs filter { f } map { g } toList 

Esto puede causar problemas de inferencia de punto y coma. Para evitar estos problemas, coloque un punto y coma o coloque una nueva línea. Ambas opciones son feas, en mi opinión. Para evitar todas estas tonterías, prefiero ir con xs.filter(f).map(g). Siempre es más fácil refactorizar con esta sintaxis.

Otro ejemplo: Digamos que tiene la siguiente en mi código:

if(foo contains bar) { .. 

Say, necesito para negar la condición. Si lo modifico de la siguiente manera:

if(!foo contains bar) { .. 

Bummer. Esto se analiza como (!foo).contains(bar). No es lo que queríamos

O supongamos que es necesario agregar una nueva condición, además, y lo modifica de modo:

if(foo contains bar && cond) { .. 

Otro rollo. Esto se analiza como foo.contains(bar.&&(cond)). No es lo que queríamos, otra vez.

Por supuesto, se podría añadir un montón de paréntesis alrededor, pero eso sería feo y difícil de leer/editar en comparación con la notación de punto.

Ahora, todo lo que he dicho anteriormente se aplica a los nombres de los métodos simbólicos también. Sin embargo, los métodos simbólicos no parecen naturales cuando se usan con sintaxis de punto, por lo que prefiero la sintaxis de infijo para ellos.


Una excepción a la directriz anterior: DSL internas. Por lo general, se elaboran con cuidado para no causar problemas de análisis cuando se escriben de la manera prescrita en su documentación/ejemplos (que generalmente usa notación infija).

+6

Esta misma lógica también se puede utilizar a favor de la notación infija, ya que proporciona un mecanismo adicional para controlar la precedencia (además de elegir operadores). Y hace que la precedencia sea más obvia visualmente. Por ejemplo, intente reescribir su primer ejemplo con funciones verdaderas y no solo con métodos levantados: '(xs filter f map g) .toList' todavía es mucho más claro y más obvio que' xs.filter (f) .map (g) .toList) ' –

+2

Poner paréntesis requiere edición no lineal, una razón más para evitar la notación infija. Dejar caer las llaves no ayuda tampoco en el caso. – missingfaktor

+1

Dejar caer paréntesis allí es el punto entero. Cuando se combina con la "fuerza" relativa de los operadores y el uso de paréntesis/llaves, entonces tener la capacidad * también * de usar infijo contra notación de puntos para controlar la precedencia es una herramienta muy poderosa para mantener limpio el código. –

12

Es una cuestión de preferencia personal. Su decisión de usar un estilo u otro debe basarse en lo que hace que su código sea más legible.

Pero tenga en cuenta que la capacidad de dejar fuera el punto y paréntesis se limita sólo a ciertas construcciones sintácticas, así que a veces sólo hay que recurrir a la utilización de ellos.

+5

Nótese también que 'a.op (b)' 'es más largo que un b' op pero más corta que' (una op b) '. Diferencia menor pero puede ser parte de la consideración "más legible". –

+0

Puede usar a? B en lugar de a.?(b) o a? b si necesita guardar cada byte. :) Por supuesto, el número de métodos, nombrables como este, de alguna manera es limitado. –

2

hay una buena style guide en la documentación oficial sitio Scala que describen el uso adecuado de notación infija sobre la notación de punto.

Sufijo Notación:

names.toList 
// is the same as 
names toList // Unsafe, don't use! 

Arity-1:

// right! 
names foreach (n => println(n)) 
names mkString "," 
optStr getOrElse "<empty>" 
// wrong! 
javaList add item 

de orden superior Funciones:

// wrong! 
names.map (_.toUpperCase).filter (_.length > 5) 
// right! 
names map (_.toUpperCase) filter (_.length > 5) 

métodos simbólicos/Operadores:

// right! 
"daniel" + " " + "Spiewak" 
// wrong! 
"daniel"+" "+"spiewak" 
0

He encontrado que el uso de notación infix para map funciona bien cuando estoy creando cartesianos con la biblioteca gatos. ej .:

(fetchIt(1) |@| fetchIt(2) |@| fetchIt(3)).map(MyCaseClass) 

usted puede deshacerse de los paréntesis que rodean este modo:

fetchIt(1) |@| fetchIt(2) |@| fetchIf(3) map MyCaseClass 

y en mi opinión, la segunda variante lee más agradable. Una cuestión de gusto, supongo. Solo quería agregar el valor de mis dos centavos.

Lo anterior funciona porque | en "| @ |" tiene una precedencia mayor que m en "mapa". Lea esta parte de la especificación Scala lang para obtener más detalles:

Si hay varias operaciones infijos en una expresión, entonces los operadores con mayor precedencia se unen más estrechamente que los operadores con menor precedencia.

http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations

Cuestiones relacionadas