Багофича C# - object initializer
От: Baiker  
Дата: 21.07.24 19:50
Оценка:
Ребят, столкнулся с какой-то маразматической особенностью C# (на которую у MS конечно же есть объяснения), но моeй инженерной логике она не поддаётся.
Всё очень просто:

class A
{
    public int P = 666;
}

class B : A
{
    public int P1 = 4;
    public int P2;

    public B()
    {
        P = 13;
    }
}

// где-то в коде решили создать класс B:

var b = new B { P2 = P1 + P };// ошибка прокладки между стулом и монитором!


...и..... ннна тебе поддых канпелятором!! В object initializer ни мембера P, ни P1 канпелятор НЕ ВИДИТ!
Что это за маразм?? Что за такой странный контекст вдруг образовался в элементарном инициализаторе?
Я-то (наивный) думал, что {} — это просто сокращение для b.P2 = b.P1 + b.P ! Похоже, мелкомягкие что-то там намудрили под капотом.

Примером выше я хотел иллюстрировать несколько другой маразм:

Форма из WinForms
   Метод()
   {
      var c = new UserControl {
          Left = Width / 2
      };
   }


Здесь в OI свойство Left КАК И ПОЛОЖЕНО — от UserControl, но Width оказывается берётся от самой формы(!!!). С какого перепоя??
Ведь Width должно браться из самого внутреннего контекста, т.е. от UserControl! Что за бредовая логика заставляет MS лезть в объемлющий контекст?

PS
А я ведь ещё на заре этой дебильной фичи предлагал: не надо этой узколобой привязки инициализатора к конструктору!! Надо, чтобы это работало как with в Паскале:

var j = new J();
// какой-то посторонний код
j init {
    .p1 = 3;
    .fn();// ДА! И ВЫЗОВ ФУНКЦИЙ ТОЖЕ!!
    p2 = .p1;
}

var j2 = new J() init {
   .p1 = p2 + 6;
}


Здесь j во-первых может инициализироваться в ЛЮБОМ месте кода, а во-вторых, чётко видно кто и откуда берётся: ".p1" — это внутренний мембер (потому что с точки),
"p2" — мембер из объемлющего контекста. Просто и универсально как лом. Что помешало неумытым "синьорам" с индийских пальм сделать это по-человечески?
Re: Багофича C# - object initializer
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.07.24 02:35
Оценка: 2 (1) +3 -1
Здравствуйте, Baiker, Вы писали:

B>Ребят, столкнулся с какой-то маразматической особенностью C# (на которую у MS конечно же есть объяснения), но моeй инженерной логике она не поддаётся.

B>// где-то в коде решили создать класс B:

B>var b = new B { P2 = P1 + P };// ошибка прокладки между стулом и монитором!


B>...и..... ннна тебе поддых канпелятором!! В object initializer ни мембера P, ни P1 канпелятор НЕ ВИДИТ!

Всё верно. Initializer исполняется в том же скоупе, где и new statement.
B>Что это за маразм?? Что за такой странный контекст вдруг образовался в элементарном инициализаторе?
Он как раз не образовался. С чего вы ожидали, что он там будет образовываться?
B>Я-то (наивный) думал, что {} — это просто сокращение для b.P2 = b.P1 + b.P ! Похоже, мелкомягкие что-то там намудрили под капотом.
Да, совершенно верно — баг в вашей логике. {} — это просто сокращение для b.P2 = P1 + P . Откуда вы там взяли справа префиксы b. — никакой логике не поддаётся.

B>Примером выше я хотел иллюстрировать несколько другой маразм:


B>
B>Форма из WinForms
B>   Метод()
B>   {
B>      var c = new UserControl {
B>          Left = Width / 2
B>      };
B>   }
B>


B>Здесь в OI свойство Left КАК И ПОЛОЖЕНО — от UserControl, но Width оказывается берётся от самой формы(!!!). С какого перепоя??

