Size: a a a

F# Flood: Be a cheif

2021 January 29

IC

Ilya Chernoudov in F# Flood: Be a cheif
в юзинге
источник

DS

Doge Shibu in F# Flood: Be a cheif
Ilya Chernoudov
я тебе показываю, что нету каста
Потому что это generic метод
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
то. что декомпилятор показывает тебе как каст - не каст
источник

DS

Doge Shibu in F# Flood: Be a cheif
Ilya Chernoudov
то. что декомпилятор показывает тебе как каст - не каст
источник

DS

Doge Shibu in F# Flood: Be a cheif
Я про такой пример
источник

DS

Doge Shibu in F# Flood: Be a cheif
Который и должен получаться при наивном lowering'е IDIsposable, но который вручную заменяется в компиляторе, чтобы бокса избежать
источник

DS

Doge Shibu in F# Flood: Be a cheif
Вот тебе буквально комментарий из исходников компилятора, как оно должно быть по спеке и как они делают, чтобы не было бокса:
            // SPEC: When ResourceType is a non-nullable value type, the expansion is:
           // SPEC:
           // SPEC: {
           // SPEC:   ResourceType resource = expr;
           // SPEC:   try { statement; }
           // SPEC:   finally { ((IDisposable)resource).Dispose(); }
           // SPEC: }
           // SPEC:
           // SPEC: Otherwise, when Resource type is a nullable value type or
           // SPEC: a reference type other than dynamic, the expansion is:
           // SPEC:
           // SPEC: {
           // SPEC:   ResourceType resource = expr;
           // SPEC:   try { statement; }
           // SPEC:   finally { if (resource != null) ((IDisposable)resource).Dispose(); }
           // SPEC: }
           // SPEC:
           // SPEC: Otherwise, when ResourceType is dynamic, the expansion is:
           // SPEC: {
           // SPEC:   dynamic resource = expr;
           // SPEC:   IDisposable d = (IDisposable)resource;
           // SPEC:   try { statement; }
           // SPEC:   finally { if (d != null) d.Dispose(); }
           // SPEC: }
           // SPEC:
           // SPEC: An implementation is permitted to implement a given using statement
           // SPEC: differently -- for example, for performance reasons -- as long as the
           // SPEC: behavior is consistent with the above expansion.
           //
           // In the case of using-await statement, we'll use "IAsyncDisposable" instead of "IDisposable", "await DisposeAsync()" instead of "Dispose()"
           //
           // And we do in fact generate the code slightly differently than precisely how it is
           // described above.
           //
           // First: if the type is a non-nullable value type then we do not do the
           // *boxing conversion* from the resource to IDisposable. Rather, we do
           // a *constrained virtual call* that elides the boxing if possible.
           //
           // Now, you might wonder if that is legal; isn't skipping the boxing producing
           // an observable difference? Because if the value type is mutable and the Dispose
           // mutates it, then skipping the boxing means that we are now mutating the original,
           // not the boxed copy. But this is never observable. Either (1) we have "using(R r = x){}"
           // and r is out of scope after the finally, so it is not possible to observe the mutation,
           // or (2) we have "using(x) {}". But that has the semantics of "using(R temp = x){}",
           // so again, we are not mutating x to begin with; we're always mutating a copy. Therefore
           // it doesn't matter if we skip making *a copy of the copy*.
источник

DS

Doge Shibu in F# Flood: Be a cheif
И по спеке там везде должен быть каст
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
Doge Shibu
Который и должен получаться при наивном lowering'е IDIsposable, но который вручную заменяется в компиляторе, чтобы бокса избежать
            // SPEC:   ResourceType resource = expr; 
           // SPEC:   try { statement; }
           // SPEC:   finally { ((IDisposable)resource).Dispose(); }
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
вот компилятор делает ровно это
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
и делает он это потому что нельзя сравнивать структуры с null
источник

DS

Doge Shibu in F# Flood: Be a cheif
Ilya Chernoudov
            // SPEC:   ResourceType resource = expr; 
           // SPEC:   try { statement; }
           // SPEC:   finally { ((IDisposable)resource).Dispose(); }
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
разница между не структурами - проверка на null
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
нет, ты можешь поменять значение resource
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
поэтому у тебя такое поведенеи
источник

DS

Doge Shibu in F# Flood: Be a cheif
И там в IL явные:
            IL_001a: box C/A
           IL_001f: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose()
           IL_0024: nop
источник

DS

Doge Shibu in F# Flood: Be a cheif
Это мы буквально получим, если будем делать lowering по спеке
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
Doge Shibu
Это мы буквально получим, если будем делать lowering по спеке
потому что ты явно пишешь
источник

IC

Ilya Chernoudov in F# Flood: Be a cheif
вообще каст там нужен для имплисит реализации
источник

AH

Ayrat Hudaygulov in F# Flood: Be a cheif
Начал интервьюировать в МС, кадры как всегда поражают.
Ждите прохладных историй
источник