Объясните про pattern matching в C#
От: dmitry_npi Россия  
Дата: 25.05.18 06:29
Оценка: +1 -1
В новых версиях языка ввели расширенный оператор switch, обозвали его "pattern matching", и рекламируют примерно так:

static string M(Person person)
{
    switch (person)
    {
        case Professor p:
            return $"Dr. {p.LastName}";
        case Studen s:
            return $"{s.FirstName} {s.LastName} ({s.Level})";
        default:
            return $"{person.FirstName} {person.LastName}";
    }
}

(взято отсюда)

Вопрос первый: в чем принципиальная новизна, которая заслуживает специального термина "pattern matching", ведь это можно было проделать и раньше, используя is/as и if/else, хоть и более громоздко?
То есть, это просто синтаксический оверхед сахар?

Вопрос второй: зачем это вообще нужно в ООП-языке? Я понимаю, что сейчас шарп дрифтует в сторону функциональщины, но ведь основой всё равно остаётся ООП. С моей точки зрения, в стиле ООП надо было сделать как-то так:
abstract class Person
{
   public string FirstName {get;set;}
   public string LastName {get;set;}

   public virtual string GetDisplayString()
   {
      return $"{FirstName} {LastName}";
   }
}

class Professor: Person
{
   public override string GetDisplayString()
   {
      return $"Dr. {LastName}";
   }
}
class Student: Person
{
   public int Level {get;set;}

   public override string GetDisplayString()
   {
      return $"{FirstName} {LastName} ({Level})";
   }
}
...
static string M(Person person)
{
    return person.GetDisplayString();
}


Здесь и модульность (можно отдельно добавлять классы), и удобство поддержки многих точек выбора (ветвление неявно осуществляет компилятор).
Новый способ банально провоцирует писать плохой код, да еще и с большим удобством
Атмосферная музыка — www.aventuel.net
Re: Объясните про pattern matching в C#
От: Ночной Смотрящий Россия  
Дата: 25.05.18 06:38
Оценка: +1 :)
Здравствуйте, dmitry_npi, Вы писали:

_>Вопрос первый: в чем принципиальная новизна, которая заслуживает специального термина "pattern matching", ведь это можно было проделать и раньше, используя is/as и if/else, хоть и более громоздко?

_>То есть, это просто синтаксический оверхед сахар?

По большому счету весь C# это синтаксический сахар над ILASM.

_>С моей точки зрения, в стиле ООП надо было сделать как-то так:

_>abstract class Person
_>{
_> public string FirstName {get;set;}
_> public string LastName {get;set;}

_> public virtual string GetDisplayString()

_> {
_> return $"{FirstName} {LastName}";
_> }
_>}

А если Person сотоварищи недоступны для модификации?
Re[2]: Объясните про pattern matching в C#
От: dmitry_npi Россия  
Дата: 25.05.18 07:03
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:


НС>А если Person сотоварищи недоступны для модификации?


Все равно, логику различения типов объектов надо бы отделить от логики форматирования строки. Например, построить параллельную иерархию PersonFormatter,где осуществлять форматирование, а различение типов спрятать в фабрику этих форматтеров.

Да, я понимаю, что громоздко. Нет, я не джавист.
Атмосферная музыка — www.aventuel.net
Re[3]: Объясните про pattern matching в C#
От: _Raz_  
Дата: 25.05.18 07:10
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

_>Все равно, логику различения типов объектов надо бы отделить от логики форматирования строки. Например, построить параллельную иерархию PersonFormatter,где осуществлять форматирование, а различение типов спрятать в фабрику этих форматтеров.


_>Да, я понимаю, что громоздко. Нет, я не джавист.


Здесь прекрасно подойдут extension methods.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re[4]: Объясните про pattern matching в C#
От: Jack128  
Дата: 25.05.18 07:19
Оценка: +1
Здравствуйте, _Raz_, Вы писали:

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


_>>Все равно, логику различения типов объектов надо бы отделить от логики форматирования строки. Например, построить параллельную иерархию PersonFormatter,где осуществлять форматирование, а различение типов спрятать в фабрику этих форматтеров.


