La risposta breve: Consistenza
Per rispondere correttamente alla tua domanda, tuttavia, ti suggerisco di fare un passo indietro e di esaminare il problema di cosa significa uguaglianza in un linguaggio di programmazione. Ci sono almeno TRE diverse possibilità, che sono usate in varie lingue:
-
Equality di riferimento : significa che a = b è vero se a e b si riferiscono allo stesso oggetto. Non sarebbe vero se a e b si riferivano a oggetti diversi, anche se tutti gli attributi di aeb erano uguali.
-
Equality Shallow : significa che a = b è vero se tutti gli attributi degli oggetti a cui a e b si riferiscono sono identici. L'estrema uguaglianza può essere facilmente implementata mediante un confronto bit a bit dello spazio di memoria che rappresenta i due oggetti. Si prega di notare che l'uguaglianza di riferimento implica l'uguaglianza superficiale
-
Uguaglianza profonda : significa che a = b è vero se ogni attributo in a e b è identico o profondamente uguale. Si noti che l'uguaglianza profonda è implicita sia dall'uguaglianza di riferimento sia dall'uguaglianza superficiale. In questo senso, l'uguaglianza profonda è la forma più debole di uguaglianza e l'uguaglianza di riferimento è la più strong.
Questi tre tipi di uguaglianza sono spesso usati perché sono convenienti da implementare: tutti e tre i controlli di uguaglianza possono essere generati facilmente da un compilatore (nel caso dell'eguaglianza profonda, il compilatore potrebbe aver bisogno di usare i bit di tag per prevenire cicli infiniti se una struttura da confrontare ha riferimenti circolari). Ma c'è un altro problema: nessuno di questi potrebbe essere appropriato.
Nei sistemi non banali, l'uguaglianza degli oggetti è spesso definita come qualcosa tra l'uguaglianza profonda e di riferimento. Per verificare se vogliamo considerare due oggetti uguali in un certo contesto, potremmo richiedere che alcuni attributi siano confrontati da dove si trova nella memoria e altri da un'eguaglianza profonda, mentre alcuni attributi possono essere completamente diversi. Quello che ci piacerebbe davvero è un "quarto tipo di uguaglianza", davvero bello, spesso chiamato in letteratura uguaglianza semantica . Le cose sono uguali se sono uguali, nel nostro dominio. =)
Quindi possiamo tornare alla tua domanda:
Is there some major benefit of defaulting to this that I am simply missing, or does
it seem reasonable that the default behavior should be logical equality,
and defaulting back to reference equality if a logical equality doesn't exist
for the class?
Che cosa intendiamo quando scriviamo 'a == b' in qualsiasi lingua? Idealmente, dovrebbe sempre essere lo stesso: l'uguaglianza semantica. Ma non è possibile.
Una delle considerazioni principali è che, almeno per tipi semplici come i numeri, ci aspettiamo che due variabili siano uguali dopo l'assegnazione dello stesso valore. Vedi sotto:
var a = 1;
var b = a;
if (a == b){
...
}
a = 3;
b = 3;
if (a == b) {
...
}
In questo caso, ci aspettiamo che 'a uguale a b' in entrambe le dichiarazioni. Qualsiasi altra cosa sarebbe pazzesca. La maggior parte (se non tutte) delle lingue seguono questa convenzione. Pertanto, con tipi semplici (cioè valori) sappiamo come raggiungere l'uguaglianza semantica. Con gli oggetti, questo può essere qualcosa di completamente diverso. Vedi sotto:
var a = new Something(1);
var b = a;
if (a == b){
...
}
b = new Something(1);
a.DoSomething();
b.DoSomething();
if (a == b) {
...
}
Ci aspettiamo che il primo "se" sia sempre vero. Ma cosa ti aspetti al secondo "se"? Dipende davvero. Can DoSomething può cambiare l'uguaglianza (semantica) di aeb?
Il problema dell'eguaglianza semantica è che non può essere generato automaticamente dal compilatore per gli oggetti, né è ovvio dai compiti . È necessario fornire un meccanismo per l'utente per definire l'uguaglianza semantica. Nei linguaggi orientati agli oggetti, quel meccanismo è un metodo ereditato: uguale a . Leggendo un pezzo di codice OO, non ci si aspetta che un metodo abbia la stessa esatta implementazione in tutte le classi. Siamo abituati all'ereditarietà e al sovraccarico.
Con gli operatori, tuttavia, ci aspettiamo lo stesso comportamento. Quando vedi 'a == b' dovresti aspettarti lo stesso tipo di uguaglianza (dal 4 sopra) in tutte le situazioni. Pertanto, mirando alla coerenza i designer di lingua hanno utilizzato l'uguaglianza di riferimento per tutti i tipi. Non dovrebbe dipendere dal fatto che un programmatore abbia sovrascritto un metodo o meno.
PS: il linguaggio Dee è leggermente diverso da Java e C #: l'operatore di uguaglianza significa uguaglianza poco profonda per i tipi semplici e l'uguaglianza semantica per le classi definite dall'utente (con la responsabilità di implementare l'operazione = che giace con l'utente - nessun valore predefinito è fornito). Come per i tipi semplici, l'uguaglianza superficiale è sempre l'uguaglianza semantica, il linguaggio è coerente. Il prezzo che paga, tuttavia, è che l'operatore di uguale è indefinito per i tipi definiti dall'utente. Devi implementarlo. E, a volte, è semplicemente noioso.