Здравствуйте, Shmj, Вы писали:
S> Теперь можно писать и так и эдак:
S>
S> int i = int.Parse(Console.ReadLine());
S> if (i == 1 || i == 3 && !(i == 5 && i != 5))
S> Console.WriteLine(1);
S> if (i is 1 or 3 and not (5 and not 5))
S> Console.WriteLine(2);
S>
S> Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Скоро вам еще begin с end'ом добавять, заживете, наконец-то, по-людски.
Здравствуйте, Shmj, Вы писали:
S>Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Совсем нет, потому что теперь можно сделать вот так в одну строку:
if (GetIQ() is < 100 and > 50)
Console.WriteLine("Hoi polloi");
Можно даже захватить походящее значение в переменную для дальнейшего использования:
if (GetIQ() is < 100 and > 50 and var iq)
Console.WriteLine("Hoi polloi IQ: {0}", iq);
Очень удобно. Или например вместо часто используемой проверки на null:
var bicycle = TryGetBicycle();
if (bicycle != null)
Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
это теперь можно делать в одну строку:
if (TryGetBicycle() is not null and var bicycle)
Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
Почему такая возможность важна? Потому что иногда это безумно удобно во вложенных if'ах, так как позволяет обойтись одним уровнем вложенности вместо плохо читаемой "ёлочки" c углублениями.
Например, классика:
var bicycle = TryGetBicycle();
if (bicycle != null)
{
Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
}
else
{
var motorcycle = TryGetMotorcycle();
if (motorcycle != null)
{
Console.WriteLine("Motorcycle owner is {0}.", motorcycle.Owner);
}
else
{
var car = TryGetCar();
if (car != null)
{
Console.WriteLine("Car owner is {0}.", car.Owner);
}
else
{
// ... намученный баян который идет глубоко вниз и конкретно долбит мозг на 5-7-м уровнях вложенности ...
}
}
}
Вместо такого ужаса теперь посмотрим на произведение исскуства, на картину Художника:
if (TryGetBicycle() is not null and var bicycle)
Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
else if (TryGetMotorcycle() is not null and var motorcycle)
Console.WriteLine("Motorcycle owner is {0}.", motorcycle.Owner);
else if (TryGetCar() is not null and var car)
Console.WriteLine("Car owner is {0}.", car.Owner);
else// ... красота на любом уровне "вложенности"! ...
Здравствуйте, Shmj, Вы писали:
S>Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Мне вообще все эти and, or, not и т.п. не нравятся.
В существующий синтаксис привычные &&, ||, ! вписать не смогли, засунули какой-то паскале-образный костыль и довольны.
Здравствуйте, Serginio1, Вы писали:
S> Ну а мне нравится. Наконец то паттерн матчинг стал применяться. Заодно мозги немного потренировать от автоматизма
Мне ни разу в жизни еще Паттерн матчинг не понадобился. Где возникала проблема — решалось нормальной архитектурой. Как-то скептически я к таким штукам отношусь и из-за использования. Люди охотнее забивают на архитектуру, т.к. любые ошибки потом можно легко обойти сахаром языка.
Здравствуйте, Sinclair, Вы писали: S>Если вас действительно интересует такой вопрос — не поленитесь и посмотрите дизассемблером. S>Микроскопические методы типа First прекрасно инлайнятся, а проверки типа в случаях, когда тип известен (то есть как раз там, где можно безопасно написать items[0]), устраняются JIT-ом.
Посмотрел через ILSpy, посмотрел на sharplab, вызов метода First никуда не делся.
Я не силён в устройстве компилятора и т.п. Метод First точно может инлайниться? Он вроде в другой сборке лежит, а не в моём проекте, такое инлайнится? S>А если этот вопрос вас не беспокоит, то старайтесь писать понятный код, дружественный к модификациям. items.First() точнее выражает намерение разработчика и дружелюбнее к будущей смене типа коллекции.
Ну, да. Мне тут намедни таск под ускорение метода прилетел. Изменил 1 строчку и получил ускорение в десяток раз.
Кто-то взял List и для него активно вызывал методы Remove и Contains. Простая замена на HashSet дала достаточный прирост скорости.
Только пришлось всё равно пробежать по коду и убедиться, что там не важен порядок элементов и я сменой коллекции ничего не нарушу.
Если бы мне пришлось попутно поменять [0] на .First(), то вот вообще не переживал бы.
А я мог и не посмотреть и не думать об особенностях и различиях обеих коллекций.
Засунул бы HashSet бездумно туда, где важен порядок элементов, лови потом весёлый баг. S>Пока что минусов не видно.
Давно хотел и вот решил под такое дело таки попробовать BenchmarkDotNet.
Код теста
public class Benchmark
{
const int retry = 10;
List<int> _items;
public Benchmark()
{
_items = new List<int>(1);
_items.Add(1);
}
[Benchmark]
public bool ByAny()
{
bool result = false;
for (int i = 0; i < retry; ++i)
{
result = _items.Any();
}
return result;
}
[Benchmark]
public bool ByCount()
{
bool result = false;
for (int i = 0; i < retry; ++i)
{
result = _items.Count != 0;
}
return result;
}
[Benchmark]
public int ByIndex()
{
int result = 0;
for (int i = 0; i < retry; ++i)
{
result = _items[0];
}
return result;
}
[Benchmark]
public int ByFirst()
{
int result = 0;
for (int i = 0; i < retry; ++i)
{
result = _items.First();
}
return result;
}
}
Здравствуйте, Sinclair, Вы писали:
K>>Last() хоть короче и понятнее записывается, чем items[items.Count — 1], а с First вообще одни минусы, как по мне. S>Пока что минусов не видно.
А бывает еще смешней: в .net7 linq методы кое-где используют векторизацию и могут работать в 10-ки раз быстрее, чем очевидная реализация руками:
Здравствуйте, karbofos42, Вы писали:
K>Может мне просто не попадалось задач, куда Pattern matching хорошо ложится и прямо нужная вещь.
Представьте список транзакций, к каждой из которых нужно добавить набор разрешённых действий. У транзакции есть набор признаков, штук 15.
Сейчас это сделано в виде 400* строк вложенных if'ов, и одно и то же действие может быть добавлено в нескольких местах этой скомканной простыни. Разбираться в этом очень тяжело.
Более прямой, "табличный" вид паттерн-матчинга сделал бы этот код более понятный. А понимать его надо, туда лезут 50 разных людей и никто ничего не знает.
*это не преувеличение, я только что проверил, и это старая версия кода, сейчас там строк прибавилось
int i = int.Parse(Console.ReadLine());
if (i == 1 || i == 3 && !(i == 5 && i != 5))
Console.WriteLine(1);
if (i is 1 or 3 and not (5 and not 5))
Console.WriteLine(2);
Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Здравствуйте, karbofos42, Вы писали:
K>Люди для List вместо проверки Count вызывают метод Any(). Вместо нулевого элемента запрашивают First().
Рекомендую поизучать исходники Linq.
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
}
if (source is ICollection<TSource> collectionoft)
{
return collectionoft.Count != 0;
}
else if (source is IIListProvider<TSource> listProv)
{
// Note that this check differs from the corresponding check in
// Count (whereas otherwise this method parallels it). If the count
// can't be retrieved cheaply, that likely means we'd need to iterate
// through the entire sequence in order to get the count, and in that
// case, we'll generally be better off falling through to the logic
// below that only enumerates at most a single element.int count = listProv.GetCount(onlyIfCheap: true);
if (count >= 0)
{
return count != 0;
}
}
else if (source is ICollection collection)
{
return collection.Count != 0;
}
using (IEnumerator<TSource> e = source.GetEnumerator())
{
return e.MoveNext();
}
}
С First примерно та же ситуация.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Aquilaware, Вы писали:
A>Можно даже захватить походящее значение в переменную для дальнейшего использования:
A>
A>if (GetIQ() is < 100 and > 50 and var iq)
A> Console.WriteLine("Hoi polloi IQ: {0}", iq);
A>
А что будет, если написать or var iq?
Почему не запись типа: A>
A>if (var iq = GetIQ() is < 100 and > 50)
A> Console.WriteLine("Hoi polloi IQ: {0}", iq);
A>
в язык не вписалось?
Возможность сама вроде норм, но выглядит то убого и чужеродно
A>Теперь вы видите?
Я лично тут вижу, что кто-то написал кривые методы, которые неудобно использовать и в результате вокруг них идут какие-то костыли.
Что мешало написать так:
if (TryGetBicycle(out var bicycle))
...
else if (TryGetMotorcycle(out var motorcycle))
...
else
...
с ?. удобно, если нужно пробраться в какую-то иерархию, где на любом уровне может быть null:
var value = root?.child1?.child2;
if (value != null)
{
...
}
без этого пришлось бы много if городить, а так это компилятор сделает и код чище выглядит.
Удобно при разборе всяких xml, json и т.п. где нельзя повлиять на наличие какого-либо объекта и не стоит падать, если в файле какой-то элемент потеряли.
Эти операторы, на мой взгляд, вполне неплохая вещь и годный сахар.
Lisp — это святое. Кстати, если бы топик стартер поупражнялся в нем, то он бы не создавал подобных тем, так как Lisp человеку помагает осознать саму материю языка. Прикоснуться к ядру компьютерной и математической вселенной, к тому, с чего начинается само понятие вычисления.
Поэтому задание для топик стартера — это написать своими руками интерпретатор Scheme (нормализованного диалекта Lisp) и в процессе прочувствовать это всё. После такого опыта дороги назад уже не будет, настолько сильным будет его влияение на сознание и на понимание происходящих процессов.
Рекомендуется всем, кто не ещё пробовал. Но конечно же, большая часть людей проигнорирует эту возможность по разным причинам. Кто-то закатит глаза со словами "опять эта функциональщина, а мне тут формы шлёпать надо", у кого-то не будет времени из-за занятости, а кто-то вообще не поймет, что тут такого особенного происходит.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, karbofos42, Вы писали: K>>Посмотрел через ILSpy, посмотрел на sharplab, вызов метода First никуда не делся. S>Это очень интересно. Действительно, почему-то вызов остаётся.
З.Ы. Посмотрел врукопашную, взяв исходник из Core https://github.com/dotnet/runtime/blob/80b7a657ee1471f20fd23f228b2576c0dbe14789/src/libraries/System.Linq/src/System/Linq/First.cs
Применение AggessiveInlining на First и TryGetFirst помогает встроить код, но в итоге почему-то всё равно остаются вызовы.
Похоже, основные оптимизации JIT попали на value-типы, а для референс-типов вроде List<T> устраняется не вся возможная косвенность.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, karbofos42, Вы писали:
K>В существующий синтаксис привычные &&, ||, ! вписать не смогли, засунули какой-то паскале-образный костыль и довольны.
Основное слово привычнее!
Мне нравится, так как я бывший паскалист и новому поколению тоже понравится!
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Shmj, Вы писали:
S>Теперь можно писать и так и эдак:
S>
S>int i = int.Parse(Console.ReadLine());
S>if (i == 1 || i == 3 && !(i == 5 && i != 5))
S> Console.WriteLine(1);
S>if (i is 1 or 3 and not (5 and not 5))
S> Console.WriteLine(2);
S>
S>Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Это же не C# написал, это ты написал. Написать непонятно можно на любом языке с любым набором фич, даже самым примитивным. Просто пиши так, чтобы было понятно и тебе, и окружающим. Разделяй сложное на простое, создавай промежуточные переменные с говорящими названиями, расставляй скобочки... Когда понятнее значками |&!^, используй значки, когда понятнее словами, пиши слова.
Здравствуйте, Shmj, Вы писали:
S>Теперь можно писать и так и эдак:
S>int i = int.Parse(Console.ReadLine());
S>if (i == 1 || i == 3 && !(i == 5 && i != 5))
S> Console.WriteLine(1);
S>if (i is 1 or 3 and not (5 and not 5))
S> Console.WriteLine(2);
S>Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Полностью согласен, помню, на C# версии 1.0 можно было то же самое написать вот так вот:
S>int i = int.Parse(Console.ReadLine());
if (i == 1 || i == 3)
Console.WriteLine(1);
но дублировать "i" не очень-то здорово, поэтому-то
if (i is 1 or 3)
Console.WriteLine(2);
рулит.
Help will always be given at Hogwarts to those who ask for it.
A>var vehicle = TryGetBicycle() ?? TryGetMotorcycke() ?? TryGetCar();
A>
Вот кстати да, всё не мог вспомнить, прямо дежа-вю. Точно, вот оно: полезность этого нововведения мне сильно напоминает позезность оператора "??", тоже были рассказы как теперь заживём по-новому и вах как все смогут писать код типа:
Console.WriteLine("The owner is {0}.", TryGetBicycle()?.Owner ?? TryGetMotorcycle()?.Owner ?? GetDefaultValue().Owner);
И прямо сердце замирало от открывшихся перспектив и причастности к великому...
За пределами демонстраций/обучающих сессий эта конструкция мне понадобилась примерно никогда, конечно. :D
Здравствуйте, Serginio1, Вы писали:
S> Мне нравится, так как я бывший паскалист и новому поколению тоже понравится!
Да я сам с паскаля начинал, потом много на Delphi 7 писал.
Мне не нравится не сами операторы, а что одно и то же в разных местах нужно по-разному писать.
Везде в программе &&, а захотел паттерн-матчинг (или как там это называется) — тут уже какой-то свой подъязык с and.
Мне такой кривой синтаксический сахар не нравится.
Здравствуйте, Serginio1, Вы писали:
S>Ну в лист как раз необязательно. Ибо ленивые вычисления и может запрос еще где понадобится для формирования нового запроса. S>В запросах как раз нет вычислений пока не позовешь MoveNext S>ToList обычно при передаче в методы, а лучше как раз передавать IEnumerable<T>. А так foreach сам раскроет IEnumerable. Но это так лирика.
Тут важно понимать внутреннее устройство. С IEnumerable в лучшем случае люди одни и те же расчёты проводили по несколько раз, т.к. коллекция попадала в несколько foreach.
В худшем — бывали трудновыявляемые баги, когда повторный прогон LINQ давал другой набор данных.
Смотришь в коде, стоит проверка на то, что 2 элемента в коллекции, а через 3 строки падает, т.к. в коллекции уже оказывается 1 элемент, хотя никто ничего не удалял.
S> В любом случае чем больше конструкций тем лучше. Пусть и не часто применяемых
В итоге часто в командах вводятся запреты на различные конструкции языка, т.к. тим лиды считают, что что-то мешает читабельности, что-то приводит к потенциальным ошибкам и т.д.
В итоге пропадает единообразие и при переходе в другую команду придётся ещё и переучиваться немного под хотелки руководства.
Здравствуйте, karbofos42, Вы писали:
K>Тут важно понимать внутреннее устройство. С IEnumerable в лучшем случае люди одни и те же расчёты проводили по несколько раз, т.к. коллекция попадала в несколько foreach. K>В худшем — бывали трудновыявляемые баги, когда повторный прогон LINQ давал другой набор данных. K>Смотришь в коде, стоит проверка на то, что 2 элемента в коллекции, а через 3 строки падает, т.к. в коллекции уже оказывается 1 элемент, хотя никто ничего не удалял.
Здравствуйте, Shmj, Вы писали:
S>Теперь можно писать и так и эдак:
S>Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Здравствуйте, IT, Вы писали:
IT>Рекомендую поизучать исходники Linq.
Так я видел и в курсе.
Разве нет разницы между items[0] и items.First() в плане, что во втором случае добавляется проверка типа коллекции?
Вроде мелочь, а вроде лишняя работа и лишнее ветвление непонятно зачем.
Last() хоть короче и понятнее записывается, чем items[items.Count — 1], а с First вообще одни минусы, как по мне.
Здравствуйте, Aquilaware, Вы писали:
A>Вместо такого ужаса теперь посмотрим на произведение исскуства, на картину Художника:
A>
A>if (TryGetBicycle() is not null and var bicycle)
A> Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
A>else if (TryGetMotorcycle() is not null and var motorcycle)
A> Console.WriteLine("Motorcycle owner is {0}.", motorcycle.Owner);
A>else if (TryGetCar() is not null and var car)
A> Console.WriteLine("Car owner is {0}.", car.Owner);
A>else
A> // ... красота на любом уровне "вложенности"! ...
A>
Для произведения искусства тут слишком много копипасты. Как по мне, я бы сделал список типов (Bicycle, Motorcycle, Car) и проверял соответствие каждому, а при выводе в консоль использовал бы метаданные (имя типа или назначенная ему человекочитаемая строка). А если бы набор TryGetX() был внешним и не поддавался переписыванию, сделал бы список хотя бы методов (TryGetBicycle, TryGetMotorcycle, TryGetCar).
Здравствуйте, Serginio1, Вы писали:
S>Угу если источник будет меняться, то получишь, что угодно. Суть понимать с чем имеешь дело.
Ну, вот и у linq я вижу варианты использования и это нужная вещи, а у этого кривого синтаксического сахара — нет.
Возможно где-то его использование и оправдано и у меня просто таких задач не было.
Предвижу, что раньше люди боялись объёмных ветвлений и начинали задумываться над архитектурой, переписывая нормально, что такие проверки становились в принципе не нужны.
Теперь объёмные проверки можно легко и коротко записывать, поэтому чего бы дублирующих условий везде не напихать и плевать как это скажется на производительности и сколько лишнего будет код делать.
Здравствуйте, Aquilaware, Вы писали:
A>То, что предлагаете вы — это никак не ровные методы, это исторический костыль. Проблема с этим костылем в том, что нельзя сделать вот так:
не костыль, а try-parse паттерн же
A>А нужно как всегда извращаться в упражнении рука-писать.
ну, для предыдущего варианта подвезли pattern-matching, могли и для этого что-то в язык тогда добавить, чтобы удобнее было использовать
Здравствуйте, karbofos42, Вы писали: K>Посмотрел через ILSpy, посмотрел на sharplab, вызов метода First никуда не делся.
Это очень интересно. Действительно, почему-то вызов остаётся. K>Я не силён в устройстве компилятора и т.п. Метод First точно может инлайниться? Он вроде в другой сборке лежит, а не в моём проекте, такое инлайнится?
Да, такое должно инлайниться. Почему этого не происходит — отдельный вопрос.
Будет время — я посмотрю логи джита. K>Ну, да. Мне тут намедни таск под ускорение метода прилетел. Изменил 1 строчку и получил ускорение в десяток раз. K>Кто-то взял List и для него активно вызывал методы Remove и Contains. Простая замена на HashSet дала достаточный прирост скорости.
И это — очень типичная ситуация. Примерно так и выглядит оптимизация шарпа в 99% случаев. K>Только пришлось всё равно пробежать по коду и убедиться, что там не важен порядок элементов и я сменой коллекции ничего не нарушу.
В идеальном случае пробежка выполняется при помощи перепрогона тестов. Если тестов мало — то да, надо смотреть глазами.
Хотя это менее надёжно — мало ли, что где можно посмотреть. K>Если бы мне пришлось попутно поменять [0] на .First(), то вот вообще не переживал бы. K>А я мог и не посмотреть и не думать об особенностях и различиях обеих коллекций. K>Засунул бы HashSet бездумно туда, где важен порядок элементов, лови потом весёлый баг.
K>| Method | Mean | Error | StdDev | K>|-------- |-----------:|----------:|----------:| K>| ByAny | 47.657 ns | 0.3115 ns | 0.2761 ns | K>| ByCount | 3.235 ns | 0.0304 ns | 0.0285 ns | K>| ByIndex | 6.913 ns | 0.0838 ns | 0.0784 ns | K>| ByFirst | 108.889 ns | 1.4484 ns | 1.3549 ns | K>[/code] K>[/cut]
K>Я что-то не так сделал или всё же разница в разы есть?
Вы всё сделали верно. Снимаю шляпу. На досуге поразбираюсь, откуда такой провал в производительности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
A>var bicycle = TryGetBicycle();
A>if (bicycle != null)
A> Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
A>
A>это теперь можно делать в одну строку:
A>if (TryGetBicycle() is not null and var bicycle)
A> Console.WriteLine("Bicycle owner is {0}.", bicycle.Owner);
A>
A>Почему такая возможность важна? Потому что иногда это безумно удобно во вложенных if'ах, так как позволяет обойтись одним уровнем вложенности вместо плохо читаемой "ёлочки" c углублениями.
Здравствуйте, karbofos42, Вы писали:
S>> Мне нравится, так как я бывший паскалист и новому поколению тоже понравится!
K>Да я сам с паскаля начинал, потом много на Delphi 7 писал. K>Мне не нравится не сами операторы, а что одно и то же в разных местах нужно по-разному писать. K>Везде в программе &&, а захотел паттерн-матчинг (или как там это называется) — тут уже какой-то свой подъязык с and. K>Мне такой кривой синтаксический сахар не нравится.
Ну а мне нравится. Наконец то паттерн матчинг стал применяться. Заодно мозги немного потренировать от автоматизма
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, karbofos42, Вы писали:
K>Мне ни разу в жизни еще Паттерн матчинг не понадобился. Где возникала проблема — решалось нормальной архитектурой. Как-то скептически я к таким штукам отношусь и из-за использования. Люди охотнее забивают на архитектуру, т.к. любые ошибки потом можно легко обойти сахаром языка.
Ну это старое мышление. Аналогично тому как появился Linq. Многие так говорили. Однако со временем Linq набрал популярность.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Ну это старое мышление. Аналогично тому как появился Linq. Многие так говорили. Однако со временем Linq набрал популярность.
LINQ мне нравится, но при этом уже устал от бессмысленных записей.
Люди для List вместо проверки Count вызывают метод Any(). Вместо нулевого элемента запрашивают First().
Недавно вообще блестящее место исправлял:
Благо хоть приучились ToList() вызывать, а то бы повторных расчётов было в разы больше.
Но Linq всё же уместен в нормальном коде и вещь полезная.
Может мне просто не попадалось задач, куда Pattern matching хорошо ложится и прямо нужная вещь.
Что попадалось и в голову приходило — это было быстрыми костылями к кривой реализации основного кода.
Ну, и Linq нормально в язык вписался, естественно и непринуждённо.
Здравствуйте, Shmj, Вы писали:
S>Теперь можно писать и так и эдак:
S>
S>int i = int.Parse(Console.ReadLine());
S>if (i == 1 || i == 3 && !(i == 5 && i != 5))
S> Console.WriteLine(1);
S>if (i is 1 or 3 and not (5 and not 5))
S> Console.WriteLine(2);
S>
Прикольно. Некрасиво, но пользу несёт однозначно.
S>Не кажется ли это внедрением бардака? В одном месте будут писать так в другом эдак.
Вариант 1 — смириться. Пишут и ладно.
Вариант 2 — поставить правило в команде и следить за соблюдением.
Вариант 3 — найти статический анализатор, который сам будет следить за соблюдением.
Здравствуйте, karbofos42, Вы писали:
K>Благо хоть приучились ToList() вызывать, а то бы повторных расчётов было в разы больше.
Ну в лист как раз необязательно. Ибо ленивые вычисления и может запрос еще где понадобится для формирования нового запроса.
В запросах как раз нет вычислений пока не позовешь MoveNext
ToList обычно при передаче в методы, а лучше как раз передавать IEnumerable<T>. А так foreach сам раскроет IEnumerable. Но это так лирика.
K>Может мне просто не попадалось задач, куда Pattern matching хорошо ложится и прямо нужная вещь. K>Что попадалось и в голову приходило — это было быстрыми костылями к кривой реализации основного кода.
Ну ПМ просто хорошь для всяких рекурсивных деревьев и прочее. Он пришел из функциональщины, но полезен там где много ветвлений с кучей вариантов условий.
Да часть можно архитектурно решить, но много и нельзя.
В любом случае чем больше конструкций тем лучше. Пусть и не часто применяемых
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Слава, Вы писали:
С>Представьте список транзакций, к каждой из которых нужно добавить набор разрешённых действий. У транзакции есть набор признаков, штук 15. С>Сейчас это сделано в виде 400* строк вложенных if'ов, и одно и то же действие может быть добавлено в нескольких местах этой скомканной простыни. Разбираться в этом очень тяжело.
PM уважаю, как и функциональный подход в принципе, но в данном случае вопрос: а нельзя ли как-то это всё «раскодировать» (перевести из кода во что-то другое)? Или в DSL, или в data-файл. Я бы в эту сторону подумал.
То, что предлагаете вы — это никак не ровные методы, это исторический костыль. Проблема с этим костылем в том, что нельзя сделать вот так:
var vehicle = TryGetBicycle() ?? TryGetMotorcycke() ?? TryGetCar();
А нужно как всегда извращаться в упражнении рука-писать. Это прям как в Java, где нет out и ref параметров функций, и поэтому люди вынуждены придумывать свои исторические костыли.
Зачем, если всё это можно сделать средствами языка? Например, был бы полноценный Optional<T> или уже сам тип данных подразумевает null значение.
Здравствуйте, karbofos42, Вы писали: K>Так я видел и в курсе. K>Разве нет разницы между items[0] и items.First() в плане, что во втором случае добавляется проверка типа коллекции?
Если вас действительно интересует такой вопрос — не поленитесь и посмотрите дизассемблером.
Микроскопические методы типа First прекрасно инлайнятся, а проверки типа в случаях, когда тип известен (то есть как раз там, где можно безопасно написать items[0]), устраняются JIT-ом.
А если этот вопрос вас не беспокоит, то старайтесь писать понятный код, дружественный к модификациям. items.First() точнее выражает намерение разработчика и дружелюбнее к будущей смене типа коллекции. K>Вроде мелочь, а вроде лишняя работа и лишнее ветвление непонятно зачем. K>Last() хоть короче и понятнее записывается, чем items[items.Count — 1], а с First вообще одни минусы, как по мне.
Пока что минусов не видно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Shtole, Вы писали:
S>PM уважаю, как и функциональный подход в принципе, но в данном случае вопрос: а нельзя ли как-то это всё «раскодировать» (перевести из кода во что-то другое)? Или в DSL, или в data-файл. Я бы в эту сторону подумал.
Для этого нужен отбеливатель и шуруповёрт с набором саморезов. В отбеливатель засунуть исполнительных копчёных сотрудников, а шуруповёртом закрутить саморезы в головы белым энергичным сотрудникам. А без этого они так и будут тикеты создавать и закрывать.
Здравствуйте, Aquilaware, Вы писали:
A>Поэтому задание для топик стартера — это написать своими руками интерпретатор Scheme (нормализованного диалекта Lisp) и в процессе прочувствовать это всё. После такого опыта дороги назад уже не будет, настолько сильным будет его влияение на сознание и на понимание происходящих процессов.
A>Рекомендуется всем, кто не ещё пробовал. Но конечно же, большая часть людей проигнорирует эту возможность по разным причинам. Кто-то закатит глаза со словами "опять эта функциональщина, а мне тут формы шлёпать надо", у кого-то не будет времени из-за занятости, а кто-то вообще не поймет, что тут такого особенного происходит.
Я писал. Компилятор даже. Нет, не понял, что там особого. Ничего особого в схеме нет. Убогий игрушечный недоязычок, даже до джаваскрипта не дотягивает. А уж интерпретатор — там и вовсе ничего интересного. С компилятором там хоть какие-то вопросы возникают в голове.
Вот хаскель — да. Там ничего писать не надо. Просто сидеть и учить, фича за фичей. Подбирая выпадающий мозг.
Тут идея в использовании сопоставление с образцом в условиях.
Правда вышла небольшая накладочка и не всегда можно просто заменить if на switch:
string? F() { return""; }
public int M2()
{
if (F() is object o && o.GetHashCode() == 1)
{
return 1;
}
else if (F() is {} s)
{
return s.Length;
}
else
{
return 2;
}
}
public int M2()
{
return F() switch
{
object o when o.GetHashCode() == 1 => 1, // && или and не подходят
{} s => 1,
_ => 2
};
}
Здравствуйте, Max Mustermann, Вы писали:
MM>За пределами демонстраций/обучающих сессий эта конструкция мне понадобилась примерно никогда, конечно.
Всё приходит с опытом. ?? — на самом деле один из самых частоисподьзуемых операторов. Но не для всех, например, при императивном подходе это как козе баян. А вот при функциональном это как диаманд.