_>>Да, я понимаю, что громоздко. Нет, я не джавист.


_R_>Здесь прекрасно подойдут extension methods.


Они не полиморфны, поэтому тестирование типа всё равно останется
Re[5]: Объясните про pattern matching в C#
От: _Raz_  
Дата: 25.05.18 07:56
Оценка: :)
Здравствуйте, Jack128, Вы писали:

J>Они не полиморфны, поэтому тестирование типа всё равно останется


Код:
using System;

namespace ConsoleApp2
{
    internal class Person
    {
    }

    internal class Professor : Person
    {
    }

    internal class Student : Person
    {
    }

    internal static class Ext
    {
        internal static string GetDisplayString(this Person p)
        {
            return p.GetType().Name;
        }

        internal static string GetDisplayString(this Professor p)
        {
            return p.GetType().Name;
        }

        internal static string GetDisplayString(this Student p)
        {
            return p.GetType().Name;
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            Console.WriteLine(new Person().GetDisplayString());
            Console.WriteLine(new Student().GetDisplayString());
            Console.WriteLine(new Professor().GetDisplayString());

            Console.ReadKey();
        }
    }
}


Вывод:
Person
Student
Professor
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re[6]: Объясните про pattern matching в C#
От: dmitry_npi Россия  
Дата: 25.05.18 08:08
Оценка: +1
Здравствуйте, _Raz_, Вы писали:

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


J>>Они не полиморфны, поэтому тестирование типа всё равно останется


_R_>Код:

_R_>
_R_>using System;

_R_>namespace ConsoleApp2
_R_>{
_R_>    internal class Person
_R_>    {
_R_>    }

_R_>    internal class Professor : Person
_R_>    {
_R_>    }

_R_>    internal class Student : Person
_R_>    {
_R_>    }

_R_>    internal static class Ext
_R_>    {
_R_>        internal static string GetDisplayString(this Person p)
_R_>        {
_R_>            return p.GetType().Name;
_R_>        }

_R_>        internal static string GetDisplayString(this Professor p)
_R_>        {
_R_>            return p.GetType().Name;
_R_>        }

_R_>        internal static string GetDisplayString(this Student p)
_R_>        {
_R_>            return p.GetType().Name;
_R_>        }
_R_>    }

_R_>    internal static class Program
_R_>    {
_R_>        private static void Main()
_R_>        {
_R_>            Console.WriteLine(new Person().GetDisplayString());
_R_>            Console.WriteLine(new Student().GetDisplayString());
_R_>            Console.WriteLine(new Professor().GetDisplayString());

_R_>            Console.ReadKey();
_R_>        }
_R_>    }
_R_>}


Не, так не пойдёт. У вас в Main тип объекта подаётся явно, а в задаче предполагается, что придет ссылка на базовый объект. У вас развязка вообще идет на уровне компиляции.
К тому же, метод GetType() — хоть и не виртуальный, но ведет себя как таковой, и только поэтому ваш код работает. Если вызывать метод расширения от ссылки на базовый объект, то последние два метода расширения вообще вызываться не будут.
Извините, если непонятно пояснил.
Атмосферная музыка — www.aventuel.net
Re[3]: Объясните про pattern matching в C#
От: Ночной Смотрящий Россия  
Дата: 25.05.18 08:18
Оценка: +1
Здравствуйте, dmitry_npi, Вы писали:

НС>>А если Person сотоварищи недоступны для модификации?

_>Все равно, логику различения типов объектов надо бы отделить от логики форматирования строки. Например, построить параллельную иерархию PersonFormatter,где осуществлять форматирование, а различение типов спрятать в фабрику этих форматтеров.
_>Да, я понимаю, что громоздко.

Тогда к чему вопросы про нужность РМ?
Ну и в довесок почитай про https://en.wikipedia.org/wiki/Tagged_union
Re[4]: Объясните про pattern matching в C#
От: Ночной Смотрящий Россия  
Дата: 25.05.18 08:20
Оценка: +2
Здравствуйте, _Raz_, Вы писали:

