Devi avere la boxe dei primitivi in lingua OO?

4

La boxe dei primitivi è richiesta nei linguaggi OO per mantenerli coerenti con il resto del sistema degli oggetti (generici ecc.)?

O è evitabile - è possibile evitare qualsiasi costo aggiuntivo per le prestazioni di avere sia primitive che oggetti in una lingua?

Una soluzione che riesco a individuare immediatamente sta avendo riferimenti abbastanza grandi da contenere i valori di ogni possibile tipo primitivo.

Esistono altre (migliori) soluzioni e sono implementate nelle lingue popolari?

    
posta mrpyo 08.05.2014 - 20:51
fonte

6 risposte

5

A causa del modo in cui i processori sono architettati, è necessario il pugilato a un certo livello per ottenere sia un'efficienza ragionevole sia un modello di tipo unificato. Tuttavia, il boxing non deve essere specificato manualmente dal programmatore e in alcune lingue viene gestito automaticamente dietro le quinte per te.

Prendi Scala, per esempio. Int è derivato da un AnyVal , che è derivato da un Any , che è la classe di livello superiore di Scala. Sintatticamente, puoi trattarlo come qualsiasi altro oggetto, ma il compilatore lo tratterà come una primitiva in contesti appropriati, facendo internamente il pugilato e l'unboxing se necessario. Il punto è che il programmatore non deve preoccuparsi. Ancora più bello, in Scala si sta implementando utilizzando impliciti , in modo che i programmatori possano implementare senza problemi i propri automatismi personalizzati boxing e unboxing se quelli built-in non sono sufficienti.

Se non sei abbastanza fortunato da usare un linguaggio come Scala, i farmaci generici possono ovviare alla necessità del pugilato manuale in molte situazioni.

    
risposta data 08.05.2014 - 21:25
fonte
6

Esistono vari approcci adottati da altre lingue, che evitano di avere tipi di valori separati "in scatola" e "non in scatola".

  • In Python, tutti i valori (dai numeri interi agli oggetti) si comportano allo stesso modo quando usati come riferimenti. Potrebbe sembrare che i valori semplici agiscano in modo diverso, ma ciò è dovuto al fatto che tipi come int e str oggetti sono immutabili. Un approccio simile è preso da Ruby e dalla maggior parte degli altri popolari linguaggi di tipo "scripting".

  • In Lisp, un valore può essere un numero o un riferimento a una cella di controllo. Alcune implementazioni combinano queste parole in una singola parola di macchina riservando uno o due dei bit più alti nella parola per indicare il tipo di valore. Ad esempio, uno 0 nel bit più alto potrebbe significare un valore intero, ma un 1 indica l'indirizzo di una cella di controllo. (Ci possono essere altre regolazioni applicate come lo spostamento del valore dell'indirizzo lasciato un paio di bit per accedere all'intero spazio di indirizzamento, possibile perché il LSB dei bit di indirizzo è sempre 0 a causa di vincoli di allineamento.Tutto ciò dipende molto dall'implementazione.)

  • In C ++, il meccanismo generico (modelli) consente di scrivere codice generico in grado di gestire tipi primitivi come int e puntatori polimorfici. Il meccanismo sottostante in realtà compila il codice generico più di una volta a seconda del tipo effettivo con cui viene creato il modello generico.

risposta data 08.05.2014 - 22:23
fonte
2

No. La boxe è richiesta solo quando si ha a che fare con un "oggetto", cioè dove il tipo è sconosciuto. Dati i generici senza cancellazione di tipo, non c'è quasi nessuna ragione per farlo.

Il motivo per cui Java e .Net hanno il pugilato è perché i generici sono stati aggiunti in seguito. La ragione per cui Java fa più boxing di .Net è una conseguenza di Java che fa più boxe del necessario e in parte come hanno deciso di implementare i generici.

Anche i "tipi primitivi" sono a loro volta un ottimizzazione delle prestazioni / dimensioni, in quanto tale è certamente concepibile per un sistema in cui tale ottimizzazione è stata considerata non necessaria.

