2012-04-19 21 views
33

Esiste una best practice per uno rispetto all'altro? Ho letto il libro Scala di Odersky, et al. e sembra che infix sia usato per molte funzioni API di collezioni, mentre il punto è riservato alle funzioni definite dal programmatore.Scala - infisso vs notazione punto

risposta

43

Personalmente non ho regole rigide per questo, ma tendo ad usare la notazione infix solo con i nomi dei metodi simbolici e la notazione dei punti per quelli alfanumerici.

La notazione infix rende difficile modificare il codice in un secondo momento. Ecco alcuni esempi.

Immaginate di avere questa riga di codice:

xs filter { f } map { g } 

Supponiamo ad un certo quest'ultimo punto nel tempo è necessario aggiungere un toList alla fine. Lo hai messo:

xs filter { f } map { g } toList 

Ciò potrebbe causare problemi di inferenza della virgola. Per evitare questi problemi, puoi inserire un punto e virgola alla fine o inserire una nuova riga. Entrambe le opzioni sono brutte, secondo me. Per evitare tutte queste sciocchezze, preferisco andare con xs.filter(f).map(g). È sempre più facile refactoring con questa sintassi.

Un altro esempio: dire che ho il seguente nel mio codice:

if(foo contains bar) { .. 

Di ', ho bisogno di negare la condizione. Se lo modifico come segue:

if(!foo contains bar) { .. 

Bummer. Questo viene analizzato come (!foo).contains(bar). Non quello che volevamo.

Oppure supponiamo che è necessario aggiungere una nuova condizione in più, e di modificarlo in modo da:

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

Un altro fiasco. Questo viene analizzato come foo.contains(bar.&&(cond)). Non quello che volevamo, di nuovo.

Ovviamente, è possibile aggiungere un gruppo di parentesi, ma sarebbe brutto e difficile da leggere/modificare rispetto alla notazione dei punti.

Ora, tutto ciò che ho detto sopra si applica anche ai nomi dei metodi simbolici. Tuttavia i metodi simbolici sembrano innaturali se usati con la sintassi del punto, e quindi preferisco la sintassi infix per loro.


Un'eccezione alla linea guida sopra: DSL interni. Di solito sono creati con cura in modo da non causare problemi di parsing se scritti nel modo prescritto nella loro documentazione/esempi (che di solito usa la notazione infix).

+6

Questa stessa logica può essere utilizzata anche a favore della notazione infisso, in quanto fornisce un meccanismo aggiuntivo per il controllo della precedenza (oltre alla scelta degli operatori). E rende la precedenza più visivamente evidente. Ad esempio, prova a riscrivere il tuo primo esempio con funzioni vere e non solo metodi risolti: '(xs filter f map g) .toList' è ancora molto più pulito e più ovvio di' xs.filter (f) .map (g) .toList) ' –

+2

L'inserimento delle parentesi richiede una modifica non lineare, un motivo in più per evitare la notazione infissa. Lasciare cadere le parentesi non aiuta neanche il caso. – missingfaktor

+1

Lasciando cadere la parentesi lì è tutto il punto. Se combinato con la "forza" relativa degli operatori e l'uso di parentesi/parentesi graffe, avere la capacità di * anche * usare la notazione infisso vs punto per controllare la precedenza è uno strumento molto potente per mantenere pulito il codice. –

12

È una questione di preferenze personali. La tua decisione di utilizzare uno stile o l'altro dovrebbe essere basata su ciò che rende il tuo codice il più leggibile.

Ma si noti che la possibilità di lasciare il punto e le parentesi è limitata solo a certe costruzioni sintattiche, quindi a volte è sufficiente ricorrere al loro utilizzo.

+5

Si noti inoltre che 'a.op (b)' 'è più lungo di un b' op, ma più breve di' (un op b) '. Differenza minore ma può far parte della considerazione "più leggibile". –

+0

È possibile utilizzare a? B anziché a.?(b) o a? b se è necessario salvare ogni byte. :) Certamente, il numero di metodi, così nominabili, è in qualche modo limitato. –

2

C'è un buon style guide nella documentazione ufficiale del sito Scala che descrive la notazione infisso di uso corretto sulla notazione a punti.

suffisso Notazione:

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

arità-1:

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

di ordine superiore Funzioni:

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

simbolici metodi/Operatori:

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

Ho scoperto che l'uso della notazione infisso per map funziona correttamente quando sto creando cartesiani con la libreria di gatti . es .:

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

si può sbarazzarsi delle parentesi che circondano in questo modo:

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

e, a mio avviso la seconda variante si legge più bello. Una questione di gusti, suppongo. Volevo solo aggiungere il valore di due centesimi.

Quanto sopra funziona perché | in "| @ |" ha una precedenza più alta di m in "mappa". Leggere questa parte specifica Scala lang per ulteriori dettagli:

Se ci sono diverse operazioni infissa in un'espressione, quindi gli operatori con più alto legano la precedenza più da vicino di operatori con minore la precedenza.

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