_>>Да, я понимаю, что громоздко. Нет, я не джавист.

_R_>Здесь прекрасно подойдут extension methods.

Не подойдут. Классическая иерархия наследования без виртуальных методов не работает, а extension методы виртуальными быть не могут.
Re[2]: Объясните про pattern matching в C#
От: mrTwister Россия  
Дата: 25.05.18 08:57
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>А если Person сотоварищи недоступны для модификации?


вводим еще один уровень абстракции
лэт ми спик фром май харт
Re[3]: Объясните про pattern matching в C#
От: Ночной Смотрящий Россия  
Дата: 25.05.18 09:02
Оценка: :)))
Здравствуйте, mrTwister, Вы писали:

T>вводим еще один уровень абстракции


Я все жду когда кто нибудь вспомнит про Visitor.
Re: Объясните про pattern matching в C#
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.05.18 09:43
Оценка: +2 -1
Здравствуйте, dmitry_npi, Вы писали:

_>Вопрос второй: зачем это вообще нужно в ООП-языке? Я понимаю, что сейчас шарп дрифтует в сторону функциональщины, но ведь основой всё равно остаётся ООП. С моей точки зрения, в стиле ООП надо было сделать как-то так:


ООП включает в себя ФП. Вот так.

_>Здесь и модульность (можно отдельно добавлять классы), и удобство поддержки многих точек выбора (ветвление неявно осуществляет компилятор).

_>Новый способ банально провоцирует писать плохой код, да еще и с большим удобством

В твоём ООП дизайне придется тащить все операции в классы, например, так, как ты протащил GetDisplayString. То есть, следствием твоего дизайна является нарушение инкапсуляции. Более того, для многих случаев придется запилить визитор или его разновидности. Что, фактически, так же есть нарушение инкапсуляции. Парадокс, да ? Вроде ООП, а нарушаем инкапсуляцию, когда следуем ООП

На самом деле в ООП класс должен предстовлять только самый базовый функционал. А все, что может быть сделано снаружи, должно и делаться снаружи.
Соответсвенно, на вызывающей стороне должно быть достаточно средств для использования этого базового функционала. Эта идея реализована в Extension Method, Query Comprehension и тд. Pattern Matching — развитие этой же идеи.

То есть, pattern matching есть улучшение ООП, а не отказ от него.
Re[3]: Объясните про pattern matching в C#
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.05.18 09:46
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

НС>>А если Person сотоварищи недоступны для модификации?


_>Все равно, логику различения типов объектов надо бы отделить от логики форматирования строки. Например, построить параллельную иерархию PersonFormatter,где осуществлять форматирование, а различение типов спрятать в фабрику этих форматтеров.


Надо отделить класс от его репрезентации. Различение типов — это репрезентация. Форматирование — репрезентация. Все это нужно отделять от самого класса.

А вот надо ли разделять различение типов от логики формирование строки это уже дело десятое. Можно разделять, а можно и не разделять.

И вот как только мы чего то разделили, то в приложении надо это же собрать в одно целое. И для этого и нужен паттер матчинг. Паттерн-матчинг не нужен там, где все монолитное.
Re[6]: Объясните про pattern matching в C#
От: vorona  
Дата: 25.05.18 09:56
Оценка:
Здравствуйте, _Raz_, Вы писали:

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


Вместо
internal static string GetDisplayString(this Person p)
{
    return p.GetType().Name;
}


Надо
internal static string GetDisplayString(this Person p)
{
    if (p.GetType() == typeof(Person))
        return "Person";

    return GetDisplayString((dynamic)p);
}
Re[7]: Объясните про pattern matching в C#
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.05.18 10:43
Оценка:
Здравствуйте, vorona, Вы писали:

V>Надо

V>
V>internal static string GetDisplayString(this Person p)
V>{
V>    if (p.GetType() == typeof(Person))
V>        return "Person";

V>    return GetDisplayString((dynamic)p);
V>}
V>


