Il comportamento è estremamente simile al Array.Resize
metodo in .NET. Per capire cosa sta succedendo, può essere utile esaminare la cronologia del .
token in C, C ++, Java, C # e Swift.
In C, una struttura non è altro che un'aggregazione di variabili. Applicando .
a una variabile di tipo struttura si accederà a una variabile memorizzata all'interno della struttura. I puntatori agli oggetti non contengono aggregazioni di variabili, ma le identificano . Se uno ha un puntatore che identifica una struttura, l' ->
operatore può essere utilizzato per accedere a una variabile memorizzata all'interno della struttura identificata dal puntatore.
In C ++, le strutture e le classi non solo aggregano le variabili, ma possono anche associare il codice ad esse. L'uso .
di invocare un metodo richiederà a una variabile quel metodo di agire sul contenuto della variabile stessa ; l'utilizzo ->
su una variabile che identifica un oggetto chiederà a quel metodo di agire sull'oggetto identificato dalla variabile.
In Java, tutti i tipi di variabili personalizzati identificano semplicemente gli oggetti e invocando un metodo su una variabile dirà al metodo quale oggetto è identificato dalla variabile. Le variabili non possono contenere direttamente alcun tipo di tipo di dati composito, né esiste alcun modo per cui un metodo può accedere a una variabile su cui viene invocato. Queste restrizioni, anche se semanticamente limitanti, semplificano notevolmente l'autonomia e facilitano la convalida del bytecode; tali semplificazioni hanno ridotto il sovraccarico di risorse di Java in un momento in cui il mercato era sensibile a tali problemi, e quindi l'hanno aiutato a guadagnare trazione sul mercato. Significavano anche che non era necessario un token equivalente a quello .
utilizzato in C o C ++. Sebbene Java avrebbe potuto usare ->
allo stesso modo di C e C ++, i creatori hanno optato per l'uso di un carattere singolo.
poiché non era necessario per nessun altro scopo.
In C # e altri linguaggi .NET, le variabili possono identificare oggetti o contenere direttamente tipi di dati compositi. Se utilizzato su una variabile di un tipo di dati composito, .
agisce sul contenuto della variabile; se utilizzato su una variabile di tipo di riferimento, .
agisce sull'oggetto identificatoda esso. Per alcuni tipi di operazioni, la distinzione semantica non è particolarmente importante, ma per altri lo è. Le situazioni più problematiche sono quelle in cui il metodo di un tipo di dati composito che modifica la variabile su cui viene invocato viene invocato su una variabile di sola lettura. Se si tenta di invocare un metodo su un valore o una variabile di sola lettura, i compilatori generalmente copiano la variabile, lasciano agire il metodo su di essa e scartano la variabile. Questo è generalmente sicuro con i metodi che leggono solo la variabile, ma non con i metodi che vi scrivono. Sfortunatamente, .does non ha ancora alcun mezzo per indicare quali metodi possono essere tranquillamente utilizzati con tale sostituzione e quali no.
In Swift, i metodi sugli aggregati possono indicare espressamente se modificheranno la variabile su cui vengono invocati e il compilatore vieterà l'uso di metodi mutanti su variabili di sola lettura (piuttosto che farli mutare copie temporanee della variabile che poi scartato). A causa di questa distinzione, l'utilizzo del .
token per chiamare metodi che modificano le variabili su cui vengono invocate è molto più sicuro in Swift che in .NET. Sfortunatamente, il fatto che lo stesso .
token venga utilizzato a tale scopo per agire su un oggetto esterno identificato da una variabile significa che rimane la possibilità di confusione.
Se avesse una macchina del tempo e tornasse alla creazione di C # e / o Swift, si potrebbe evitare retroattivamente gran parte della confusione che circonda tali problemi facendo in modo che le lingue utilizzino i token .
e ->
in un modo molto più vicino all'utilizzo del C ++. I metodi di entrambi gli aggregati e i tipi di riferimento potrebbero utilizzare .
per agire sulla variabile su cui sono stati invocati e ->
per agire su un valore (per i composti) o sulla cosa identificata in tal modo (per i tipi di riferimento). Nessuna delle due lingue è progettata in questo modo, tuttavia.
In C #, la pratica normale per un metodo di modificare una variabile su cui viene invocata è passare la variabile come ref
parametro a un metodo. Pertanto, chiamare Array.Resize(ref someArray, 23);
quando someArray
identifica un array di 20 elementi farà someArray
identificare un nuovo array di 23 elementi, senza influire sull'array originale. L'uso di ref
chiarisce che il metodo dovrebbe prevedere la modifica della variabile su cui è invocato. In molti casi, è vantaggioso poter modificare le variabili senza utilizzare metodi statici; Indirizzi rapidi che significa utilizzando la .
sintassi. Lo svantaggio è che perde il chiarimento su quali metodi agiscono sulle variabili e quali metodi agiscono sui valori.