Эмм. А когда вы пишете руками c.Left = Width / 2, вас не удивляет то, что Width берётся из контекста, а не из c?
B>Ведь Width должно браться из самого внутреннего контекста, т.е. от UserControl! Что за бредовая логика заставляет MS лезть в объемлющий контекст?
Нет конечно, с чего вы взяли, что Width должно браться откуда-то ещё, кроме объемлющего контекста?

B>PS

B>А я ведь ещё на заре этой дебильной фичи предлагал: не надо этой узколобой привязки инициализатора к конструктору!!
B>Здесь j во-первых может инициализироваться в ЛЮБОМ месте кода, а во-вторых, чётко видно кто и откуда берётся: ".p1" — это внутренний мембер (потому что с точки),
B> "p2" — мембер из объемлющего контекста. Просто и универсально как лом. Что помешало неумытым "синьорам" с индийских пальм сделать это по-человечески?
Наверное, то, что предлагаемый вами подход создаёт больше проблем, чем решает. В частности, не очень понятно, как быть с вложенными инициализаторами.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Багофича C# - object initializer
От: Baiker  
Дата: 23.07.24 13:12
Оценка:
Здравствуйте, Sinclair, Вы писали:

B>>var b = new B { P2 = P1 + P };// ошибка прокладки между стулом и монитором!

B>>...и..... ннна тебе поддых канпелятором!! В object initializer ни мембера P, ни P1 канпелятор НЕ ВИДИТ!

S>Всё верно. Initializer исполняется в том же скоупе, где и new statement.


Это "объяснение" никак не объясняет, почему тогда виден P2!
Кроме того, OI — это вам не "скобочки для if" — это специфическая часть, которая работает (у MS) только после new.

Итак, ваше очко переходит зрителям, а вопрос так и остаётся неотвеченным. Перефразирую:

А накой ляд тогда делать вообще OI, если он такой кривой???
Вопрос-уточнение: мне не интересно, что думал Хлипперт и как конкретно он реализовал эту багофичу. С инженерной точки зрения что мешает видеть P1 и P?


B>>Я-то (наивный) думал, что {} — это просто сокращение для b.P2 = b.P1 + b.P ! Похоже, мелкомягкие что-то там намудрили под капотом.

S>Да, совершенно верно — баг в вашей логике. {} — это просто сокращение для b.P2 = P1 + P . Откуда вы там взяли справа префиксы b. — никакой логике не поддаётся.

Чушь полная. См. вопрос-уточнение выше.


B>>PS

B>>А я ведь ещё на заре этой дебильной фичи предлагал: не надо этой узколобой привязки инициализатора к конструктору!!
B>>Здесь j во-первых может инициализироваться в ЛЮБОМ месте кода, а во-вторых, чётко видно кто и откуда берётся: ".p1" — это внутренний мембер (потому что с точки),
B>> "p2" — мембер из объемлющего контекста. Просто и универсально как лом. Что помешало неумытым "синьорам" с индийских пальм сделать это по-человечески?

S>Наверное, то, что предлагаемый вами подход создаёт больше проблем, чем решает. В частности, не очень понятно, как быть с вложенными инициализаторами.


Наверное, может надо ПОДУМАТЬ и реализовать? Я сейчас не могу спонталыку просто взять и углубиться в тему компиляторостроения, но если вы приведёте пример такого вот "не очень понятно", то можно поговорить хотя бы о часностях.
Опережающий ответ:
1. Никто не сказал, что можно будет делать вложенные иниты. В конце концов, 99.999999% кода — это как раз простые донельзя конструкции одного уровня.
2. Если они будут вложенные и как-то конфликтовать, ВСЕГДА можно посидеть и придумать какое-то интересное решение.

Главное — БАЗОВАЯ ЛОГИКА должна быть инженерная, а не "у нас тут индусокод и вот так исторически сложилось".

