Doge
Что и является в неком роде тем самым дак тайпингом о котором тут и говорили
Doge
Потому что в компиляторе именно для IDisposable + using + value типа зашито это поведение
Ilya
Там была фраза "не во всех случаях"
приведи пример, когда это не так с using
Ilya
Ilya
мы точно об одном говорим?
Roman
нет
Ilya
нет
тогда как это относится к using и Dispose?
Ilya
вот какого хера Dispose на реф структах работает в юзинге, а в обычных нет???
Ilya
имеется в виду что имплементация IDisposable не нужна на реф структах
Ilya
почему нельзя было сделать для любых типов
Ilya
это же все компайл тайм сахар с юзингом
Ilya
но ведь это выгодно для структур
Ilya
нет каста к интерфейсам -_-
Ilya
почему только для реф структур - неясно
Ilya
прям зОгадка
Ilya
Не понял ща, чем выгодно в данном случае?
Ilya
Без каста в тырфейс
Ilya
В каком месте каст?
Ilya
В юзинге для структур нет каста
Ilya
Бля в обычных структурах. В обычных
Ilya
Именно, поэтому я не понял, чем тебе поможет дипозабл для структур
Ilya
На дак тацйпинге
Ilya
затем, чтобы struct A : IDisposable {}; using var a = new A(); работало без боксинга
Doge
На дак тацйпинге
Ну смотри пример с дак тайпингом (прям настоящим) для ref struct'ов: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBLANgHwAEAmARgFgAoKwgZgAJYAzegZwygFcwN6BBegG8q9enTEp6AEWysADhFYwAFAEohI0VsKkAnMoBEAGQi4DqgNyaAvlVvVK4kvQDCGylrENCkgLJr3T09CAAZlADsYAHd+NXVhDyCknX0DADkIXlxTcytEpPtPe2sgA===
Doge
Вот тебе настоящий дак тайпинг, даже без всякого IDisposable и каста в него
Doge
А вот и сам дак тайпинг в компиле для желающих: https://github.com/chsienki/roslyn/blob/master/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs#L199 Причём он работает и для асинк диспозаблов, внезапно: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBLANgHwAEAmARgFgAoQgBgAJDSBWAbiqsIGY6BnDKAK5gMdAIKi6Abyp0G3QkjoARbDwAOEHjFE8AngDswACgCUdALwA+GbNsKAdACUB+o6YuWGpAJxGARAAyELh+JiZslFQAvuzU3LAAZrz8QiIS0pSyXAwoyqoaWu4ZtnY+/kEh4TYxlDUc8sR0AMJSNlnyuQCyRW0lDDRG+jAA7mKmZsV9U4y+fgByECK4waERU7I1JZu2vdmEABwMip2kPZnrhN79gyNiouOt5+uls6IAykrvSqu9W701USAA==
Крылатый
А меж тем https://twitter.com/wesleywiser/status/1354896012113022984
Крылатый
Бегу!
Ilya
Вот тебе настоящий дак тайпинг, даже без всякого IDisposable и каста в него
ты просто смотришь не туда, смотри на jit (каста нет даже в IL) дак тайпинг и с интрефейсом код абсолютно идентичен
Ilya
Я смотрю туда, это как раз то о чём говорил @omgszer
я просто смотрю и не вижу боксинга
Ilya
вот прям хоть убей
Ilya
IL_000c: constrained. A IL_0012: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose()
Doge
ты просто смотришь не туда, смотри на jit (каста нет даже в IL) дак тайпинг и с интрефейсом код абсолютно идентичен
Потому что именно для Disposable кодген одинаковый у вскх случаев и там будет не бокс, а IL_000c: constrained. A IL_0012: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose()
Doge
И про такую реализацию явно сказано в lowering'е для disposable, который я выше кидал
Doge
Если ты попробуешь сделать каст в свой интерфейс (не диспозабл), то ты получишь бокс в IL
Ilya
https://t.me/fsharp_flood/284148
Doge
а этот кейс тут причём?
Потому что вся работа с IDisposable'ом + структурами явно зашита в компиль, чтобы не генерить бокс, который будет, если это преобразование кода делать наивно. Это прям конкретный хак под это конкретное место, о котором напрямую в комменте и сказано.
Ilya
IL_0000: nop IL_0001: ldarga.s item IL_0003: constrained. !!T IL_0009: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose() IL_000e: nop IL_000f: ret
Doge
Это опять IDisposable
Doge
Ты попробуй с любым другим интерфейсом
Ilya
Это тут причём?
мой интерфейс, точно так же нет
Ilya
Ilya
какой диспозабл?
Doge
public struct A:IA
Только метод ты генеришь для T: IDisposable
Ilya
Только метод ты генеришь для T: IDisposable
https://sharplab.io/#v2:C4LglgNgNAJiDUAfAAgJgIwFgBQyAMABMugHQAyYAdgI4DcO+R6ALPbgMxGoEDCBA3jgLCinZMwIBZdAB4AKgD4AFHIJhgAUwC2ASgDuACw0AnDQTkgAkgEEBQkcPXaSAETABnAA4B7dxqU6bA4AvvbCYQQRyJxUmsYAZgCGAMZmNhGC2A7iBG5evv6BEaFZIlGc7sDGAK7JwATWVtYZEdliEnk+fgH8JSFhOMFAA===
Ilya
сорян
Ilya
IL_0000: nop IL_0001: ldarga.s item IL_0003: constrained. !!T IL_0009: callvirt instance void C/IA::Dispose() IL_000e: nop
Doge
Ты попробуй явно каст сделать и увидешь результат
Ilya
А это потому что тут generic метод без каста
я тебе показываю, что нету каста
Ilya
в юзинге
Doge
я тебе показываю, что нету каста
Потому что это generic метод
Ilya
то. что декомпилятор показывает тебе как каст - не каст
Doge
то. что декомпилятор показывает тебе как каст - не каст
https://sharplab.io/#v2:C4LglgNgNAJiDUAfAAgJgIwFgBQyAMABMugHQAyYAdgI4DcO+R6ALPbgMxGoEDCBA3jgLCinZMwIBZdAAoAlIOwiRMmQEkAgnMoBTAO4EN8uSQAiYAM4AHAPYWd8tsoC+QkW+EfRBKsB0AnADMAQwBjHQJNL0VlcQJzazsHOScRVyV3DOFkTgtgfwBXUOBDECisgS9YsQkE23t5fnSXDxxnIA===
Doge
Я про такой пример
Doge
Который и должен получаться при наивном lowering'е IDIsposable, но который вручную заменяется в компиляторе, чтобы бокса избежать
Doge
Вот тебе буквально комментарий из исходников компилятора, как оно должно быть по спеке и как они делают, чтобы не было бокса: // 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*.
Doge
И по спеке там везде должен быть каст
Ilya
вот компилятор делает ровно это
Ilya
и делает он это потому что нельзя сравнивать структуры с null
Doge
// SPEC: ResourceType resource = expr; // SPEC: try { statement; } // SPEC: finally { ((IDisposable)resource).Dispose(); }
Нет, потому что если бы он делал так, то получился бы бокс: https://sharplab.io/#v2:C4LglgNgNAJiDUAfAAgJgIwFgBQyAMABMugHQAyYAdgI4DcO+R6ALPbgMxGoEDCBA3jgLCinZMwIBZdAAoAlIOwjlBAIIEATgFMAzgHsArhoDGWggF4ClLQHc182gSErhwDQE8BTAJwyARGQA8mR+co4Avk5KLgQAZlQAhhAQnvwEMjIAkgAiYDoADno6CQBGEFpy2vpGpnIkuQVFWg4E4c7CbdHC7VHKyJxUwFoasQmmBJmqPYp9Eg2FOs1hPZ3KPf0EOm4GxsBqIBPzRaXl0z19YnN5C0v8qyL3UeFAA==
Ilya
разница между не структурами - проверка на null
Ilya
поэтому у тебя такое поведенеи
Doge
И там в IL явные: IL_001a: box C/A IL_001f: callvirt instance void [System.Private.CoreLib]System.IDisposable::Dispose() IL_0024: nop
Doge
Это мы буквально получим, если будем делать lowering по спеке
Ilya
вообще каст там нужен для имплисит реализации
Ayrat
Начал интервьюировать в МС, кадры как всегда поражают. Ждите прохладных историй