Vuoi creare un tipo specializzato solo per avvolgere un primitivo? [duplicare]

0

Spesso nella programmazione, dobbiamo rappresentare un valore che può essere facilmente rappresentato usando un semplice tipo primitivo.

Ad esempio, in un gioco potremmo aver bisogno di rappresentare la velocità di un oggetto in movimento. Questo potrebbe facilmente essere rappresentato con un valore double . Questo oggetto potrebbe anche avere un valore di massa; questo può anche essere rappresentato con double .

Alcuni sostengono che dovremmo avere un tipo Speed e un tipo Mass per ognuno di questi, invece del tipo double per scopi generici. L'argomentazione a favore di ciò è che in questo modo sfruttiamo la "tipizzazione strong"; il compilatore non ci lascia passare una velocità per una massa o una massa per una velocità e commettere errori come quelli.

Questa argomentazione ha senso. Tuttavia, non posso fare a meno di pensare che questo sarebbe un eccessivo.

Quindi cosa useresti? Un semplice double (seguendo KISS e mantenendo tutto il più semplice possibile) o un tipo creato per uno scopo specifico?

    
posta Aviv Cohn 20.06.2015 - 19:44
fonte

6 risposte

3

Direi di sì se quel tipo ha un significato più del semplice valore. Nel tuo esempio, Velocità e Massa potrebbero essere rappresentati da un doppio, ma hanno significati diversi e hanno calcoli diversi che possono essere fatti su di loro.

Posso dirti per esperienza personale che fare questo (si chiama micro dominio btw), ha reso il mio codice molto più leggibile e mi ha salvato molte volte dal passare la variabile sbagliata per errore.

    
risposta data 20.06.2015 - 20:00
fonte
2

Dipende dalla lingua e da quanto impegno sei disposto a investire per una maggiore correttezza. Esiste un delicato equilibrio tra "codice conciso" e "codice rigoroso", ma la posizione di questo varia da lingua a lingua e dipende anche dal gusto e dalle circostanze personali. Ad esempio, se sei solo prototipazione, potrebbe non valere affatto la pena.

In alcuni casi, il vantaggio vale il costo aggiuntivo - l'esempio più comunemente citato sono i wrapper di stringa che consentono di distinguere stringhe di input non sicure da stringhe scritte dal programmatore, riducendo così il rischio di un attacco di iniezione accidentale quando queste stringhe sono concatenati con noncuranza.

Si può fare lo stesso anche con le quantità. Alcune lingue hanno anche librerie che ti consentono di gestire le unità in modo generale , se il sistema di tipi è abbastanza potente da supportare tale caratteristica.

Per quanto riguarda le prestazioni, molte lingue sono in grado di ottimizzare i tipi di dati del wrapper banale, quindi potrebbe non avere alcun impatto sulle prestazioni, tranne forse riducendo leggermente la velocità di compilazione.

    
risposta data 20.06.2015 - 21:26
fonte
1

F # risolve bene questo problema con le misure:

[<Measure>] type cm
[<Measure>] type ml = cm^3

Per altre lingue, è un compromesso (come tutto). L'incapsulamento delle primitive può avere un impatto su prestazioni e spazio, ma ha benefici in termini di sicurezza del tipo. Puoi confondere gli sviluppatori più giovani (e forse anche quelli più anziani), quindi ci sono potenziali problemi di leggibilità, così come perdite di produttività se non implementa correttamente la cosa, o se la lingua non ti permette di implementare completamente qualcosa come questo . Ad esempio, potresti lanciare implicitamente il tuo nuovo tipo incapsulato? MyNewType i = 2; Come funziona l'uguaglianza? %codice%. ecc.

    
risposta data 21.06.2015 - 02:00
fonte
0

Probabilmente potresti capirlo controllando i casi d'uso di un rapido campione. Direi che questo ha senso se puoi facilmente riassumere e implementare ciascuno dei casi d'uso, diciamo, di un tipo numerico. L'intero punto di un sistema di tipi è quello di aiutarti a capire quando lavori con il tipo sbagliato, e questo può prendere molti problemi prima che accadano. Potrebbe anche rendere più semplice cambiare gli argomenti di un metodo se si decide, per esempio, di riordinare "position / velocity" in modo che legga meglio; tutto ciò che non corrisponde genererà un errore di compilazione.

Ma se hai un tipo che viene sempre aggiunto, sottratto a, diviso, e tutti i tipi di operazioni matematiche diverse in varie classi di servizio, e farlo senza eliminare il tipo primitivo è fastidioso, allora questo potrebbe indicare che c'è un design migliore per questo.

Poiché tutti i primitivi hanno qualcosa per cui sono usati (ovvio), è possibile applicare male questo principio; Ovviamente sarebbe eccessivo fare cose come racchiudere una proprietà "enabled: Boolean" come "enabled: EnabledState" a meno che non avessi una buona ragione (cvars, in un videogioco, potrebbe essere una buona esempio ma non ho implementato un sistema del genere prima)

    
risposta data 20.06.2015 - 20:44
fonte
0

Sono favorevole ai tipi di dominio micro come @Miki li descrive. Ho fatto entrambe le cose e il codice che ha i tipi personalizzati è più facile da gestire rispetto al codice che utilizza i tipi primitivi, specialmente nei progetti di grandi dimensioni. Apportare modifiche e / o trovare gli usi è più semplice e anche il compilatore può aiutare a rilevare gli errori. Cosa non va? Certamente, C # ha delle strutture che rendono praticamente privo l'uso di un wrapper, ad esempio, una serie di strutture è molto efficiente rispetto a una matrice di oggetti e inoltre, il CLR si integra particolarmente bene con le strutture di 1 elemento. Con Java, penso che paghi un prezzo per il wrapper (hanno già aggiunto dei tipi di valore?).

    
risposta data 21.06.2015 - 02:09
fonte
0

Se il valore è proprio questo - il valore, attenersi a utilizzarlo come un campo su un altro oggetto. La massa e la velocità sono due cose diverse, ma il fatto di aver creato un tipo separato per ciascuna non significa in realtà che non avrei mescolato le due cose quando creerei nuove istanze di quegli oggetti - in altre parole - NO, tipi semplici sono semplici per una ragione e non dovresti complicare il tuo codice con un nuovo tipo per ogni valore semplice, perché potresti stratificare dopo strato tentando di proteggere il futuro sviluppatore dagli errori, ma puoi fare così tanto.

    
risposta data 23.06.2015 - 01:49
fonte

Leggi altre domande sui tag