В конце концов, для чего вообще придумывать фичи, кроме как для УДОБСТВА ПРОГРАММИСТА? И на поверку оказалось, что OI-сахарок — чёрте что и полностью обламывает прямую логику разработчика.
Re[2]: Багофича C# - object initializer
От: Baiker  
Дата: 23.07.24 13:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

B>>PS

B>>А я ведь ещё на заре этой дебильной фичи предлагал: не надо этой узколобой привязки инициализатора к конструктору!!

S>Наверное, то, что предлагаемый вами подход создаёт больше проблем, чем решает. В частности, не очень понятно, как быть с вложенными инициализаторами.


По моему конкретному варианту в постскриптуме — вам нравится его реализация? Если нет — давайте обсудим возражения. Если нравится, давайте в рамках предложенного синтаксиса посмотрим на конкретный пример, где "создаёт больше проблем, чем решает". По-моему, как раз мой вариант стократ универсальнее мелкомягкого (напомню — он помогает вообще ВЕЗДЕ в коде, а не только после new).

Вот интересный пример со вложенностью, но я тут "множества нерешённых проблем" не вижу, дополняйте:

int Width = 7;// обычная переменная в outer scope

var btn = new Button init B { // внимание! 'B' - это alias для создаваемого объекта (во внешнем scope это btn)
    .Width = Width + 50;// Button.Width = Width + 50 = 57
    .Invalidate();// такое MS не сделала даже за 20 лет!
    .Height = .Width + 1;// очевидно, что справа от = всё тот же контекст - взяли внутреннего мембера .Width
    .Children.Add(niceIcon);
    .Styles = new HTMLStyle init { // как и просили, вложенный init
        .CSS = "color: #" + .Color;// Button.Color взят извне, т.к. HTMLStyle его не содержит
        .File = 1;// error! Нет такого мембера ни у HTMLStyle, ни у Button, внешний scope не рассматривается
        .Length = B.Length - 7;// ага! Вот где alias нужен. Вот теперь это HTMLStyle.Length = Button(B).Length - 7
    };
};
Отредактировано 23.07.2024 13:40 Baiker . Предыдущая версия .
Re[3]: Багофича C# - object initializer
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.07.24 14:47
Оценка: 2 (1) +1
Здравствуйте, Baiker, Вы писали:
B>Это "объяснение" никак не объясняет, почему тогда виден P2!
Он не "виден", он — часть инициализатора.
Вы же заметили, что в object initializer нельзя слева написать произвольное lvalue? А только свойства инициализируемого объекта?

B>Кроме того, OI — это вам не "скобочки для if" — это специфическая часть, которая работает (у MS) только после new.

Всё верно. И она работает предсказуемым, понятным, и устойчивым к мелким изменениям образом.

B>А накой ляд тогда делать вообще OI, если он такой кривой???

Для упрощения инициализации объектов с большим количеством свойств, лишь малая часть которых нужна в каждом конкретном случае. Ваш К.О.
B>Вопрос-уточнение: мне не интересно, что думал Хлипперт и как конкретно он реализовал эту багофичу. С инженерной точки зрения что мешает видеть P1 и P?
То, что это принесёт больше вреда, чем пользы.

B>Наверное, может надо ПОДУМАТЬ и реализовать?

Может быть. Пока что видно, что ПОДУМАТЬ не желаете как раз вы.

Я сейчас не могу спонталыку просто взять и углубиться в тему компиляторостроения, но если вы приведёте пример такого вот "не очень понятно", то можно поговорить хотя бы о часностях.
B>Опережающий ответ:
B>1. Никто не сказал, что можно будет делать вложенные иниты.
И как вы собираетесь их запретить? На всякий случай поясню, что Object Initializer — это expression. И его, естественно, можно поставить в любое место, где нужен expression.
То есть примерно везде — включая объемлющий object initializer.
B>В конце концов, 99.999999% кода — это как раз простые донельзя конструкции одного уровня.
Основная ценность object initializer — как раз конструирование сложных деревьев объектов. Если у вас простая линейная конструкция, то вам не нужен никакой object initializer — просто напишите цепочку присваиваний свойств.

