L’estensione non può contenere proprietà archiviate, ma perché è consentita la statica

L’estensione non può contenere proprietà archiviate, ma perché quindi la proprietà statica memorizzata può essere definita all’interno dell’estensione?

Inoltre, non ho trovato alcuna documentazione che menzionasse che la proprietà statica è consentita in estensione.

extension String { static let test = "Test" static var test2 = "Test2" } 

Le estensioni non possono contenere proprietà di istanze memorizzate. Perché? Perché l’aggiunta di una proprietà di istanza cambierebbe la dimensione delle istanze di quel tipo. Cosa succede se un modulo aggiunge un’estensione tale che un Int ora è lungo 2 parole? Cosa dovrebbe accadere quando, ad esempio, ottiene un Int da un altro modulo dove hanno ancora 1 word in termini di dimensioni?

Il motivo per cui le proprietà statiche memorizzate sono permesse nelle estensioni è semplicemente perché hanno una durata statica; esistono indipendentemente dalle istanze del tipo specificato che stai estendendo. In realtà non sono nient’altro che variabili globali memorizzate, solo un namespace di un tipo. Pertanto possono essere aggiunti liberamente senza influenzare il codice che è già stato compilato senza la conoscenza di essi.

Vale la pena notare tuttavia che attualmente esistono tre restrizioni sulla definizione delle proprietà statiche memorizzate.

1. Non è ansible definire una proprietà static memorizzata su un tipo generico

Ciò richiederebbe lo stoccaggio separato delle proprietà per ogni singola specializzazione dei segnaposti generici. Ad esempio, con:

 struct S { static var foo: Int { return 5 } static let bar = "" // error: Static stored properties not supported in generic types } 

Proprio come foo viene chiamato sulla specializzazione individuale di S , ad esempio S.foo e S.foo e non su S stesso (infatti, S non è nemmeno un tipo al momento, richiede che T sia soddisfatto); bar sarebbe (probabilmente) lo stesso. Sarebbe chiamato come, per esempio, S.bar , non S.bar .

Questo è un dettaglio importante perché il metatipo su cui viene chiamato un membro statico viene passato al ricevitore come argomento implicito di self . Questo è accessibile nelle espressioni di inizializzazione delle proprietà statiche; quindi permettendo loro di chiamare altri metodi statici.

Pertanto, essere in grado di chiamare lo stesso inizializzatore di proprietà statiche su specializzazioni differenti di un tipo generico potrebbe potenzialmente creare valori di proprietà diversi per ciascuno (si consideri il caso semplice di static let baz = T.self ). Pertanto abbiamo bisogno di una memoria separata per ciascuno di essi.

Tuttavia, detto tutto, non c’è una vera ragione per cui il compilatore / runtime non può farlo, e potrebbe benissimo farlo in una versione futura della lingua. Anche se un argomento contro questo è che in alcuni casi può produrre un comportamento confuso.

Ad esempio, considera:

 import Foundation struct S { static let date = Date() } 

Se il runtime generava implicitamente nuovo spazio di archiviazione per la date ogni volta che si accede a una nuova specializzazione di S , allora S.date non sarebbe uguale a S.date ; che può essere fonte di confusione e / o indesiderabile.

2. Non è ansible definire una proprietà static memorizzata in un’estensione di protocollo

Questo segue principalmente dal punto precedente. Una proprietà static memorizzata in un’estensione di protocollo richiederebbe una memoria separata per ogni tipo conforms di quel protocollo (ma ancora una volta, non c’è motivo per cui il compilatore / runtime non possa farlo).

Ciò è necessario con i protocolli, poiché static membri static nelle estensioni di protocollo non sono membri del tipo di protocollo stesso. Sono membri di tipi concreti conformi al protocollo.

Ad esempio, se abbiamo:

 protocol P {} extension P { static var foo: Int { return 5 } static let bar = "" // error: Static stored properties not supported in generic types // (not really a great diagnostic) } struct S : P {} struct S1 : P {} 

Non possiamo accedere a foo sul tipo di protocollo stesso, non possiamo dire P.foo . Possiamo solo dire S.foo o S1.foo . Questo è importante perché il getter di foo può richiamare i requisiti del protocollo statico su self ; tuttavia ciò non è ansible se self è P.self (cioè il tipo di protocollo stesso ), poiché i protocolli non sono conformi a se stessi .

Lo stesso dovrebbe (probabilmente) seguire per static proprietà static memorizzate come la bar .

3. Non è ansible definire una proprietà memorizzata di class

Non credo che ci sarebbe alcun problema con una tale dichiarazione nel corpo della class stessa (sarebbe semplicemente equivalente a una proprietà di class calcasting sostenuta da una proprietà static immagazzinata).

Tuttavia, sarebbe potenzialmente problematico nelle estensioni, perché le estensioni non possono aggiungere nuovi membri a una class Swift vtable (sebbene possano aggiungersi alla controparte Obj-C, se applicabile). Pertanto nella maggior parte dei casi non sarebbero spediti dynamicmente (quindi sarebbe effettivamente final , e quindi static ). Nonostante ciò, class proprietà calcolate in class sono attualmente consentite nelle estensioni, pertanto potrebbe essere consentita nell’interesse della coerenza.