L'unico caso d'uso che posso pensare per il pugilato in .net dato generici è il tag sui controlli - cioè una classe che espone una proprietà per gli utenti della classe, e non per l'uso nella classe. E anche lì, il pugilato potrebbe essere evitato richiedendo che sia una classe non primitiva, un po 'di lavoro extra, ma non in modo irragionevole.

    
risposta data 08.05.2014 - 23:00
fonte
2

Mi stai chiedendo di tipi e oggetti primitivi, ma non penso che sia una distinzione utile qui. Invece, dovresti pensare ai tipi di riferimento e ai tipi di valore:

  • Tipi di valore : sempre esattamente del tipo specificato (non può essere invece un tipo derivato); non è possibile utilizzare la funzione di invio virtuale; lifetime legato all'ambito della variabile (solitamente allocata nello stack)
  • Tipi di riferimento : può essere il tipo specificato o un tipo derivato; può utilizzare la funzione di invio virtuale; durata non legata all'ambito della variabile (solitamente allocata sullo heap)

Se osservi queste differenze, ti rendi conto che entrambi i tipi hanno alcuni pregi: i tipi di valore sono più performanti, mentre i tipi di riferimento sono più flessibili, specialmente se si desidera utilizzare le funzionalità OOP come ereditarietà o funzioni virtuali.

Questo è il motivo per cui molte lingue (incluso C ++, C # e Java) offrono entrambe in una forma o nell'altra (sebbene la forma sia molto varia).

Ora abbiamo due tipi di tipi, ma vorremmo anche avere un sistema di tipi unificato. E questo significa avere un tipo, in cui le variabili di questo tipo possono contenere valori di qualsiasi tipo. Questo requisito significa che il tipo (chiamato Object in C # e Java) deve essere un tipo di riferimento. E per convertire un tipo di valore in questo tipo di Object , devi "box": crea una copia del valore che si comporta come un tipo di riferimento.

Per riassumere: una lingua deve supportare la boxe, se si desidera avere tipi di riferimento, tipi di valore e un sistema di tipi unificato.

    
risposta data 10.05.2014 - 16:36
fonte
0

Dipende dalla lingua.

In C # 1.0 / 1.1, il pugilato era inevitabile abbastanza spesso - quando un metodo ha un parametro object e uno ha provato a passare in un tipo di valore (pensate al tipo primitivo, sebbene non esattamente), doveva essere inscatolato in ordine da passare come tipo di riferimento.

Con il supporto di C # 2 e generici, la maggior parte di questo tipo di boxe è andato via, poiché è possibile utilizzare un tipo generico.

    
risposta data 08.05.2014 - 20:55
fonte
0

VB6 includeva tipi "varianti" che potevano memorizzare primitive o riferimenti a oggetti, quindi è possibile . La semantica dei tipi di varianti VB6 era assolutamente orribile e non suggerirei che qualsiasi linguaggio provasse a emularli.

Altrimenti, mentre in alcuni rari casi potrebbe essere utile definire un tipo aggregato che contiene un riferimento a un oggetto e qualcosa di simile a un int64 i cui bit potrebbero essere interpretati come necessari per rappresentare qualsiasi tipo primitivo, generalmente non si può fare nulla di utile con un tipo di variante a meno che non si sappia cosa dovrebbe essere, e se si sa cosa si suppone che un tipo sia uno non ha realmente bisogno di una variante. In un framework come .NET che ha tipi generici "reali", la boxe è raramente necessaria e in quei contesti in cui è necessario, sarebbe probabilmente più utile avere tutti tipi ricevere uno strato di boxe ( in modo che un riferimento di tipo Animal che identifica un Cat , verrebbe classificato come "Riferimento inscatolato di tipo Animale che identifica un gatto").

    
risposta data 10.05.2014 - 06:40
fonte

Leggi altre domande sui tag