B>2. Если они будут вложенные и как-то конфликтовать, ВСЕГДА можно посидеть и придумать какое-то интересное решение.

Проблема не в том, чтобы придумать решение. А в том, чтобы это решение не приводило к трудноуловимым багам и WTF. В том числе и в corner cases.

Вот вам простой пример. Версия кода 1:
public class Foo
{
  public string DisplayName {get;set;} 
  public int Number {get; init;}
  public Foo(int number)
  { 
    Number = number;
    DisplayName = number.ToString();
  }
}

public class Bar
{
  public string Name {get; init;}
  public List<Foo> Foos {get; } = new();
  public Bar(int seed) => Name = $"Bar #{new Random(seed).Next()}";
}

public class Program
{
  public static void Main()
  {
    var b = new Bar(42) {
      Foos = {
        new Foo(1) { DisplayName = Name + ":" + Number},
        new Foo(2) { DisplayName = Name + ":" + Number}
      }
    };
  }
}

вроде всё хорошо, да? Name берётся из "текущего" Bar, Number — из "текущего" Foo.
Теперь автор класса Foo, который ничего не знает о коде Main (и, может быть, даже о коде Bar) публикует версию 2, добавляя невинно выглядящее свойство:

public class Foo
{
  public string Name {get;set;}
  public string DisplayName {get;set;}
  public int Number {get; init;}
  public Foo(int number)
  { 
    Number = number;
    Name = number.ToString();
    DisplayName = number.ToString();
  }
}

Автор Main забирает апдейт, компилирует. Всё успешно. Когда он получит баг репорт, он долго пытается понять, почему хорошо отлаженный код вдруг стал выдавать какую-то ересь.
Но вопрос даже не в этом — ну, допустим, он понял, в чём дело. Что ему теперь делать? Как вы предлагаете ему писать код Main так, чтобы он работал как в предыдущем случае?

B>Главное — БАЗОВАЯ ЛОГИКА должна быть инженерная, а не "у нас тут индусокод и вот так исторически сложилось".

Совершенно верно. Базовая логика как раз инженерная.

B>В конце концов, для чего вообще придумывать фичи, кроме как для УДОБСТВА ПРОГРАММИСТА? И на поверку оказалось, что OI-сахарок — чёрте что и полностью обламывает прямую логику разработчика.

Обламывает он только лично вас — и то потому, что вы вместо изучения инструмента придумываете неудачные варианты того, как он мог бы (а точнее — не мог бы) работать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Багофича C# - object initializer
От: Baiker  
Дата: 23.07.24 15:02
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

B>>2. Если они будут вложенные и как-то конфликтовать, ВСЕГДА можно посидеть и придумать какое-то интересное решение.

S>Проблема не в том, чтобы придумать решение. А в том, чтобы это решение не приводило к трудноуловимым багам и WTF. В том числе и в corner cases.

Все подобные вещи надо обдумывать, тестировать, проверять на существующей кодовой базе — НИЧЕГО сложного или нереализуемого.
И по факту, "пришлёпка" сахара в виде мелкомягкой OI — это самая тупая и ограниченная реализация того, что могло бы быть.


S> new Foo(1) { DisplayName = Name + ":" + Number},

S>вроде всё хорошо, да? Name берётся из "текущего" Bar, Number — из "текущего" Foo.
S>Теперь автор класса Foo, который ничего не знает о коде Main (и, может быть, даже о коде Bar) публикует версию 2, добавляя невинно выглядящее свойство:
S> public string Name {get;set;}

S>Но вопрос даже не в этом — ну, допустим, он понял, в чём дело. Что ему теперь делать? Как вы предлагаете ему писать код Main так, чтобы он работал как в предыдущем случае?


