Per le lingue contemporanee, è solo zucchero sintattico; in un modo completamente indipendente dal linguaggio, è più di questo.
In precedenza questa risposta affermava semplicemente che è più che zucchero sintattico, ma se vedrai nei commenti, Falco ha sollevato il punto che c'era un pezzo del puzzle che le lingue contemporanee sembrano mancare tutti; non mischiano l'overload del metodo con la determinazione dinamica di quale funzione chiamare nello stesso passaggio. Questo sarà chiarito in seguito.
Ecco perché dovrebbe essere di più.
Prendi in considerazione un linguaggio che supporti sia il sovraccarico del metodo sia le variabili non tipizzate. Potresti avere i seguenti prototipi di metodo:
bool someFunction(int arg);
bool someFunction(string arg);
In alcune lingue, verrai probabilmente rassegnato a sapere in fase di compilazione quale di queste verrebbe chiamata da una determinata riga di codice. Ma in alcune lingue, non tutte le variabili vengono digitate (o tutte implicitamente digitate come Object
o qualsiasi altra cosa), quindi immagina di costruire un dizionario le cui chiavi siano associate a valori di diversi tipi:
dict roomNumber; // some hotels use numbers, some use letters, and some use
// alphanumerical strings. In some languages, built-in dictionary
// types automatically use untyped values for their keys to map to,
// so it makes more sense then to allow for both ints and strings in
// your code.
E allora, se volessi fare domanda someFunction
per uno di quei numeri di stanza? Tu lo chiami:
someFunction(roomNumber[someSortOfKey]);
Si someFunction(int)
chiama o si someFunction(string)
chiama? Qui puoi vedere un esempio in cui questi non sono metodi totalmente ortogonali, specialmente nei linguaggi di livello superiore. Il linguaggio deve capire - durante il runtime - quale di questi chiamare, quindi deve ancora considerarli almeno un po 'lo stesso metodo.
Perché non usare semplicemente i modelli? Perché non usare semplicemente un argomento non tipizzato?
Flessibilità e controllo più accurato. A volte l'uso di template / argomenti non tipizzati è un approccio migliore, ma a volte no.
Devi pensare a casi in cui, ad esempio, potresti avere due firme di metodo che prendono ciascuno un int
e un string
come argomenti, ma in cui l'ordine è diverso in ciascuna firma. Potresti benissimo avere una buona ragione per farlo, dato che l'implementazione di ciascuna firma può fare sostanzialmente la stessa cosa, ma con un tocco leggermente diverso; la registrazione potrebbe essere diversa, ad esempio. O anche se fanno la stessa cosa esatta, potresti essere in grado di raccogliere automaticamente determinate informazioni solo dall'ordine in cui sono stati specificati gli argomenti. Tecnicamente potresti semplicemente usare le istruzioni pseudo-switch per determinare il tipo di ciascuno degli argomenti passati, ma diventa disordinato.
Quindi questo prossimo esempio è una cattiva pratica di programmazione?
bool stringIsTrue(int arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
bool stringIsTrue(Object arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
bool stringIsTrue(string arg)
{
if (arg == "0")
{
return false;
}
else
{
return true;
}
}
Sì, nel complesso. In questo esempio particolare, potrebbe impedire a qualcuno di provare ad applicarlo a determinati tipi primitivi e di ottenere comportamenti inaspettati (il che potrebbe essere una buona cosa); ma supponiamo che io abbia abbreviato il codice sopra e che tu, in effetti, hai un sovraccarico per tutti i tipi primitivi, così come per Object
s. Quindi questo prossimo bit di codice è davvero più appropriato:
bool stringIsTrue(untyped arg)
{
if (arg.toString() == "0")
{
return false;
}
else
{
return true;
}
}
Ma cosa succede se avete solo bisogno di utilizzare questo per int
s e string
s, e che cosa se si vuole che ritorni vero in base alle condizioni più semplici o più complicate di conseguenza? Quindi hai una buona ragione per usare il sovraccarico:
bool appearsToBeFirstFloor(int arg)
{
if (arg.digitAt(0) == 1)
{
return true;
}
else
{
return false;
}
}
bool appearsToBeFirstFloor(string arg)
{
string firstCharacter = arg.characterAt(0);
if (firstCharacter.isDigit())
{
return appearsToBeFirstFloor(int(firstCharacter));
}
else if (firstCharacter.toUpper() == "A")
{
return true;
}
else
{
return false;
}
}
Ma hey, perché non dare a queste funzioni due nomi diversi? Hai ancora la stessa quantità di controllo a grana fine, vero?
Perché, come affermato prima, alcuni hotel usano numeri, alcuni usano lettere e altri usano una combinazione di numeri e lettere:
appearsToBeFirstFloor(roomNumber[someSortOfKey]);
// will treat ints and strings differently, without you having to write extra code
// every single spot where the function is being called
Questo non è ancora esattamente lo stesso codice esatto che userei nella vita reale, ma dovrebbe illustrare il punto che sto facendo proprio bene.
Ma ... Ecco perché non è altro che zucchero sintattico nelle lingue contemporanee.
Falco ha sollevato il punto nei commenti secondo cui le lingue attuali fondamentalmente non mescolano il sovraccarico dei metodi e la selezione dinamica delle funzioni all'interno dello stesso passo. Il modo in cui avevo precedentemente compreso il funzionamento di alcune lingue era che potresti sovraccaricare appearsToBeFirstFloor
nell'esempio sopra, e quindi la lingua avrebbe determinato in fase di esecuzione quale versione della funzione da chiamare, a seconda del valore di runtime della variabile non tipizzata. Questa confusione derivava in parte dal lavorare con una specie di linguaggi ECMA, come ActionScript 3.0, in cui è possibile randomizzare facilmente quale funzione viene chiamata su una determinata riga di codice in fase di esecuzione.
Come forse saprai, ActionScript 3 non supporta il sovraccarico del metodo. Per quanto riguarda VB.NET, puoi dichiarare e impostare variabili senza assegnare esplicitamente un tipo, ma quando provi a passare queste variabili come argomenti a metodi sovraccarichi, non vuole ancora leggere il valore di runtime per determinare quale metodo chiamare; vuole invece trovare un metodo con argomenti di tipo Object
o nessun tipo o qualcos'altro del genere. Quindi l' esempio int
vs. string
sopra non funzionerebbe neanche in quella lingua. Il C ++ ha problemi simili, come quando usi qualcosa come un puntatore vuoto o qualche altro meccanismo del genere, ti richiede comunque di chiarire manualmente il tipo al momento della compilazione.
Quindi, come dice la prima intestazione ...
Per le lingue contemporanee, è solo zucchero sintattico; in un modo completamente indipendente dal linguaggio, è più di questo. Rendere il sovraccarico del metodo più utile e pertinente, come nell'esempio sopra, potrebbe effettivamente essere una buona caratteristica da aggiungere a una lingua esistente (come è stato ampiamente implicitamente richiesto per AS3), oppure potrebbe anche servire come uno tra molti diversi pilastri fondamentali per la creazione di un nuovo linguaggio procedurale / orientato agli oggetti.