Domanda Perché il comportamento di Lazy.CreateFromValue è cambiato in F # tra le versioni di .NET Framework?


Ho appena riscontrato un cambiamento nel comportamento tra le versioni di framework durante la compilazione di questo pezzo di codice in F #:

let test = Lazy.CreateFromValue 1

Compilato con .NET Framework 2.0, l'espressione risulta in un oggetto Lazy "già creato", ovvero:

test.IsValueCreated = true

Quando è compilato su .NET framework 4.0, l'espressione risulta in un oggetto pigro "non valutato", ovvero:

 test.IsValueCreated = false

Solo dopo l'accesso test.Value in quest'ultimo caso i due sono equivalenti.

Non ho trovato alcun riferimento a questo cambiamento da nessuna parte, quindi la mia domanda è: perché questo si comporta in modo diverso e qual è stato il ragionamento alla base del cambiamento (si sta rompendo). A mio parere, il comportamento in .NET 2.0 ha più senso: la creazione di un oggetto Lazy da un valore concreto dovrebbe comportare un oggetto pigro "già valutato".


10
2017-12-06 17:41


origine


risposte:


Prima di .NET 4.0, il framework non è stato fornito con Lazy<'T>.

Questa è una storia antica, ma F # aveva in origine una sua implementazione Lazydistinto da quello che abbiamo oggi, puoi vederlo Qui.

Questa implementazione è stata abbandonata quando è diventato chiaro Lazy sta arrivando al quadro vero e proprio. Invece, F # 2.0 è stato spedito con la sua implementazione di System.Lazy<'T> (notare lo spazio dei nomi) in FSharp.Core montaggio. Questa è l'implementazione che puoi ancora vedere Qui. L'idea era che, una volta disponibile .NET 4.0, F # riprendesse senza problemi System.Lazy<'T> da lì, invece, senza rompere gli utenti. Che ha funzionato per la maggior parte, ma non era del tutto privo di problemi.

Noterai che l'implementazione di F # ha a CreateFromValue membro che produce un valore di tipo Lazy<'T> già contrassegnato come valutato. Il che ha un senso perfetto semanticamente, dal momento che ovviamente gli dai un valore valutato in primo luogo.

Perché allora l'implementazione di .NET 4.0 non fa lo stesso?

Se guardi il documentazione per Lazy<'T>, scoprirai che non c'è modo di crearlo in uno stato valutato. Non c'è CreateFromValue membro su di esso, e nessun costruttore prende un valore di 'T, solo un Func<'T>. CreateFromValue è effettivamente fornito come un metodo di estensione di F #.

Sarebbe abbastanza facile fornire questo metodo in modo irrinunciabile:

static member CreateFromValue(value : 'T) : System.Lazy<'T> =
    let x = System.Lazy<'T>.Create(fun () -> value)
    x.Value |> ignore
    x

ma questo non è accaduto per qualche motivo. Forse è stata una scelta deliberata - suppongo che potresti discutere sia a favore sia contro tale cambiamento - ma forse è stata una svista. Se guardi alla storia contorta di questo tipo, penso che sarai d'accordo sul fatto che potrebbe essere stato peggio.


13
2017-12-06 22:17



Il Lazy<T> la classe è stata aggiunta al framework in .NET 4. Il supporto F # per lazy è più di uno stub per consentire all'API di funzionare su .NET 2, ma non fornisce un'implementazione veramente pigra quando si utilizza questa API.

Il compilatore F # lo ha creato proprio tipo pigro per .NET 2, come previsto per la versione .NET 4. In .NET 2, il tipo pigro imposta semplicemente il valore in modo esplicito e non è veramente pigro (vedere il fonte) quando si usa CreateFromValue.

Per questo motivo, il CreateFromValue  estensione su .NET 4 è veramente pigro - istanzia il tipo pigro con una funzione che restituisce il valore. Su .NET 2, il viene invece usato il tipo interno, che soddisfa l'API di Lazy<'T>.CreateFromValue, ma non è veramente pigro.


4
2017-12-06 19:49