См. пример из дополненного мной коммента.
Re[3]: Багофича C# - object initializer
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.07.24 16:30
Оценка: 12 (1) +1
Здравствуйте, Baiker, Вы писали:

B>По моему конкретному варианту в постскриптуме — вам нравится его реализация?

Нет, не нравится.

B>Если нет — давайте обсудим возражения.


B>Вот интересный пример со вложенностью, но я тут "множества нерешённых проблем" не вижу, дополняйте:


B>
B>int Width = 7;// обычная переменная в outer scope

B>var btn = new Button init B { // внимание! 'B' - это alias для создаваемого объекта (во внешнем scope это btn)
B>    .Width = Width + 50;// Button.Width = Width + 50 = 57
B>    .Invalidate();// такое MS не сделала даже за 20 лет!
B>    .Height = .Width + 1;// очевидно, что справа от = всё тот же контекст - взяли внутреннего мембера .Width 
B>    .Children.Add(niceIcon);
B>    .Styles = new HTMLStyle init { // как и просили, вложенный init
B>        .CSS = "color: #" + .Color;// Button.Color взят извне, т.к. HTMLStyle его не содержит
B>        .File = 1;// error! Нет такого мембера ни у HTMLStyle, ни у Button, внешний scope не рассматривается
B>        .Length = B.Length - 7;// ага! Вот где alias нужен. Вот теперь это HTMLStyle.Length = Button(B).Length - 7
B>    };
B>};
B>

Вот видите — первый же заданный вопрос заставил вас менять синтаксис. Теперь в init появился опциональный алиас. Причём теперь нужно не забыть его указать, иначе получится бяка.
Двигаемся дальше. Вот у вас в .Styles не было .Color, а вот он появился. Всё, поведение кода поменялось, без малейших подсказок со стороны компилятора. Удачной отладки.
Коммент про .File — а что, если бы у Button было такое свойство, то всё бы скомпилировалось?

Двигаемся дальше. В чём у нас семантика этого init? Слева от него — некое object expression, справа — опциональный алиас плюс некий блок кода.
Что это за блок кода такой? А это такой блок кода, где (это я угадываю телепатически)
1. Определён указанный выше алиас, если он есть
2. Разрешены только операторы присваивания и вызовы методов (причём не любых, см далее)
3. В аргументах методов и в выражениях операторов присваивания разрешены обращения к свойствам и методам через точку без object expression слева.

Для начала нужно убедиться, что у нас нет проблем с п.3. Не будет ли конфликтов при разборе? Я пока вижу один нехороший сценарий: взаимодействие с тернарным оператором и null-checking member access. Выражения типа x > y ? .Inc() похожи и на x > (y?.Inc()), и на (x > y)?.Inc()). А теперь у нас ещё и добавляется прекрасная возможность (x > y) ? (.Inc()), то есть "Syntax error, : expected".
Когда мы с этим разберёмся, захочется понять, какие именно методы можно вызывать, а какие — нет. Способ поиска методов слева от =, справа от =, и просто при записи .Invalidate() будет отличаться? Я так понимаю, что для "справа от = " вы хотите, чтобы выполнялся поиск вверх во всех init-блоках, пока не найдется подходящий метод. Будет ли это работать также без =? То есть если я пишу btn init{.Styles init {.Invalidate()}}; — будет ли успешно вызываться btn.Invalidate()?
Рассматриваются ли extension-методы?

