La risposta breve: coerenza
Per rispondere correttamente alla tua domanda, tuttavia, suggerisco di fare un passo indietro e guardare al problema di ciò che significa uguaglianza in un linguaggio di programmazione. Esistono almeno TRE diverse possibilità, che sono utilizzate in varie lingue:
- Uguaglianza di riferimento : significa che a = b è vero se aeb si riferiscono allo stesso oggetto. Non sarebbe vero se aeb si riferissero a oggetti diversi, anche se tutti gli attributi di aeb fossero uguali.
- Uguaglianza superficiale : significa che a = b è vero se tutti gli attributi degli oggetti a cui aeb si riferiscono sono identici. L'uguaglianza superficiale può essere facilmente implementata mediante un confronto bit a bit dello spazio di memoria che rappresenta i due oggetti. Si noti che l'uguaglianza di riferimento implica l'uguaglianza superficiale
- Uguaglianza profonda : significa che a = b è vero se ogni attributo in aeb è 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ù forte.
Questi tre tipi di uguaglianza sono spesso usati perché sono convenienti da implementare: tutti e tre i controlli di uguaglianza possono essere facilmente generati da un compilatore (in caso di uguaglianza profonda, il compilatore potrebbe aver bisogno di usare i tag tag per evitare loop infiniti se una struttura per essere confrontato 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 quella di riferimento. Per verificare se vogliamo considerare due oggetti uguali in un determinato contesto, potremmo richiedere che alcuni attributi vengano confrontati da dove si trova in memoria e altri da una profonda uguaglianza, mentre ad alcuni attributi può essere permesso di essere qualcosa di completamente diverso. Quello che vorremmo 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:
C'è qualche grande vantaggio nell'impostare ciò che mi manca semplicemente, o sembra ragionevole che il comportamento predefinito dovrebbe essere l'uguaglianza logica e tornare all'uguaglianza di riferimento se non esiste un'uguaglianza logica per la classe?
Che cosa intendiamo quando scriviamo "a == b" in qualsiasi lingua? Idealmente, dovrebbe essere sempre la stessa: uguaglianza semantica. Ma questo 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 sia uguale a b" in entrambe le affermazioni. Qualsiasi altra cosa sarebbe pazza. La maggior parte (se non tutte) delle lingue segue questa convenzione. Pertanto, con tipi semplici (ovvero valori) sappiamo come raggiungere l'uguaglianza semantica. Con gli oggetti, 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" sarà sempre vero. Ma cosa ti aspetti dal secondo "se"? Dipende davvero. 'DoSomething' può cambiare l'uguaglianza (semantica) di aeb?
Il problema con l'uguaglianza semantica è che non può essere generato automaticamente dal compilatore per gli oggetti, né è evidente dalle assegnazioni . È necessario fornire un meccanismo affinché l'utente definisca l'uguaglianza semantica. Nei linguaggi orientati agli oggetti, quel meccanismo è un metodo ereditato: uguale a . Leggendo un pezzo di codice OO, non ci aspettiamo che un metodo abbia la stessa esatta implementazione in tutte le classi. Siamo abituati all'eredità e al sovraccarico.
Con gli operatori, tuttavia, ci aspettiamo lo stesso comportamento. Quando vedi 'a == b' dovresti aspettarti lo stesso tipo di uguaglianza (da 4 sopra) in tutte le situazioni. Quindi, puntando alla coerenza, i progettisti delle lingue hanno usato l'uguaglianza di riferimento per tutti i tipi. Non dovrebbe dipendere dal fatto che un programmatore abbia ignorato un metodo o meno.
PS: il linguaggio Dee è leggermente diverso da Java e C #: l'operatore equals significa uguaglianza superficiale per tipi semplici e uguaglianza semantica per le classi definite dall'utente (con la responsabilità di implementare l'operazione = che giace con l'utente - non viene fornito alcun valore predefinito). Poiché, per i tipi semplici, l'uguaglianza superficiale è sempre uguaglianza semantica, il linguaggio è coerente. Il prezzo che paga, tuttavia, è che l'operatore uguale è per impostazione predefinita non definito per i tipi definiti dall'utente. Devi implementarlo. E, a volte, è solo noioso.