Вот так — не надо. DisplayString может меняться в зависимости от особенностей вьюшки, настроек юзера, размера устройства и тд и тд. Тащить все это в класс Person — преступление.
Re[5]: Объясните про pattern matching в C#
От: AlexRK  
Дата: 25.05.18 10:45
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Не подойдут. Классическая иерархия наследования без виртуальных методов не работает, а extension методы виртуальными быть не могут.


Почему не сделать виртуальными extension methods?
Re: Объясните про pattern matching в C#
От: elmal  
Дата: 25.05.18 10:48
Оценка: +1
Здравствуйте, dmitry_npi, Вы писали:

_>Вопрос первый: в чем принципиальная новизна, которая заслуживает специального термина "pattern matching", ведь это можно было проделать и раньше, используя is/as и if/else, хоть и более громоздко?

_>То есть, это просто синтаксический оверхед сахар?
Это не Pattern matching. Это просто расширенный оператор switch и ничего более.

Для нормального pattern matching нужно что то вроде:
static string M(Person person)
{
    return switch (person)
    {
        case Professor("Иванов", _, _) p:
            $"Dr. {p.LastName}";
        case Studen("Петров", _, _, level1) s:
            $"{s.FirstName} {s.LastName} ({s.Level})";
        default:
            $"{person.FirstName} {person.LastName}";
    }
}

То есть нам приходит класс, мы его сопоставляем с образцом и в зависимости от того, что куда подходит, мы выполняем определенные действия. Например мы хотим найти тех профессоров, которые Ивановы, и студентов, которые Петровы. Раньше можно было матчить по значению примитивов, енумов и строк вроде, сейчас добавили возможность по конкретным типам, все нововведение. При этом, так как не поддерживаются алгебраические типы данных, этот switch мало чем отличается от обычного if else. Если бы алгебраические типы данных поддерживались, в этом случае хотя бы компилятор мог бы проверить что мы обработали все возможные подтипы, и в отдельном операторе switch имел бы смысл, а так — просто незначительное синтаксическое улучшение. А полноценный pattern matching не так уж и просто сделать на деле, слишком много будет corner cases.

А pattern matching это называют потому, что в языках, которые поддерживают этот самый pattern matching, его зачастую используют примерно затем, зачем используют switch в C#. И когда навороты не нужны, достаточно матчиться по конкретному типу, в этом случае код будет практически аналогичный. Когда этот pattern matching в языке есть, он несколько меняет стиль программирования. Например если есть поддержка Tuples с деструктуризацией, это весьма сильно меняет стиль написания кода, появляется возможность не создавать кучу классов на ровном месте, код становится более компактным, но в тоже время вполне понятным при определенном навыке.
Re[6]: Объясните про pattern matching в C#
От: vdimas Россия  
Дата: 25.05.18 10:57
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Почему не сделать виртуальными extension methods?


Виртуальные методы известны на момент компляции целевого типа, а методы расширения нет.
Re[4]: Объясните про pattern matching в C#
От: vdimas Россия  
Дата: 25.05.18 10:58
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

T>>вводим еще один уровень абстракции

НС>Я все жду когда кто нибудь вспомнит про Visitor.

А как он поможет, если иерархию уже нельзя модифицировать и до этого иерархия о некоем визитёре не знала?
Re: Объясните про pattern matching в C#
От: Kolesiki  
Дата: 25.05.18 11:07
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

_>Вопрос первый: в чем принципиальная новизна, которая заслуживает специального термина "pattern matching"



Ну а в чём "новизна" foreach, когда ты можешь руками перебирать индексы? Всё, что используется часто, имеет смысл выносить в удобные, краткие конструкции. Собственно, для написания любого алгоритма вообще требуются всего три команды!
Согласен, что "pattern matching" здесь чахотошный, но называть чем-то другим — лишний раз вводить в заблуждение. Пусть будет "матчинг начального уровня"

_>Вопрос второй: зачем это вообще нужно в ООП-языке?



ООП не причём. Просто так удобно разбирать структуры, когда нужно проверять кучу условий. PM проявляет себя во всей красе, например, при обработке AST. В регулярной работе мне матчинг нафик не нужен — обхожусь, но если б он был в C# сразу, наверняка и применение нашлось бы!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.