Самое интересное тут вот в чём: как будем разруливать перегрузки методов? На всякий случай: в С# итак уже весьма навороченные (и местами неожиданные) правила байндинга вызовов (см. пример). Теперь вы предлагаете добавить к этой кунсткамере ещё одно измерение: подбор подходящего this в иерархии инициализируемых объектов. Как вы себе это видите — хотя бы в общих чертах? Вот у нас завелись два похожих метода: Button.Foo(int i), HtmlStyle.Foo(decimal d). Мы наблюдаем такое выражение: btn init{.Styles init {.Length = .Foo(42)}};. Какой из Foo будет вызван? Можно позвать .Styles.Foo — 42 implicitly convertible to decimal, и он доступен во внутреннем scope. Но, может быть, надо звать btn.Foo — ведь он better fit, т.к. там вообще не надо преобразовывать параметры? Или лучше всё же падать с CS0121: The call is ambiguous? Примерно к любому варианту, который вы выберете, я напишу контрпример, который работает "не так, как интуитивно ожидается".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 24.07.2024 8:05 Sinclair . Предыдущая версия . Еще …
Отредактировано 23.07.2024 16:34 Sinclair . Предыдущая версия .
Re[4]: Багофича C# - object initializer
От: Baiker  
Дата: 03.09.24 01:19
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

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


B>>
B>>int Width = 7;// обычная переменная в outer scope

B>>var btn = new Button init B { // внимание! 'B' - это alias для создаваемого объекта (во внешнем scope это btn)
B>>    .Width = Width + 50;// Button.Width = Width + 50 = 57
B>>    .Invalidate();// такое MS не сделала даже за 20 лет!
B>>    .Height = .Width + 1;// очевидно, что справа от = всё тот же контекст - взяли внутреннего мембера .Width 
B>>    .Children.Add(niceIcon);
B>>    .Styles = new HTMLStyle init { // как и просили, вложенный init
B>>        .CSS = "color: #" + .Color;// Button.Color взят извне, т.к. HTMLStyle его не содержит
B>>        .File = 1;// error! Нет такого мембера ни у HTMLStyle, ни у Button, внешний scope не рассматривается
B>>        .Length = B.Length - 7;// ага! Вот где alias нужен. Вот теперь это HTMLStyle.Length = Button(B).Length - 7
B>>    };
B>>};
B>>



S>Вот видите — первый же заданный вопрос заставил вас менять синтаксис


И что в этом такого?? Я что, принёс вам готовые спеки что ли?? Глупый наезд на почве личной опупительности. НЕ НАДО на меня наезжать! Я ни вам, ни микрософту ничего не должен.
Изменил синтаксис — значит так надо, значит СТАЛО ЛУЧШЕ. Так или иначе, я предлагаю улучшать компилятор, а не бодаться с луддитами и "исторически сложилось" факапами.

S> Теперь в init появился опциональный алиас. Причём теперь нужно не забыть его указать, иначе получится бяка.


Разумеется указать! Если он нужен. А на его нужность укажет компилятор в местах с неоднозначностями. В ЧЁМ ПРОБЛЕМА-ТО?? Я не понимаю этого агрессивного противостояния — нужно ПОМОГАТЬ МНЕ решить эту синтаксическую проблему (если она вообще есть), а не выделываться здесь "мы в микрософт все умные, а вы ничего не понимаете!".

S>Двигаемся дальше. Вот у вас в .Styles не было .Color, а вот он появился. Всё, поведение кода поменялось, без малейших подсказок со стороны компилятора. Удачной отладки.


Да, это проблема. Но не такая проблема, чтобы прям осбосраться и отменить фичу! Просто надо чутка подумать и решить, как ОБЯЗАТЕЛЬНО реализовать фичу, но предусмотреть этот сложный случай.
К примеру, сам компилятор проверит, что было использование одного объекта, а после введения члена появился другой. Ни бог весть какая проблема — БЫЛО БЫ ЖЕЛАНИЕ РЕШИТЬ.

S>Коммент про .File — а что, если бы у Button было такое свойство, то всё бы скомпилировалось?


Да. В чём проблема?

S>Двигаемся дальше. В чём у нас семантика этого init?


С самого начала поста объяснил, так сложно доходит? СОКРАЩЕНИЕ КОДА.

S>1. Определён указанный выше алиас, если он есть

S>2. Разрешены только операторы присваивания и вызовы методов (причём не любых, см далее)
S>3. В аргументах методов и в выражениях операторов присваивания разрешены обращения к свойствам и методам через точку без object expression слева.

