Re[9]: Interpolated strings: есть идеи, как подправить произ
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.04.16 09:41
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Serginio1, Вы писали:


S>>>Про чинить компилятор спрашивал, ответ — заведи отдельный метод и не страдай фигнёй


S>>А можно спросить, где явная реализация explicit строки к FormattableString? Совсем отстал от жизни

S>Я сейчас явно торможу, т.к. вообще не понял вопрос

S>Можешь как-нибудь переформулировать?


Откуда приведение строки к FormattableString?
Assert(x > 0, (FormattableString)$"Value of x ({x}) be should be greater than zero.");
и солнце б утром не вставало, когда бы не было меня
Re[10]: Interpolated strings: есть идеи, как подправить прои
От: Sinix  
Дата: 20.04.16 11:05
Оценка: 7 (1)
Здравствуйте, Serginio1, Вы писали:


S>Откуда приведение строки к FormattableString?


А, там прикол в следующем: если нет другой подходящей перегрузки, как вот тут:
        // Других перегрузок нет
        static void AssertState(bool condition, IFormattable message)
        {
            if (!condition)
                throw new InvalidOperationException(message.ToString());
        }


то авторы шарпа считают, что сгенерить FormattableString — это нормально.
(в параметре использован IFormattable вместо FormattableString, т.к. собирается под 4.5, там FormattableString нет)

А вот если рядом есть перегрузка с строкой, то использовать FormattableString внезапно становится некомильфо — перегрузка для FormattableString автоматом не выберется никогда, только если явный каст сделать.

UPD ещё одно следствие этого решения — extension-методов для interpolated string не работают.

Т.е.
$"Version {2.0}".InvariantCulture(); // Version 2.0 even with Russian locale

не сработает. На что я уже напоролся в пришедшем с продакшна логе — парсер благополучно сломался на числах, выведенных в левой культуре.

При Хейлсберге такой фигни не было
Отредактировано 20.04.2016 12:34 Sinix . Предыдущая версия .
Re[11]: Interpolated strings: есть идеи, как подправить прои
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.04.16 11:16
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Serginio1, Вы писали:



S>>Откуда приведение строки к FormattableString?


S>А, там прикол в следующем: если нет другой подходящей перегрузки, как вот тут:

S>
S>        // Других перегрузок нет
S>        static void AssertState(bool condition, IFormattable message)
S>        {
S>            if (!condition)
S>                throw new InvalidOperationException(message.ToString());
S>        }
S>


S>то авторы шарпа считают, что сгенерить FormattableString — это нормально.

S>(в параметре использован IFormattable вместо FormattableString, т.к. собирается под 4.5, там FormattableString нет)

S>А вот если рядом есть перегрузка с строкой, то использовать FormattableString внезапно становится некомильфо — перегрузка для FormattableString автоматом не выберется никогда, только если явный каст сделать.


Это я понимаю. То есть
строка $"Value of x ({x}) be should be greater than zero."); не что иное как IFormattable ?

Нашел https://msdn.microsoft.com/ru-ru/library/dn961160.aspx
и солнце б утром не вставало, когда бы не было меня
Отредактировано 20.04.2016 11:18 Serginio1 . Предыдущая версия .
Re[6]: Interpolated strings: есть идеи, как подправить произ
От: xy012111  
Дата: 20.04.16 11:18
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Я до сих пор не могу понять, пользователи действительно считают что решарпер пишут тупые фичеписцы, или просто когда критикуешь решарпер почему-то не хочется думать что за инспекциями стоял какой-то здравый смысл...


П>Что касается проблемы с assert-методами: мы просто продолбали этот сценарий, …



П>…который конечно здорово подкашивает веру в единообразие кода форматирования строк


Это полдела; важнее, что заставляет думать о первом ("что решарпер пишут…") Вот опубликуй вы какой-нить "Кодекс РеШарпера", из которого пользователям было бы ясно, как вы себе представляете код, который они, пользователи, пишут и где вы видите ту асимптоту, к которой считаете нужным приблизить этот код — не пришлось бы обижаться на такие подозрения. Сказали бы просто — зри в кодекс, в нашу модель пользовательского кода.

И интересно было бы многим, и с тонкими такими моментами стало бы ясно что делать: просить до- или перепилить или настроить сразу себе правила.

П>Мы определенно подточим инспекцию …

П>Мы вас слышим и обязательно починим этот кейс, спасибо большое что вынесли на обсуждение!

