Confronto dell'abuso di sovraccarico dell'operatore in diverse lingue

6

Un argomento comune contro il sovraccarico dell'operatore è che può essere ed è abusato, ad es. A+B sta facendo qualcosa di completamente diverso per l'aggiunta. Gli esempi sono spesso citati in snippet C ++, dove le funzioni che sovraccaricano gli operatori non nominano gli operatori (ad esempio operator+() ). Confrontalo con Python, dove gli operatori sono nominati (ad esempio __add__ ).

Questo aiuta a dissuadere i programmatori dall'abuso del sovraccarico nel modo sopra descritto? Qualcuno ha qualche esperienza di sovraccarico dell'operatore Python che viene abusato?

    
posta marcog 10.09.2011 - 16:21
fonte

8 risposte

3
Does this help to deter programmers from abusing overloading 
in the aforementioned manner?

Bene, per prima cosa dovremmo definire cosa sia l' abuso ? File.Delete in C # elimina semplicemente un file senza nemmeno avvisare l'utente. Quindi, come sviluppatore, posso semplicemente scrivere questo codice:

List<string> files = Directory.GetFile("path").ToList();
files.ForEach(f => {
    File.Delete(f);
});

È considerato abuso ? OK, sei libero di definire + symbol (carattere) come operatore che voti su e - come operatore di voto in discesa . Ma è considerato abuso?

Inoltre, sei costretto ad abusare di queste funzionalità? Ad esempio, un guidatore può semplicemente girare la ruota per raggiungere l'area pedonale e uccidere le persone? Dovremmo bloccare la ruota?

Voglio dire, dopo tutto, anche se c'è un'opportunità per qualsiasi tipo di abuso, chi si farà del male? Developer.

Nonostante l'elevata infrastruttura OO, puoi scrivere proceduralmente in C #. È un abuso?

    
risposta data 10.09.2011 - 19:11
fonte
2

Puoi fare le stesse cose con i nomi di funzioni, come usare list.next () per restituire la lunghezza della lista, o list.length () per restituire un booleano.

La differenza è che abbiamo forti aspettative dalla matematica, che

a + b == b + a 

che è, ad esempio, violato nella concatenazione di stringhe, ma non ho mai incontrato una persona, che ha avuto problemi ad accettare + come operatore di concatenazione, e che si aspettava "foo" + "bar" per restituire "barfoo".

Secondo me è un argomento dalla fantasia. Sì, possiamo immaginare che le cose vadano male, ma in realtà non accadono.

Un altro trabocchetto sarebbe prevedibile

a + b * c to be evaluated a + (b * c), and 
(a + b) * c to be the same as (a*c) + (b*c) 

Ma è un problema nella realtà? Io non la penso così

    
risposta data 10.09.2011 - 19:31
fonte
1

Non fa alcuna differenza. Può darsi che i programmatori Python siano meno inclini ad abusare del sovraccarico dell'operatore. Se ciò è vero, è dovuto all'abilità dei programmatori, non alla differenza di sintassi.

Per un certo periodo di tempo, C ++ veniva utilizzato da un numero enorme di programmatori commerciali che scrivevano applicazioni interne di Windows. È un linguaggio potente progettato da esperti per esperti. Non sorprende che le sue caratteristiche siano state ampiamente fraintese e abusate.

Qualsiasi funzione linguistica, incluso il sovraccarico dell'operatore, può essere utilizzata male. Rimozione (o blocco delle funzioni) di una lingua non impedirà ai programmatori poveri di codificare male, così come rimuovere le parole dall'inglese non impedirà ai cattivi scrittori di scrivere male. Invece, frustrerà i bravi programmatori, costringendoli a aggirare la caratteristica mancante.

    
risposta data 10.09.2011 - 19:14
fonte
1

Definizione

Per prima cosa devi definire l'abuso in questo contesto.

Per me questo significa ridefinire gli operatori in modo che non funzionino in modo intuitivo per chiunque legga il codice.

Ma ovviamente intuitivamente dipende anche dal contesto, ma non solo dal contesto ma dalle classi coinvolte. Quindi si riduce anche a will the use of operator overloading make the code harder to read or lead to any misunderstanding da qualcuno che legge ingenuamente il codice senza capire il contesto completo.

