Perché gli operatori definiti dall'utente non sono più comuni?

92

Una caratteristica che mi manca dai linguaggi funzionali è l'idea che gli operatori siano solo funzioni, quindi aggiungere un operatore personalizzato è spesso semplice come aggiungere una funzione. Molti linguaggi procedurali consentono il sovraccarico dell'operatore, quindi in un certo senso gli operatori sono ancora funzioni (questo è molto vero in D dove l'operatore è passato come una stringa in un parametro template).

Sembra che laddove sia consentito il sovraccarico dell'operatore, è spesso banale aggiungere operatori addizionali personalizzati. Ho trovato questo post del blog , che sostiene che gli operatori personalizzati non funzionano bene con la notazione infisso a causa delle regole di precedenza, ma l'autore fornisce diverse soluzioni a questo problema.

Mi sono guardato intorno e non sono riuscito a trovare alcun linguaggio procedurale che supporti gli operatori personalizzati nella lingua. Ci sono degli hack (come i macro in C ++), ma questo è quasi lo stesso del supporto linguistico.

Poiché questa funzione è piuttosto semplice da implementare, perché non è più comune?

Capisco che possa portare a qualche brutto codice, ma che in passato non ha impedito ai progettisti di linguaggi di aggiungere funzionalità utili che possono essere facilmente abusate (macro, operatore ternario, puntatori non sicuri).

Casi di utilizzo effettivi:

  • Implementa gli operatori mancanti (ad esempio, Lua non ha operatori bit a bit)
  • Mimica% ~ (concatenazione di array)
  • DSL
  • Usa | come zucchero sintassi stile pipe Unix (usando coroutine / generatori)

Mi interessano anche le lingue che do consentono agli operatori personalizzati, ma sono più interessato a perché è stato escluso. Ho pensato di creare un linguaggio di scripting per aggiungere operatori definiti dall'utente, ma mi sono fermato quando ho capito che non l'ho visto da nessuna parte, quindi c'è probabilmente una buona ragione per cui i progettisti di linguaggi più intelligenti di me non l'hanno permesso.

    
posta beatgammit 29.12.2012 - 19:23
fonte

16 risposte

131

Ci sono due scuole di pensiero diametralmente opposte nella programmazione del linguaggio di programmazione. Uno è che i programmatori scrivono un codice migliore con meno restrizioni e l'altro è che scrivono un codice migliore con più restrizioni. A mio parere, la realtà è che i programmatori esperti di buona qualità prosperano con meno restrizioni, ma che le restrizioni possono avvantaggiare la qualità del codice dei principianti.

Gli operatori definiti dall'utente possono creare codice molto elegante con mani esperte e codice assolutamente orribile da un principiante. Quindi, che la tua lingua li includa o meno dipende dalla scuola di pensiero del tuo disegnatore linguistico.

    
risposta data 29.12.2012 - 22:05
fonte
83

Data una scelta tra concatenare gli array con ~ o con "myArray.Concat (secondArray)", probabilmente preferirei quest'ultimo. Perché? Perché ~ è un personaggio completamente privo di significato che ha solo il suo significato - quello della concatenazione dell'array - dato nel progetto specifico in cui è stato scritto.

Fondamentalmente, come hai detto, gli operatori non sono diversi dai metodi. Ma mentre i metodi possono essere dati nomi leggibili e comprensibili che si aggiungono alla comprensione del flusso del codice, gli operatori sono opachi e situazionali.

Questo è il motivo per cui anche a me non piace l'operatore . di PHP (concatenazione delle stringhe) o la maggior parte degli operatori in Haskell o OCaml, anche se in questo caso alcuni standard universalmente accettati stanno emergendo per i linguaggi funzionali.

    
risposta data 29.12.2012 - 19:31
fonte
70

Since this feature is pretty trivial to implement, why isn't it more common?

La tua premessa è sbagliata. È non "piuttosto semplice da implementare". In effetti, porta un sacco di problemi.

Diamo un'occhiata alle "soluzioni" suggerite nel post:

  • Nessuna precedenza . Lo stesso autore dice "Non usare le regole di precedenza non è semplicemente un'opzione".
  • Analisi semantica consapevole . Come dice l'articolo, questo richiederebbe al compilatore di avere molte conoscenze semantiche. L'articolo in realtà non offre una soluzione per questo e lascia che ti dica, questo semplicemente non è banale. I compilatori sono progettati come un compromesso tra potenza e complessità. In particolare, l'autore cita una fase di pre-analisi per raccogliere le informazioni pertinenti, ma la pre-analisi è inefficiente e i compilatori si impegnano molto a minimizzare i passaggi di analisi.
  • Nessun operatore di infisso personalizzato . Bene, questa non è una soluzione.
  • Soluzione ibrida . Questa soluzione comporta molti (ma non tutti) gli svantaggi dell'analisi sintattica semantica. In particolare, poiché il compilatore deve trattare i token sconosciuti come potenzialmente rappresentativi di operatori personalizzati, spesso non può produrre messaggi di errore significativi. Potrebbe anche richiedere la definizione di detto operatore per procedere con l'analisi (per raccogliere informazioni sul tipo ecc.), Richiedendo nuovamente un ulteriore pass di analisi.

Tutto sommato, questa è una caratteristica costosa da implementare, sia in termini di complessità del parser che in termini di prestazioni, e non è chiaro che possa portare molti benefici. Certo, ci sono alcuni benefici per la capacità di definire nuovi operatori, ma anche quelli sono controversi (basta guardare le altre risposte sostenendo che avere nuovi operatori non è una buona cosa).

    
risposta data 30.12.2012 - 13:38
fonte
25

Ignoriamo per il momento l'argomento "operatori abusati di danneggiare la leggibilità" e concentriamoci sulle implicazioni del design del linguaggio.

Gli operatori Infix hanno più problemi rispetto alle semplici regole di precedenza (anche se per essere smussati, il collegamento che fai riferimento banalizza l'impatto di tale decisione progettuale). Uno è la risoluzione dei conflitti: cosa succede quando definisci a.operator+(b) e b.operator+(a) ? Preferire l'uno sull'altro porta a rompere la proprietà commutativa prevista di quell'operatore. Lanciare un errore può portare alla rottura di moduli che altrimenti funzionerebbero una volta insieme. Cosa succede quando inizi a lanciare tipi derivati nel mix?

Il fatto è che gli operatori non sono solo funzioni. Le funzioni sono indipendenti o appartengono alla loro classe, il che fornisce una chiara preferenza su quale parametro (se esiste) possiede la spedizione polimorfica.

E ciò ignora i vari problemi di packaging e risoluzione che sorgono dagli operatori. Il motivo per cui i progettisti di linguaggi (in generale) limitano la definizione dell'operatore infisso è perché crea una serie di problemi per la lingua fornendo un vantaggio discutibile.

E, francamente, perché sono non banali da implementare.

    
risposta data 30.12.2012 - 00:08
fonte
19

Penso che saresti sorpreso di quanto spesso sovraccarichi dell'operatore siano implementati in qualche forma. Ma non sono comunemente usati in molte comunità.

Perché usare ~ per concatenare un array? Perché non utilizza < < come fa Ruby ? Perché i programmatori con cui lavori probabilmente non sono programmatori Ruby. O programmatori D. Quindi cosa fanno quando incontrano il tuo codice? Devono andare a cercare cosa significa il simbolo.

Lavoravo con un ottimo sviluppatore di C # che aveva anche il gusto per i linguaggi funzionali. A prima vista, ha iniziato a presentare monads a C # mediante metodi di estensione e utilizzando la terminologia monad standard. Nessuno poteva contestare che parte del suo codice fosse terser e ancor più leggibile una volta che sapevi cosa significava, ma significava che tutti dovevano imparare la terminologia monad prima che il codice avesse senso .

Giusto abbastanza, pensi? Era solo una piccola squadra. Personalmente, non sono d'accordo. Ogni nuovo sviluppatore era destinato a essere confuso da questa terminologia. Non abbiamo abbastanza problemi nell'apprendere un nuovo dominio?

D'altro canto, userò felicemente l'operatore ?? in C # perché Mi aspetto che altri sviluppatori C # sappiano di cosa si tratta, ma non lo sovraccaricherò in un linguaggio che non lo supporta per impostazione predefinita.

    
risposta data 29.12.2012 - 21:25
fonte
11

Posso pensare ad alcuni motivi:

  • Loro non sono banali da implementare - consentendo agli operatori personalizzati arbitrari di rendere il compilatore molto più complesso, soprattutto se si consentono le regole di precedenza, di fissità e di integrità definite dall'utente. Se la semplicità è una virtù, l'overloading dell'operatore ti porta lontano dal buon design del linguaggio.
  • Sono abusati - principalmente da programmatori che pensano che sia "cool" ridefinire gli operatori e iniziare a ridefinirli per tutti i tipi di classi personalizzate. In poco tempo, il tuo codice è disseminato di un carico di simboli personalizzati che nessun altro può leggere o capire perché gli operatori non seguono le convenzionali regole ben comprese. Non compro l'argomento "DSL", a meno che il tuo DSL non sia un sottoinsieme di matematica: -)
  • Loro compromettono la leggibilità e la gestibilità - se gli operatori vengono sovrascritti regolarmente, può diventare difficile individuare quando viene utilizzata questa funzione e i programmatori sono costretti a chiedersi continuamente cosa sta facendo un operatore. È molto meglio dare nomi di funzioni significativi. Digitare qualche carattere in più è economico, i problemi di manutenzione a lungo termine sono costosi.
  • Possono rompere le aspettative implicite sulle prestazioni . Ad esempio, normalmente mi aspetto che la ricerca di un elemento in una matrice sia O(1) . Ma con l'overloading dell'operatore, someobject[i] potrebbe facilmente essere un'operazione O(n) a seconda dell'implementazione dell'operatore di indicizzazione.

In realtà, ci sono pochissimi casi in cui il sovraccarico dell'operatore ha usi giustificabili rispetto all'uso di funzioni regolari. Un esempio legittimo potrebbe essere la progettazione di una classe numerica complessa per l'uso da parte di matematici, che comprendono i modi ben compresi che gli operatori matematici definiscono per numeri complessi. Ma questo non è un caso molto comune.

Alcuni casi interessanti da considerare:

  • Lisps : in generale non distinguono tra operatori e funzioni - + è solo una funzione regolare. Puoi definire le funzioni come preferisci (in genere esiste un modo per definirle in spazi dei nomi separati per evitare conflitti con il + incorporato), inclusi gli operatori. Ma c'è una tendenza culturale a usare nomi di funzioni significativi, quindi questo non viene abusato molto. Inoltre, nella notazione del prefisso Lisp tende ad abituarsi in modo esclusivo, quindi c'è meno valore nello "zucchero sintattico" fornito dall'overload degli operatori.
  • Java - non consente l'overloading dell'operatore. Questo a volte è fastidioso (per cose come il caso numero complesso), ma in media è probabilmente la decisione di design giusta per Java che è intesa come un semplice linguaggio OOP generico. Il codice Java è in realtà abbastanza semplice da mantenere per gli sviluppatori di livello medio / basso come risultato di questa semplicità.
  • C ++ ha un sovraccarico dell'operatore molto sofisticato. A volte questo viene abusato ( cout << "Hello World!" chiunque?) Ma l'approccio ha senso dato il posizionamento di C ++ come un linguaggio complesso che consente una programmazione di alto livello pur consentendo di avvicinarsi molto al metallo per le prestazioni, quindi puoi ad es. scrivi una classe di numeri complessi che si comporta esattamente come vuoi senza compromettere le prestazioni. Resta inteso che è una tua responsabilità se ti spari ai piedi.
risposta data 02.01.2013 - 06:17
fonte
8

Since this feature is pretty trivial to implement, why isn't it more common?

È non è banale da implementare (a meno che non sia implementato banalmente). Inoltre, non ti dà molto, anche se implementato idealmente: i guadagni di leggibilità dalla chiarezza sono compensati dalle perdite di leggibilità da non familiarità e opacità. In breve, è raro perché di solito non vale il tempo degli sviluppatori o degli utenti.

Detto questo, posso pensare a tre lingue che lo fanno, e lo fanno in diversi modi:

  • Racket, uno schema, quando non è tutto, S-expression-y consente e ti aspetta che tu scriva ciò che equivale a parser per ogni sintassi che vuoi estendere (e fornisce hook utili per renderlo trattabile).
  • Haskell, un linguaggio di programmazione puramente funzionale, consente di definire qualsiasi operatore costituito esclusivamente da punteggiatura e consente di fornire un livello di fissità (10 disponibili) e un'associatività. Gli operatori ternari, ecc., Possono essere creati da operatori binari e funzioni di ordine superiore.
  • Agda, un linguaggio di programmazione tipicamente dipendente, è estremamente flessibile con gli operatori (carta qui ) che consente sia la definizione di se-then che di se-else-else come operatori nello stesso programma, ma il suo lexer, parser e valutatore sono tutti strongmente accoppiati come risultato.
risposta data 30.12.2012 - 19:14
fonte
7

Uno dei motivi principali per cui gli operatori personalizzati sono scoraggiati è perché ogni operatore può significare / può fare qualsiasi cosa.

Ad esempio il sovraccarico di spostamento a sinistra molto criticato di cstream .

Quando una lingua consente il sovraccarico dell'operatore, generalmente si incoraggia l'operatore a mantenere il comportamento dell'operatore simile al comportamento di base per evitare confusione.

Anche gli operatori definiti dall'utente rendono l'analisi molto più difficile, specialmente quando ci sono anche regole di preferenze personalizzate.

    
risposta data 29.12.2012 - 20:01
fonte
4

Non usiamo gli operatori definiti dall'utente per lo stesso motivo per cui non usiamo le parole definite dall'utente. Nessuno chiamerebbe la loro funzione "sworp". L'unico modo per trasmettere il tuo pensiero ad un'altra persona è usare un linguaggio condiviso. Ciò significa che sia le parole che i segni (operatori) devono essere noti alla società per la quale stai scrivendo il tuo codice.

Quindi gli operatori che vedete in uso nei linguaggi di programmazione sono quelli che abbiamo imparato a scuola (aritmetica) o quelli che sono stati stabiliti nella comunità di programmazione, come ad esempio gli operatori booleani.

    
risposta data 30.12.2012 - 19:32
fonte
4

Per quanto riguarda le lingue che supportano tale sovraccarico: Scala lo fa, in realtà in un modo molto più pulito e migliore può C ++. La maggior parte dei caratteri può essere usata nei nomi di funzioni, quindi puoi definire operatori come! + * = ++, se lo desideri. C'è un supporto integrato per infix (per tutte le funzioni che accettano un argomento). Penso che tu possa definire anche l'associatività di tali funzioni. Tuttavia, non puoi definire la precedenza (solo con brutti scherzi, vedi qui ).

    
risposta data 23.05.2017 - 14:40
fonte
4

Una cosa che non è stata ancora menzionata è il caso di Smalltalk, dove tutto (inclusi gli operatori) è un messaggio inviato. "Operatori" come + , | e così via sono in realtà metodi unari.

Tutti i metodi possono essere sovrascritti, quindi a + b significa l'aggiunta di interi se a e b sono entrambi interi, e significa aggiunta vettoriale se sono entrambi OrderedCollection s.

Non ci sono regole di precedenza, poiché si tratta solo di chiamate di metodo. Ciò ha un'importante implicazione per la notazione matematica standard: 3 + 4 * 5 significa (3 + 4) * 5 , non 3 + (4 * 5) .

(Questo è un grosso ostacolo per i neofiti di Smalltalk. Spezzare le regole matematiche rimuove un caso particolare, in modo che tutta la valutazione del codice proceda uniformemente da sinistra a destra, rendendo la lingua molto più semplice.)

    
risposta data 02.01.2013 - 08:53
fonte
3

Stai combattendo contro due cose qui:

  1. Perché gli operatori esistono nelle lingue in primo luogo?
  2. Qual è la virtù degli operatori rispetto a funzioni / metodi?

Nella maggior parte delle lingue, gli operatori non sono realmente implementati come semplici funzioni. Potrebbero avere uno scaffolding di funzioni, ma il compilatore / runtime è esplicitamente consapevole del loro significato semantico e di come tradurli efficientemente in codice macchina. Questo è molto più vero anche rispetto alle funzioni integrate (motivo per cui la maggior parte delle implementazioni non include tutte le funzioni di overhead delle chiamate nella loro implementazione). La maggior parte degli operatori sono astrazioni di livello superiore sulle istruzioni primitive trovate nelle CPU (che è in parte il motivo per cui la maggior parte degli operatori sono aritmetiche, booleane o bit a bit). Potresti modellarli come funzioni "speciali" (chiamali "primitive" o "builtins" o "native" o qualsiasi altra cosa), ma per fare ciò richiede genericamente un insieme di semantica molto robusto per definire tali funzioni speciali. L'alternativa consiste nell'avere operatori integrati che assomigliano semanticamente a operatori definiti dall'utente, ma che altrimenti richiamano percorsi speciali nel compilatore. Che funziona in contrasto con la risposta alla seconda domanda ...

A parte il problema di traduzione automatica che ho menzionato sopra, a livello sintattico gli operatori non sono molto diversi dalle funzioni. Le loro caratteristiche distintive tendono ad essere che sono concise e simboliche, il che suggerisce una caratteristica aggiuntiva significativa che devono essere utili: devono avere un significato / semantica ampiamente comprensibile per gli sviluppatori. I simboli brevi non trasmettono molto significato a meno che non sia una mano corta per un insieme di semantica che sono già compresi. Ciò rende gli operatori definiti dall'utente intrinsecamente inutili, poiché per loro stessa natura non sono così capiti. Hanno senso quanto i nomi di una o due lettere.

I sovraccarichi dell'operatore di C ++ forniscono un terreno fertile per esaminarlo. La maggior parte degli "abusi" di sovraccarico dell'operatore si presentano sotto forma di sovraccarichi che interrompono parte del contratto semantico che è ampiamente compreso (un classico esempio è un sovraccarico di operatore + tale che a + b! = B + a, o dove + modifica uno dei suoi operandi).

Se si guarda Smalltalk, che consente all'operatore di sovraccaricare gli operatori definiti dall'utente e , è possibile vedere come potrebbe funzionare una lingua e come sarebbe utile. In Smalltalk, gli operatori sono semplicemente metodi con proprietà sintattiche diverse (vale a dire, sono codificati come infix binary). Il linguaggio usa "metodi primitivi" per operatori e metodi speciali accelerati. Trovi che pochi se vengono creati degli operatori definiti dall'utente, e quando lo sono, tendono a non abituarsi tanto quanto l'autore probabilmente ha intenzione di usarli. Anche l'equivalente di un sovraccarico dell'operatore è raro, perché è soprattutto una perdita netta definire una nuova funzione come operatore anziché come metodo, poiché quest'ultimo consente un'espressione della semantica della funzione.

    
risposta data 30.12.2012 - 21:14
fonte
1

Ho sempre trovato che gli overloads dell'operatore in C ++ sono una comoda scorciatoia per un singolo team di sviluppatori, ma che causa ogni sorta di confusione a lungo termine semplicemente perché le chiamate al metodo sono "nascoste" in un modo che non è È facile per strumenti come Doxygen separare, e le persone hanno bisogno di capire gli idiomi per poterli utilizzare correttamente.

A volte è molto più difficile dare un senso a quello che ti aspetti, anche. C'era una volta, in un grande progetto C ++ multipiattaforma, ho deciso che sarebbe stata una buona idea normalizzare il modo in cui i percorsi sono stati creati creando un oggetto FilePath (simile all'oggetto File di Java), che avrebbe operatore / utilizzato per concatenare un'altra parte di percorso su di esso (in modo da poter fare qualcosa come File::getHomeDir()/"foo"/"bar" e farebbe la cosa giusta su tutte le nostre piattaforme supportate). Tutti quelli che l'hanno visto direbbero essenzialmente: "Che diavolo? Divisione per archi? ... Oh, è carino, ma non mi fido che faccia la cosa giusta."

Allo stesso modo, ci sono molti casi nella programmazione grafica o in altre aree in cui la matematica vettoriale / a matrice avviene molto quando si è tentati di fare cose come Matrix * Matrix, Vector * Vector (punto), Vector% Vector (croce), Matrix * Vector (matrice trasformata), Matrix ^ Vector (trasformazione della matrice del caso speciale che ignora la coordinata omogenea - utile per le normali delle superfici), e così via, ma mentre si risparmia un po 'di tempo di analisi per la persona che ha scritto la libreria matematica vettoriale, finisce solo per confondere il problema più per gli altri. Non ne vale la pena.

    
risposta data 26.05.2013 - 00:07
fonte
0

I sovraccarichi dell'operatore sono una cattiva idea per la stessa ragione per cui i sovraccarichi di metodo sono una cattiva idea: lo stesso simbolo sullo schermo avrebbe significati diversi a seconda di ciò che lo circonda. Questo rende più difficile la lettura casuale.

Poiché la leggibilità è un aspetto critico della manutenibilità, si dovrebbe sempre evitare di sovraccaricare (tranne in alcuni casi molto speciali). È molto meglio che ogni simbolo (che sia operatore o identificatore alfanumerico) abbia un significato unico che si regge da solo.

Per illustrare: quando leggi un codice sconosciuto, se incontri un nuovo identificatore alfanum che non conosci, almeno hai il vantaggio che sai di non saperlo . Puoi quindi andare a cercarlo. Se, tuttavia, si vede un identificatore o un operatore comune di cui si conosce il significato, è molto meno probabile notare che in realtà è stato sovraccaricato per avere un significato completamente diverso. Per sapere quali operatori sono stati sovraccaricati (in una base di codice che ha fatto un uso diffuso dell'overloading), è necessaria una conoscenza pratica del codice completo, anche se si desidera solo leggerne una piccola parte. Ciò renderebbe difficile avvicinare i nuovi sviluppatori a quel codice, e impossibile portare le persone a fare un piccolo lavoro. Ciò può essere utile per la sicurezza del lavoro del programmatore, ma se sei responsabile del successo della base di codice, dovresti evitare questa pratica a tutti i costi.

Poiché gli operatori sono di piccole dimensioni, gli operatori di overload consentirebbero un codice più denso, ma rendere il codice denso non è un vantaggio reale. Una riga con il doppio della logica impiega il doppio del tempo di lettura. Il compilatore non si preoccupa. L'unico problema è la leggibilità umana. Dal momento che rendere il codice compatto non migliora la leggibilità, non c'è alcun vantaggio reale per la compattezza. Vai avanti e prendi lo spazio, e dai alle operazioni univoci un identificatore univoco, e il tuo codice avrà più successo nel lungo periodo.

    
risposta data 01.01.2013 - 03:47
fonte
-1

Difficoltà tecniche per gestire la precedenza e il parsing complesso accantonato, penso che ci siano alcuni aspetti di ciò che un linguaggio di programmazione deve essere considerato.

Gli operatori sono in genere brevi costrutti logici ben definiti e documentati nel linguaggio principale (confronta, assegna ..). In genere sono anche difficili da capire senza documentazione (confronta a^b con xor(a,b) per esempio). Esiste un numero piuttosto limitato di operatori che potrebbe avere senso nella normale programmazione (>, & lt ;, =, + ecc.).

La mia idea è che è meglio attenersi a una serie di operatori ben definiti in una lingua, quindi consentire all'operatore di sovraccaricare tali operatori (in base a una raccomandazione che gli operatori dovrebbero fare la stessa cosa, ma con un tipo di dati personalizzato) .

I tuoi casi d'uso di ~ e | sarebbero effettivamente possibili con un semplice overloading dell'operatore (C #, C ++, ecc.). DSL è un'area di utilizzo valida, ma probabilmente una delle uniche aree valide (dal mio punto di vista). Io, tuttavia, penso che ci siano strumenti migliori per creare nuove lingue all'interno. L'esecuzione di un vero linguaggio DSL in un'altra lingua non è così difficile utilizzando uno di questi strumenti compilatore-compilatore. Lo stesso vale per "estendere l'argomento LUA". È probabile che una lingua sia definita principalmente per risolvere problemi in un modo specifico, non per essere una base per le lingue secondarie (esistono eccezioni).

    
risposta data 30.12.2012 - 15:32
fonte
-1

Un altro fattore è che non è sempre semplice definire un'operazione con gli operatori disponibili. Voglio dire, sì, per qualsiasi tipo di numero, l'operatore '*' può avere senso, e di solito sono implementati nella lingua o nei moduli esistenti. Ma nel caso delle classi complesse tipiche che è necessario definire (cose come ShipingAddress, WindowManager, ObjectDimensions, PlayerCharacter, ecc.) Questo comportamento non è chiaro ... Cosa significa aggiungere o sottrarre un numero a un indirizzo? Moltiplicare due indirizzi?

Certo, puoi definire che aggiungere una stringa a una classe ShippingAddress significa un'operazione personalizzata come "sostituire la riga 1 nell'indirizzo" (invece della funzione "setLine1") e aggiungere un numero è "sostituire il codice postale" (invece di " setZipCode "), ma il codice non è molto leggibile e confuso. Generalmente pensiamo che l'operatore sia usato nei tipi / classi di base, in quanto il loro comportamento è intuitivo, chiaro e coerente (almeno una volta che si ha familiarità con la lingua). Pensa in tipi come Integer, String, ComplexNumbers, ecc.

Quindi, anche se la definizione degli operatori può essere molto utile in alcuni casi specifici, la loro implementazione nel mondo reale è piuttosto limitata, in quanto il 99% dei casi in cui questa sarà una chiara vittoria sono già stati implementati nel pacchetto linguistico di base.

    
risposta data 06.01.2013 - 22:19
fonte

Leggi altre domande sui tag