Re[12]: Interpolated strings: есть идеи, как подправить прои
От: Sinix  
Дата: 20.04.16 12:05
Оценка: 7 (1)
Здравствуйте, Serginio1, Вы писали:

Не совсем так. Interpolated string — это конструкция, которая не имеет прямого аналога в IL. Ну, как лямбды, await, итераторы и тд и тп.

Она может быть превращена компилятором в несколько представлений, как минимум в
String.Format("Value of x ({0}) be should be greater than zero", x);

и
FormattableStringFactory.Create("Value of x ({0}) be should be greater than zero", x);


Но в будущем могут появиться любые другие.
Re[11]: Interpolated strings: есть идеи, как подправить прои
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.04.16 09:20
Оценка:
Здравствуйте, Sinix, Вы писали:
S>А вот если рядом есть перегрузка с строкой, то использовать FormattableString внезапно становится некомильфо — перегрузка для FormattableString автоматом не выберется никогда, только если явный каст сделать.
Интересно, что помешало им всегда генерить FormattableString, и добавить в него implicit conversion в System String.
Тогда бы всё работало как интуитивно ожидается c точки зрения перегрузки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: Interpolated strings: есть идеи, как подправить прои
От: Jack128  
Дата: 21.04.16 09:29
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Sinix, Вы писали:

S>>А вот если рядом есть перегрузка с строкой, то использовать FormattableString внезапно становится некомильфо — перегрузка для FormattableString автоматом не выберется никогда, только если явный каст сделать.
S>Интересно, что помешало им всегда генерить FormattableString, и добавить в него implicit conversion в System String.
S>Тогда бы всё работало как интуитивно ожидается c точки зрения перегрузки.

Помимо перегрузок есть еще много всего.
Например, если сделать как ты предлагаешь, то:
string str = "Hello, world";
string world = "world";

if (str.Equals($"Hello, {world}")) 
{
  // А сюда мы не попадем string.Equals(FormatableString) очевидно вернет false
}
Отредактировано 21.04.2016 9:32 Jack128 . Предыдущая версия .
Re[12]: Interpolated strings: есть идеи, как подправить прои
От: Sinix  
Дата: 21.04.16 10:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Интересно, что помешало им всегда генерить FormattableString, и добавить в него implicit conversion в System String.

S>Тогда бы всё работало как интуитивно ожидается c точки зрения перегрузки.

Как я понял, тогда был бы нужен костыль для случаев
var s = $"Hello, {Name}!";

чтоб s был строкой.

Точнее, пришлось бы добавить оптимизацию компилятора — заменять FormattableString на string.Format(...), если FormattableString не нужен.
Ну и плюс отразить это всё внятно в спецификации, тоже задача не из лёгких.
Чтоб было совсем весело — изменение затрагивает overload resolution (сразу сложность x10) + поведение должно быть одинаковым что для dynamic, что для expression trees.


Но это чисто моё мнение, официальное лучше в issues рослина спросить.
Re: Interpolated strings: есть идеи, как подправить производител
От: Venom  
Дата: 08.06.16 07:05
Оценка: 42 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Бенчмарк:

S>FormattableString как параметр не прикрутишь, таргетинг на 4.5 стоит, там этого типа нет.

А как ты затаргетил на 4.5?
У меня при таргете 4.5 (точнее 4.5.2) не компилируется с:

error CS0518: Predefined type 'System.Runtime.CompilerServices.FormattableStringFactory' is not defined or imported

Причем студия не выдает ошибку в Error List'е, а только в Output'е: https://github.com/dotnet/roslyn/issues/7093 , но это пофиг.

При таргете на 4.6:

Formattable: 188ms, ips: 53 079 655,05 | Mem: 3 708,13 kb, GC 0/1/2: 104/0/0 => 10000000
FormattableNoArg: 171ms, ips: 58 412 306,77 | Mem: 608,07 kb, GC 0/1/2: 38/0/0 => 10000000
FormattableInt: 62ms, ips: 159 577 693,59 | Mem: 2 504,03 kb, GC 0/1/2: 28/0/0 => 10000000
String: 33ms, ips: 300 022 801,73 | Mem: 8,00 kb, GC 0/1/2: 0/0/0 => 10000000
String.Format: 127ms, ips: 78 166 220,47 | Mem: 3 104,03 kb, GC 0/1/2: 66/0/0 => 10000000
FuncNoClosure: 43ms, ips: 228 267 246,16 | Mem: 8,00 kb, GC 0/1/2: 0/0/0 => 10000000
FuncClosure: 99ms, ips: 100 312 372,73 | Mem: 1 208,04 kb, GC 0/1/2: 76/0/0 => 10000000
FuncClosureFormat: 96ms, ips: 103 399 571,10 | Mem: 1 208,04 kb, GC 0/1/2: 76/0/0 => 10000000

