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
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).
È 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.
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". –
È 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. –
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"
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
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) ' –
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
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. –