Matrix   x;
Matrix   y;
Matrix   z  = x * y; // Is this abuse.

Questo dipende. Sono i matematici del tuo pubblico principale (o studenti CS intelligenti). Se sì, allora questo non è un abuso, ma una mano in ordine. Se il tuo pubblico principale è un professore di letteratura inglese, forse dovresti averlo scritto in questo modo:

WordUsage      Hamlet;
WordUsage      Othello;
WordUsage      Shakespeare = Hamlet.DeduceLoveCorrelation(Othello);
           // OK that was not clear to me but I am not an Literature buff.
           // But to a literature person those identifiers may mean something.

Uso

Quindi in C ++ puoi ridefinire gli operatori per fare qualsiasi cosa (il C ++ ti dà molta flessibilità (ma questo è anche il modo in cui sono stati introdotti gli operatori di streaming)). Quindi l'abuso può trasformarsi in un uso comune se l'idioma è accettato dalla comunità come scorciatoia utile.

Does this help to deter programmers from abusing overloading in the aforementioned manner?

Lo rende più complicato per definire l'abuso del deterrente da sovraccarico dell'operatore. No . Non è come se usare __add __ sia meno difficile dell'utilizzo di operator+() .

Anyone have any experiences of Python operator overloading being abused?

Penso che la comunità python abbia imparato dall'abuso e dalla stampa successiva sull'abuso che C ++ ha avuto oltre un decennio fa. Quando è uscito C ++ è stato il primo mainstream linguaggio che ha permesso il sovraccarico degli operatori e le persone hanno sperimentato selvaggiamente il concetto. Ciò ha causato molta frustrazione da parte dei manutentori e gli articoli sugli operatori che sovraccaricano sono un abuso (che ha portato a una reazione e lingue come Java che li vietano senza motivo (a parte l'influenza dell'opinione pubblica).

Nota: un paio di lingue meno conosciute lo hanno fatto prima (sovraccarico dell'operatore) ma sono state utilizzate principalmente da persone sensibili negli istituti di ricerca. Quindi o erano abbastanza intelligenti da non abusare degli operatori, o la ricerca era talmente ristretta che pochi si sono presi la briga di leggere il loro codice e quindi non ha ottenuto la stampa.

    
risposta data 10.09.2011 - 19:31
fonte
0

Non ho provato molte lingue, né Python, ma, nel caso di C ++ / Java / c #, penso che il supporto per l'overloading dell'operatore sia confuso e forse non corretto.

In C ++, un cattivo esempio è "< <" e "> >" operatori per i flussi, evito acutamente di utilizzarli.

Forse vorresti riformulare la tua domanda come "Come evito il sovraccarico dell'operatore in Python o in altre lingue?".

Molte volte, se utilizzo la programmazione orientata agli oggetti e ho bisogno di sovraccaricare e utilizzare l'operatore, preferisco utilizzare le funzioni anziché gli operatori.

    
risposta data 10.09.2011 - 17:48
fonte
0

L'abuso o l'uso improprio dell'overloading dell'operatore dipende da chi scrive il codice e non dalla sintassi utilizzata dal linguaggio di programmazione.

Per fare un esempio, se sovraccaricare l'operatore + per renderlo non commutativo era considerato una cattiva pratica, il compilatore (o l'interprete) non poteva fare nulla per evitare di creare una versione non commutativa del + operatore, in quanto non controlla se il risultato di a + b è uguale al risultato di b + a .
Se i programmatori che utilizzano un linguaggio di programmazione specifico considerano una cattiva pratica sovraccaricare l'operatore + per creare una versione non commutativa, allora non sovraccaricheranno quell'operatore per utilizzarlo come operatore di concatenazione per le stringhe.

    
risposta data 10.09.2011 - 19:36
fonte
0

Ci sono diversi gradi tra l'uso corretto del sovraccarico dell'operatore e l'abuso evidente.

L'uso corretto sarebbe quando l'operatore sovraccarico soddisfa entrambi i vincoli formali dell'operatore originale, E corrisponde intuitivamente e concettualmente. Ad esempio, se si implementa una classe bigint in C ++, l'overloading degli operatori aritmetici è perfettamente ragionevole, perché eseguono gli equivalenti bigint degli operatori di interi.

Dall'altra parte dello spettro, abbiamo un sovraccarico dell'operatore che cambia completamente il significato dell'operatore, introduce effetti collaterali non ovvi, viola il comportamento dell'operatore che si suppone stia modellando (commutatività, associatività, distruttività, ecc.) o altrimenti porta a codice fuorviante. Un esempio potrebbe essere l'overloading dell'operatore unario-meno per convertire una stringa in maiuscolo: il uppercasing non è reversibile e non ha nulla da fare concettualmente con il segno di un numero.

Da qualche parte tra questi due estremi, c'è una linea; dove esattamente lo si disegna dipende dalle preferenze personali. I progettisti di linguaggi di solito hanno idee su dove disegnare quella linea, e la lingua riflette questo in un modo. La differenza tra il modo C ++ e il modo Python, tuttavia, è semplicemente lo zucchero di sintassi.

Penso che l'overloading dell'operatore sia un potente strumento che può portare a un codice molto espressivo, se usato con gusto. Andare alla deriva dovrebbe essere evitato, ma proprio come con qualsiasi potente funzionalità linguistica, è responsabilità dei programmatori, non del compilatore, proteggerlo.

    
risposta data 10.09.2011 - 20:43
fonte
0

Per iniziare con la mia amata citazione sull'argomento:

I saw 'cout' being shifted "Hello world" times to the left and stopped right there.
— Steve Gonedes

Molto simile a qualsiasi funzione potente, o come qualsiasi funzione, può essere e sarà usata in modo improprio da qualcuno. Detto questo, renderlo un po 'più difficile da fare, vale probabilmente la pena.

Quello che davvero non vuoi che succeda è avere persone che definiscono operatori non evidenti. Permettetemi di darvi alcuni esempi di operatori binari (con aeb essendo gli operandi):

  • Array<T> * int : restituisce un Array<T> di lunghezza a.length * b concatenando a b volte a un array vuoto
  • Array<int> * int : restituisce un Array<int> , in cui ogni elemento di a è moltiplicato b
  • Array<T> * T->R : restituisce un Array<R> , dove ogni elemento è il valore di ritorno della chiamata b con l'elemento da una (mappa funzionale)
  • Array<T> / T->bool : restituisce un Array<T> , in cui sono inclusi solo quegli elementi, per i quali b restituisce true
  • ...

Puoi divertirti molto con questo. E le persone lo fanno. Ed è discutibilmente ok, se non è ambiguo (esempio 1 e esempio 2) e le persone lo capiscono (esempio 3 e esempio 4), che generalmente si ottiene scegliendo operatori relativamente chiari e quindi rispettandoli coerentemente .

L'unica lingua, dove ho giocato con l'overloading dell'operatore era Ruby, che lo rende molto semplice. È interessante notare che le persone non tendono ad abusarne. Per speculare su alcuni motivi:

  • La libreria standard di Ruby include la maggior parte delle raccolte di cui avrai bisogno e sovraccarica gli operatori su di esse in modo sparso, ma molto significativo. Dal punto di vista dei programmatori, l'operatore più comunemente sovraccarico è probabilmente l' operatore nave spaziale , ma per ovvi motivi, con ovvie conseguenze.
  • Ruby ha una community "più stretta" rispetto al C ++ (probabilmente i rubygems giocano un ruolo in questo, o forse il lungo tempo nell'ombra prima che l'hype lo facesse), quindi non hai troppe persone che scrivono le proprie raccolte-DSL tramite l'overloading dell'operatore
  • Le chiamate ruby possono omettere le parentesi. Probabilmente riderai di questo. I programmatori sono estremamente pigri e le parentesi sono piuttosto lente da digitare. Pertanto scrivere a.add b è una valida alternativa al sovraccarico di + .

Quindi direi che: il modo migliore per impedire alle persone di abusare del sovraccarico dell'operatore è di fornire buone alternative.

    
risposta data 10.09.2011 - 21:29
fonte

Leggi altre domande sui tag