Т.е. разница не в 120 раз, а примерно в 6.
Re[2]: Interpolated strings: есть идеи, как подправить производител
От: Sinix  
Дата: 08.06.16 07:33
Оценка: 4 (1)
Здравствуйте, Venom, Вы писали:

V>А как ты затаргетил на 4.5?

V>У меня при таргете 4.5 (точнее 4.5.2) не компилируется с:
Это я криво описал проблему. Сама библиотека под 4.5 и внутри неё FormattableString не поддерживаются, понятное дело.
А вот использующий библиотеку код вполне может быть с таргетом 4.6.

V>Т.е. разница не в 120 раз, а примерно в 6.

Угу. Результаты в стартовом топике под x64, у тебя x86, так?

Для более честного сценария надо [MethodImpl(MethodImplOptions.NoInlining)] на методы навесить, а то jit может заинлайнить вызов ассерта и вытащить строку за тело цикла (что он по-моему и делает). Тогда примерно то же, что у тебя получается.
А по факту главная проблема не в времени, а в избыточных аллокациях и тут надо во всех методах с params object[] args делать перегрузки с 1-2-3 аргументами.

Или просто писать код в стиле
if (!condition)
  throw CodeExceptions.InvalidOperation($"Bad value {value};")


Остаётся ещё одна засада — с культурой, для дат и для для дробных чисел фигня выводится. И что самое обидное, я пока не знаю как её красиво решить даже для простого string.Format, который используется в CodeExceptions.
Re[3]: Interpolated strings: есть идеи, как подправить производител
От: Venom  
Дата: 08.06.16 08:35
Оценка:
Здравствуйте, Sinix, Вы писали:

V>>Т.е. разница не в 120 раз, а примерно в 6.

S>Угу. Результаты в стартовом топике под x64, у тебя x86, так?

У меня Any CPU.
Еще в Project Properties->Build крыжик на "Prefer 32bit" стоит, который никак не отражен в .csproj, но возможно влияет.
  .csproj

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>



Я понял в чем была проблема: это был Configuration = Debug, с запуском по Ctrl+F5.
С Configuration=Release, с запуском по Ctrl+F5, и в 4.6, и в 4.6.1. результат для String = 2-3ms.
Re[4]: Interpolated strings: есть идеи, как подправить производител
От: Sinix  
Дата: 08.06.16 08:42
Оценка: 8 (2) :)
Здравствуйте, Venom, Вы писали:

V>У меня Any CPU.

V>Еще в Project Properties->Build крыжик на "Prefer 32bit" стоит, который никак не отражен в .csproj, но возможно влияет.
Вот он и влияет. В Debug может быть собирается?

V>Я понял в чем была проблема: это был Configuration = Debug, с запуском по Ctrl+F5.

V>С Configuration=Release, с запуском по Ctrl+F5, и в 4.6, и в 4.6.1. результат для String = 2-3ms.
Угадал)))

Это по-моему результат слишком агрессивного JIT,
https://alexandrnikitin.github.io/blog/hoisting-in-net-explained/
Re[13]: Interpolated strings: есть идеи, как подправить прои
От: hardcase Пират http://nemerle.org
Дата: 19.06.16 20:38
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Как я понял, тогда был бы нужен костыль для случаев

S>
S>var s = $"Hello, {Name}!";
S>

S>чтоб s был строкой.

Чтобы s был строкой и все было клево нужно всего-то вспомнить, что .NET — это как бы про ООП, и следовало запилить тип FormattableString как наследник System.String.
Хотя тут больше проблема не в типах, а в порядке вычисления. В ассертах мы имеем тот случай, когда необходима ленивость для вычисления ряда аргументов: форматной строки и всех ее параметров. Это в сущности фундаментальная проблема, так как CLR не предоставляет из коробки иных моделей вычисления кроме энергичной.
/* иЗвиНите зА неРовнЫй поЧерК */
Отредактировано 19.06.2016 20:45 hardcase . Предыдущая версия . Еще …
Отредактировано 19.06.2016 20:44 hardcase . Предыдущая версия .
Re[14]: Interpolated strings: есть идеи, как подправить прои
От: Sinix  
Дата: 20.06.16 05:54
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Чтобы s был строкой и все было клево нужно всего-то вспомнить, что .NET — это как бы про ООП, и следовало запилить тип FormattableString как наследник System.String.