Да, всё верно.

S>Для начала нужно убедиться, что у нас нет проблем с п.3. Не будет ли конфликтов при разборе? Я пока вижу один нехороший сценарий: взаимодействие с тернарным оператором и null-checking member access. Выражения типа x > y ? .Inc() похожи и на x > (y?.Inc()), и на (x > y)?.Inc()). А теперь у нас ещё и добавляется прекрасная возможность (x > y) ? (.Inc()), то есть "Syntax error, : expected".


Решается обычным приоритетом операторов! На крайняк, НЕТ такого оператора "?␣." — есть "?.". Пробел значим. В любом случае, ЕСТЬ СКОБКИ и подсветка/подсказка. Навёл курсор на .Inc() — увидел, от кого взят мембер.


S>Способ поиска методов слева от =, справа от =, и просто при записи .Invalidate() будет отличаться?


Нет, он должен быть одинаков (как и ожидает программист, просто СОКРАЩАЯ КОД).

S> Я так понимаю, что для "справа от = " вы хотите, чтобы выполнялся поиск вверх во всех init-блоках, пока не найдется подходящий метод. Будет ли это работать также без =? То есть если я пишу btn init{.Styles init {.Invalidate()}}; — будет ли успешно вызываться btn.Invalidate()?


Разумеется! Я же привёл пример:

B>> .Invalidate();// такое MS не сделала даже за 20 лет!


Здесь нет никакого присвоения, просто ищем подходящий объект.

S>Рассматриваются ли extension-методы?


Тут я ещё не думал, но... почему бы и нет? У компилятора ВСЕГДА есть шанс сказать, когда у него неоднозначность! Скажем, если будет код:

var lst1 = new List<File>() init {
    var lst2 = new List<File>() init {
        .Sort();// чей сорт?
    }
}

...выправляем его так:
var lst1 = new List<File>() init L {
    var lst2 = new List<File>() init {
        L.Sort();// ага, знаю чей!
    }
}


S>Самое интересное тут вот в чём: как будем разруливать перегрузки методов? Вот у нас завелись два похожих метода: Button.Foo(int i), HtmlStyle.Foo(decimal d). Мы наблюдаем такое выражение: btn init{.Styles init {.Length = .Foo(42)}};. Какой из Foo будет вызван?


Согласен, тонкий И РЕДКИЙ случай — выкинем ambiguous. Что сложного-то?? Не надо пытаться сделать больше, чем позволено "тупой машине"! (иначе сделаешь только хуже)

Тут принцип построения фич простой: запиливаем фичу для большинства случаев (предварительно хорошенько рассмотрев все случаи). Если люди дадут фидбэк "вот у нас такой часто используемый код, а он лажает на вашем синтаксисе" — повторяем SDLC и допиливаем как надо (фича всё равно в АЛЬФА ТЕСТЕ!). И так до полной шлифовки.

S>Примерно к любому варианту, который вы выберете, я напишу контрпример, который работает "не так, как интуитивно ожидается".


Да ради бога! Чем больше контр-примеров, тем шире почва для обсуждения (а не отмазок НЕ ДЕЛАТЬ). Факт тот, что фичу МОЖНО и НУЖНО сделать. Я не глубокий спец именно в компиляторах, но я знаю, что если что-то делать — то оно сделается! А если в стиле Хлипперта придумывать "почему мы НЕ ХОТИМ это делать" — то ничего и не будет.
Пока что из обсуждения я не увидел НИ ЕДИНОГО аргумента "эту фичу принципиально нельзя сделать" — ВСЁ ВОЗМОЖНО, но постепенно. А вы сейчас своей ДЕМАГОГИЕЙ пытаетесь грубо говоря "закидать шапками". Так люди НЕ КООПЕРИРУТСЯ! Мыслить надо ДРУЖЕСКИ, а не сидеть как тухлый ёж и совать всем иголки.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.