Здравствуйте, _NN_, Вы писали:
_NN>Интересная дискуссия про ассоциативность операции "?." в C#: https://roslyn.codeplex.com/discussions/543895 _NN>В Nemerle она лево-асссоциатвна, а в C# похоже будет право-асссоциатвной.
Тут надо развеять некоторые мифы. Это не вопрос ассоциативности, и в Roslyn отсутствует оператор ?.. В Roslyn есть бинарный оператор ?, который вычисляет свой левый операнд, и если он не null, то вычисляет правый операнд. Правый операнд может (и должен) начинаться на токены . или [, которые парсятся, соответственно, как начало member access или element access, в которых отсутствует явный левый операнд (здесь можно усмотреть синтаксическую аналогию с выражениями .Foo в VB внутри With блоков). В рантайме (и в compile-time с целью проверки типов) в качестве отсутствующего операнда подставляется значение левого операнда innermost enclosing бинарного оператора ?.
Если бы не дополнительное требование (существующее исключительно для упрощения данной конструкции), что токены . или [ должны следовать непосредственно за токеном ?, то выражение a ? .b.c(d()).e можно было бы записать как a ? (((.b).c(d())).e).
Бинарный оператор ? является лево-ассоциативным.
Окончательная версия спецификации, возможно, будет давать объяснение в несколько других терминах, но с точки зрения наблюдаемого поведения компилятора, оно будет в точности соответствовать тому, что я написал (по крайней мере, таковы текущие планы). Синтаксические деревья, которые выдаёт Roslyn API, соответствуют тому, что я написал.
Здравствуйте, nikov, Вы писали:
N>Я так понял, что он интересуется, что означает выражение a?.b.c в Nemerle. N>Или же это (a?.b).c (что может бросить NRE, если (a?.b) даёт null), или оно имеет смысл a ? («значение-a-если-не-null».b.c) аналогично Roslyn C# (ни свойство b, ни свойство c не вычисляются, если a даёт null).
Реализована вторая семантика: если a != null, то вычисляем цепочку дальше.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, nikov, Вы писали:
N>>Я так понял, что он интересуется, что означает выражение a?.b.c в Nemerle. N>>Или же это (a?.b).c (что может бросить NRE, если (a?.b) даёт null), или оно имеет смысл a ? («значение-a-если-не-null».b.c) аналогично Roslyn C# (ни свойство b, ни свойство c не вычисляются, если a даёт null).
H>Реализована вторая семантика: если a != null, то вычисляем цепочку дальше.
А если равен null ?
В C# 6 аналогичный код не будет приводить к NRE:
using System.Console;
def x = (null : string)?.Trim().Replace("a", "b");
WriteLine(x);
System.NullReferenceException
ncc :
string text = null;
string text2 = null;
if (text != null)
{
text2 = text.Trim();
}
string value = text2.Replace("a", "b");
Console.WriteLine(value);
ncc -debug- -optimize :
string text = null;
string text2 = null;
if (text2 != null)
{
text = text2.Trim();
}
text2 = text.Replace("a", "b");
Console.WriteLine(text2);
. Q>Т.е. чаще нужна проверка a на null, чем a.b, так что ли?
Неважно, что нужно чаще. Важно, что иногда нужно одно, а иногда другое. В существующем в Roslyn дизайне можно написать a?.b.c, если ты хочешь только проверить a на null (если a.b вдруг окажется null, то это ошибка, которую не нужно маскировать, передавая null дальше, а нужно бросить исключение). Но можно написать и a?.b?.c, если и a, и b могут оказаться null, и в таком случае ты хочешь заменить результат вызова c на null. Также ещё можно написать (a?.b).c, явно поставив скобки, и это будет третий вариант, который тоже имеет смысл в ограниченном числе случаев (например, когда .c — это .HasValue, .GetValueOrDefault() или extension method, позволяющий null в качестве первого аргумента). Roslyn позволяет тебе написать именно то выражение, которое тебе требуется по смыслу.
Здравствуйте, VladD2, Вы писали:
VD>Возможно хватит изменения силы связывания (приоритетов) у препаратора ".?". Нужно сделать его меньшим чем у ".". Тогда код будет разбираться так: VD>
VD>def x = (null : string)?.(Trim().Replace("a", "b"));
VD>
VD>что решит проблему (я надеюсь).
Я не думаю, что метод Trim() сам догадается, у какого объекта вызываться.
Здравствуйте, _NN_, Вы писали:
_NN>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, _NN_, Вы писали:
_NN>>>Nemerle: _NN>>>a?.b().c() --> (a?.b()).c() --> (if(a != null) a else null).b().c() А>>не рабочая конструкция А>>если a==null -> error
_NN>Об этом и говорят в обсуждении
Но более сложна конструкция уже рабочая.
Точно написал?
Здравствуйте, _NN_, Вы писали:
_NN>Одна из причин это упрощение кода, чтобы не писать каждый раз "?." и уменьшить количество проверок.
_NN>C# _NN>a?.b().c() --> a?.(b().c()) --> if(a != null) a.b().c() else null
Чушь какая-то. Ассоциативность имеет смысл когда один и тот же оператор применяется более одного раза. В твоем примере "?." одни. Ассоциативность в нем просто ни на что не действует.
Правая ассоциативность означает, что выражение:
a?.b?.c?.d будет интерпретировано как a?.(b?.(c?.d)), а не как ((a?.b)?.c)?.d.
Я даже не представляю как интерпретировать правоассоцитивный вариант.
Ты явно путаешь понятия.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Ты сначала приведи внятный пример демонстрирующий хотя бы какое-то преимущество, а потом поговорим.
Ну вот пример из обсуждения рослина:
string ReturnStringOrNull() { .. }
var x = ReturnStringOrNull()?.Trim().Substring(1,2).Replace("a","b");
Методы String не возвращают null, поэтому можно обойтись одной проверкой, а не каждый раз.
Т.е. писать множество ?. не нужно будет.
VD>Ассоциативность у "?." такая же как у ".", чтобы они вместе нормально компоновались в выражение. Ну, и чтобы людей не удивлять.
Вот и у них обсуждение, что вроде логично считать все слева направо, а можно и сэкономить количество проверок.
Здравствуйте, _NN_, Вы писали:
_NN>Ну вот пример из обсуждения рослина:
_NN>
_NN>string ReturnStringOrNull() { .. }
_NN>var x = ReturnStringOrNull()?.Trim().Substring(1,2).Replace("a","b");
_NN>
Где тут второй "?.". Я же кажется рядом уже говорил, что ассоциативность возникает только когда операторов больше двух. В противном случае речь идет о приоритете.
Короче, разберись в терминах и переформулируй вопрос.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Где тут второй "?.". Я же кажется рядом уже говорил, что ассоциативность возникает только когда операторов больше двух. В противном случае речь идет о приоритете.
Ну да, в данном случае речь о приоритете, я запутался
Здравствуйте, VladD2, Вы писали:
N>>в Roslyn отсутствует оператор ?.. В Roslyn есть бинарный оператор ?
VD>О, как? И как разруливается неоднозначность с тернарным оператором?
Если следующий токен . или [, то это бинарный оператор, иначе — тернарный.
Здравствуйте, nikov, Вы писали:
N>В Roslyn есть бинарный оператор ?, который вычисляет свой левый операнд, и если он не null, то вычисляет правый операнд. Правый операнд может (и должен) начинаться на токены . или [, которые парсятся, соответственно, как начало member access или element access N>...Если бы не дополнительное требование (существующее исключительно для упрощения данной конструкции), что токены . или [ должны следовать непосредственно за токеном ?, то выражение a ? .b.c(d()).e можно было бы записать как a ? (((.b).c(d())).e).
Ну, тогда это ничем не отличается от операторов "?." и "?[". Только можно пробелы вставить в середину.
N>Бинарный оператор ? является лево-ассоциативным.
В немерле мы "?[" не реализовывали. Как-то на практике не требовалось.
Я только не понял, что NN хочет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Я только не понял, что NN хочет.
Я так понял, что он интересуется, что означает выражение a?.b.c в Nemerle.
Или же это (a?.b).c (что может бросить NRE, если (a?.b) даёт null), или оно имеет смысл a ? («значение-a-если-не-null».b.c) аналогично Roslyn C# (ни свойство b, ни свойство c не вычисляются, если a даёт null).
Ну, наконец-то ты объяснил свою мысль. Нужно было привести данный пример в тематическом сообщении. Тогда и бадяги бы на 5 экранов не было бы.
Да, согласен, так лучше. Попробуй переделать. Возможно хватит изменения силы связывания (приоритетов) у препаратора ".?". Нужно сделать его меньшим чем у ".". Тогда код будет разбираться так:
def x = (null : string)?.(Trim().Replace("a", "b"));
что решит проблему (я надеюсь).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, nikov, Вы писали:
N>Бинарный оператор ? является лево-ассоциативным.
Кстати, недавно переделали на право-ассоциативный. Это довольно редко заметно на практике (как и с оператором ??), но в некоторых случаях даёт лучшую диагностику ошибок и позволяет избавиться от definite assignment errors в случаях вроде