Зануда mode: Liskov плачет и рыдает. Всё равно, что наследовать корову от молока

Если серьёзно — нету там хорошего решения. Более того, на практике if ... throw оказывается если и не удобнее, то уж точно не хуже. Сравни
Code.AssertState(
    someLongCondition || someAnotherCondition || whatever,
    $"Long {text} no one going to read bla-bla-bla and {so_on}.");

vs

if (!someLongCondition && !someAnotherCondition && !whatever)
    throw CodeExceptions.InvalidOperation(
        $"Long {text} no one going to read bla-bla-bla and {so_on}.")


Поэтому лично я просто использую второй вариант, как порождающий меньше всего WTF.


H>Хотя тут больше проблема не в типах, а в порядке вычисления.


Ну так не решит оно исходную проблему, перфоманс будет проседать из-за аллокации замыканий. Тут только code rewrite поможет. Ну, или старый-добрый if, что и быстрее, и проще.
Re[15]: Interpolated strings: есть идеи, как подправить прои
От: hardcase Пират http://nemerle.org
Дата: 20.06.16 11:05
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, hardcase, Вы писали:


H>>Чтобы s был строкой и все было клево нужно всего-то вспомнить, что .NET — это как бы про ООП, и следовало запилить тип FormattableString как наследник System.String.

S>Зануда mode: Liskov плачет и рыдает. Всё равно, что наследовать корову от молока

Это смотря как посмотреть. С точки зрения языка обе конструкции
$"..."
и
"..."
есть строки, вот только первая несколько более сложным образом вычисляется.

H>>Хотя тут больше проблема не в типах, а в порядке вычисления.


S>Ну так не решит оно исходную проблему, перфоманс будет проседать из-за аллокации замыканий.


Это если мыслить в нынешней принятой стратегии вычисления в CLR. Для эффективной реализации ассертов и логирования конструкцию
$""
следует рассматривать как ленивые вычисления — строка физически вычисляется ровно тогда, когда становится необходимым ее куда-то передать.


S>Если серьёзно — нету там хорошего решения. Более того, на практике if ... throw оказывается если и не удобнее, то уж точно не хуже. Сравни

S>
S>Code.AssertState(
S>    someLongCondition || someAnotherCondition || whatever,
S>    $"Long {text} no one going to read bla-bla-bla and {so_on}.");

S>vs

S>if (!someLongCondition && !someAnotherCondition && !whatever)
S>    throw CodeExceptions.InvalidOperation(
S>        $"Long {text} no one going to read bla-bla-bla and {so_on}.")
S>


Вопрос первого или второго синтаксиса — это вопрос вкуса. Но принимая во внимание нынешнее положение дел, то вторая запись предпочтительнее. Здесь уместно вспомнить assert-макросы Nemerle, которые переписывают первый вариант во второй, и бакс-строки разворачиваются ровно когда они становятся необходимыми чтобы бросить исключение.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Interpolated strings: есть идеи, как подправить производител
От: Kolesiki  
Дата: 20.06.16 12:57
Оценка: 21 (1)
Здравствуйте, Sinix, Вы писали:

S>Code.AssertState(someCondition, "Message #{0}", 123);

S>ну, т.е. обычная перегрузка и вариант с строкой форматирования.
S>в 99.99% случаев ассерт не срабатывает, форматирование не требуется.
S>Ну и как с этим жить?

Вынести ассерты на уровень языка? (как это сделано в D)
Re[2]: Interpolated strings: есть идеи, как подправить производител
От: Sinix  
Дата: 20.06.16 13:16
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Вынести ассерты на уровень языка? (как это сделано в D)

Не, сама по себе поддержка со стороны языка тут ничем не поможет, т.к. нужны произвольные типы исключений, поддержка вызова произвольных методов + выдача произвольных сообщений пользователю.
Т.е. возвращаемся к исходной проблеме.

Что будет без "произвольные типы исключений" и далее по списку — см на CodeContracts. Сама по себе идея шикарная, общий подход примерно тот же, что и в D, только вот на практике они неюзабельны абсолютно.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.