2010-08-06 2 views
7
val filesHere = (new java.io.File(".")).listFiles 
val filesHere2 = (new java.io.File(".")).listFiles 

scala> filesHere == filesHere2
res0: Boolean = falseScala, Java e l'uguaglianza

che è abbastanza intuitive. Preferirei che i file Here e filesHere2 siano uguali.

Ciò è certamente dovuto a una mancata corrispondenza semantica tra Java e Scala, ad esempio, su array o (file) uguaglianza. Chiaramente, mi manca qualcosa qui!

risposta

4

Si consiglia di leggere qui:

http://ofps.oreilly.com/titles/9780596155957/AdvancedObjectOrientedProgramming.html#EqualityOfObjects

ma sembra che se hai fatto: filesHere.sameElements(filesHere2) che dovrebbe essere vero.

Javadoc per questo è qui: http://www.scala-lang.org/api/2.6.0/scala/IterableProxy.html#sameElements%28Iterable%5BB%5D%29

UPDATE:

Un paio di frammenti dal primo link che possono essere utili:

In Java, C++ e C# l'operatore == verifica il riferimento, non l'uguaglianza di valore. Al contrario, l'operatore == di Ruby verifica l'uguaglianza dei valori. Qualunque sia la lingua a cui sei abituato, ricordati che in Scala, == sta testando l'uguaglianza dei valori.

In riferimento a == non funziona come previsto su Liste:

Anche se questo può sembrare una contraddizione, favorendo un test esplicito della parità di due strutture di dati mutabili è un approccio conservativo da parte del progettisti di linguaggi A lungo termine, dovrebbe salvarti da risultati imprevisti nei tuoi condizionali.

UPDATE 2:

Sulla base di commenti da Raffaello ho guardato le specifiche, ed era datata due giorni fa per l'aggiornamento più recente, e vedo questi a http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf:

Method equals: (Any)Boolean is structural equality, where two instances 
are equal if they both belong to the case class in question and they have equal 
(with respect to equals) constructor arguments. 

class AnyRef extends Any { 
    def equals(that: Any): Boolean = this eq that 
    final def eq(that: AnyRef): Boolean = . . . // reference equality 

Quindi, sembra che la definizione non sia cambiata in Scala 2.10.2, poiché le specifiche sembrano essere coerenti. Se il comportamento è diverso, se scrivi un test unitario dovrebbe essere inviato come errore per Scala.

+0

Bella risorsa, grazie! Mostra come affrontare il problema menzionato sopra (usando sameElements, OK!) Ma non spiega perché il problema (o la "sorpresa") si verifichi come in scala> Array (1, 2) == Array (1 , 2) res0: Boolean = false – acherm

+0

@acherm - Ecco perché ho inserito l'aggiornamento, l'ultima citazione dell'articolo dovrebbe spiegare il perché, per incoraggiare test espliciti per l'uguaglianza. –

+0

Un'altra interessante discussione qui: http://scalide.blogspot.com/2009/05/hashcode-equals-in-scala-28-collections.html Questo non chiarisce completamente la situazione, ma illustra che "l'uguaglianza è un argomento interessante, semplicemente a causa dell'incredibile varietà di interpretazioni che ci sono in esso. " Guardando Array.scala (http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_8_0_final/src//library/scala/Array.scala), il metodo equals() non è definito . – acherm

8

Il metodo equals() di array Java utilizza l'uguaglianza di riferimento piuttosto che qualsiasi altra cosa più sofisticata, e lo == di Scala è semplicemente Java equals().

+0

In Scala == e uguale a() sono per l'uguaglianza di valore e eq è per due oggetti che hanno l'uguaglianza di riferimento. –

+1

@James yes, ma in questo caso equals() è implementato per controllare semplicemente l'uguaglianza di riferimento. Quindi in questo caso particolare, (Scala ==) == (Java's ==) :) –

+0

Ecco una discussione interessante: http://scala-programming-language.1934581.n4.nabble.com/scala-Array-equality -td2001726.html Ma comunque, sono davvero confuso. Se Scala == (o "uguale") chiama in realtà il metodo equals() di Java (come sembra il caso), questo esempio interrompe un po 'la scelta di progettazione del linguaggio Scala sull'uguaglianza. Come programmatore di Scala, devo ricordare la semantica dell'eguaglianza in Java e fare attenzione a tutti i punti delicati. Dannazione! – acherm

17

Se ho governato il mondo, io ricuso eq metodo di Scala sulla base del fatto che il nome è estremamente confusible con eguali e ==. Invece l'inglese ha una parola che esprime l'identità in contrapposizione all'uguaglianza: io lo chiamerei semplicemente è.

Allo stesso modo vorrei sostituire ne di Scala (che è un nome terribile, dal momento che è sia un'abbreviazione e incomprensibile) con isnt.

Mi sembra che in realtà potrebbero essere aggiunti a AnyRef e i vecchi metodi deprecati, anche in questa fase avanzata.

+3

Mi piace molto questa idea. –

+3

Sì, buona idea, ma "is" è ambiguo con controlli di tipo come: obj is String, che è popolare in altre lingue, e quindi confuso. – tuxSlayer

8

Il confronto non funziona come previsto, poiché questa API Java restituisce una matrice.

Gli array di Scala e gli array Java sono gli stessi dietro le quinte e sebbene l'array di Scala assomigli ad una classe, è solo un java.io.File [] (in questo esempio).

Questo è il motivo per cui il controllo di uguaglianza non può essere ignorato. Scala deve usare la semantica Java per questo.

Considerate questo esempio:

val filesHere = (new java.io.File(".")).listFiles.toList 
val filesHere2 = (new java.io.File(".")).listFiles.toList 

Questo potrebbe funzionare come previsto.

+0

Array (1, 2) == Array (1, 2) non funziona o – FUD

+0

@FUD sì, perché è una matrice. Ma se chiami '.toList' - inizierà a funzionare. Questo perché diventerà una classe del mondo di Scala, e le classi in Scala sono definite con un 'equals' più bello. – VasyaNovikov