Re[3]: Паттерн "или"
От: nikov США http://www.linkedin.com/in/nikov
Дата: 22.04.23 03:26
Оценка: 523 (12)
Здравствуйте, VladD2, Вы писали:

TB>>Только какой тип у этого x внутри блока? B или C?


VD>Наиболее частный общий.


Он может быть неоднозначным, например, у них могут быть несколько общих интерфейсов, не связанных друг с другом. Или, например, у контравариантных делегатов Action<Array> и Action<IList<object>> есть общий базовый тип MulticastDelegate, но он не самый специфичный. Потому что у них ещё есть более узкие общие базовые типы Action<string[]>, Action<string[][]> (и много других), но ни один из них не является более специфичным чем другой, хотя они все более специфичны, чем MulticastDelegate.

А по поводу твоего исходного вопроса — это можно сделать так:
if (foo() is (B or C) and var x)
{
  // здесь x имеет тип A, но попадаем сюда, только если значение x имеет тип B или С (или более производный)
}

Или же можно написать так (это вопрос стиля):
if (foo() is var x and (B or C))
{
  // здесь x имеет тип A, но попадаем сюда, только если значение x имеет тип B или С (или более производный)
}


А если, например, foo() имеет тип object, а ты хочешь чтобы x имела тип A (общий для B и C), то (ввиду возможной неоднозначности указанной выше) надо указать, какой именно общий тип ты хочешь у переменной:
if (foo() is (B or C) and A x) 
{
  // здесь x имеет тип A, но попадаем сюда, только если значение x имеет тип B или С (или более производный)
}

или, как вариант,
if (foo() is A x and (B or C)) 
{
  // здесь x имеет тип A, но попадаем сюда, только если значение x имеет тип B или С (или более производный)
}
Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.04.23 17:50
Оценка: -1
Всем привет!

Что-то не понимаю. МС не позволяет сделать или-паттерн в паттер-матчинге, или я не пойму как это синтаксически записать?

Есть ситуация:
class A {}
class B : A {}
class C : A {}
class D : A {}
...

A foo() => new C();

if (foo() is B x)
{
  // код использующий x
}


Я хочу сделать еще один паттерн:
if (foo() is B x || foo() is C x)
{
  // код использующий x
}

но компилятор Щарп орет, что переменную x нельзя дважды объявлять. Это что же в Шарп не завезли или-патерн?

Другими словами, аналога вот такого немерлового кода написать нельзя?
module Program
{
  class A {}
  class B : A {}
  class C : A {}
  class D : A {}

  Main() : void
  {
    def foo() : A { C() }
    match (foo())
    {
      | B as x
      | C as x => WriteLine(x) // в x экземпляр C или B, но не D и не A, а переменная имеет тип A
      | _ => WriteLine("other")
    }
  }
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 21.04.2023 17:52 VladD2 . Предыдущая версия .
Re: Паттерн "или"
От: Ромашка Украина  
Дата: 21.04.23 18:17
Оценка: :)
Здравствуйте, VladD2, Вы писали:

Влад, не тупи...



if (foo() is B || foo() is C)
{
   A x = foo();
  // код использующий x
}


Всё, что нас не убивает, ещё горько об этом пожалеет.
Re[2]: Паттерн "или"
От: Философ Ад http://vk.com/id10256428
Дата: 21.04.23 19:04
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>....какой тип у этого x внутри блока?...


....переменная имеет тип A

Всё сказанное выше — личное мнение, если не указано обратное.
Re: Паттерн "или"
От: nmd  
Дата: 21.04.23 17:58
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Всем привет!


Код похож на работу обфускатора, с трудом воспринимается.
Re: Паттерн "или"
От: T4r4sB Россия  
Дата: 21.04.23 18:11
Оценка:
VD>Другими словами, аналога вот такого немерлового кода написать нельзя?

Немерле самый лучший язык, это понятно. Только какой тип у этого x внутри блока? B или C? Или комплиятор должен неявно продублировать тело ветки?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: Паттерн "или"
От: T4r4sB Россия  
Дата: 21.04.23 19:07
Оценка:
Здравствуйте, Философ, Вы писали:

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


TB>>....какой тип у этого x внутри блока?...


Ф>

Ф>....переменная имеет тип A


То есть
A x = foo();
if (x is B || x is C)
{
  // код использующий x
}

?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[2]: Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.23 00:09
Оценка:
Здравствуйте, Ромашка, Вы писали:

Р>Влад, не тупи...

Р>if (foo() is B || foo() is C)
Р>{
Р> A x = foo();
Р> // код использующий x
Р>}

К сожалению, в реальной жизни всё несколько сложнее. Пришлось на шарпе вот такое накатать:
private static ClickInfo? CreateListItemClickInfoOrDefault(DependencyObject targetControl, DependencyObject[] controls)
{
    if (targetControl is not ListBoxItem and not MenuItem)
        return null;

    if (tryGetViewModels(out var viewModel, out var itemViewModel))
    {
...
    }

    return null;

    bool tryGetViewModels([MaybeNullWhen(false)] out object vm, [MaybeNullWhen(false)] out object itemVm)
    {
        if (controls.OfType<ISupportListItemClickInfo>().FirstOrDefault() is FrameworkElement { DataContext: { } vm1 }
            && targetControl is FrameworkElement { DataContext: { } itemViewModel1 })
        {
            vm = vm1;
            itemVm = itemViewModel1;
            return true;
        }

        if (controls.OfType<Selector>().FirstOrDefault() is FrameworkElement { DataContext: { } vm2 }
            && targetControl is FrameworkElement { DataContext: { } itemVm2 })
        {
            vm = vm2;
            itemVm = itemVm2;
            return true;
        }

        itemVm = null;
        vm = null;
        return false;
    }
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 22.04.2023 0:26 VladD2 . Предыдущая версия . Еще …
Отредактировано 22.04.2023 0:25 VladD2 . Предыдущая версия .
Re[4]: Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.23 00:11
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>A x = foo();

TB>if (x is B || x is C)

Нет так не пойдет. См вот этот ответ
Автор: VladD2
Дата: 22.04.23
.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.23 00:15
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Немерле самый лучший язык, это понятно. Только какой тип у этого x внутри блока? B или C? Или комплиятор должен неявно продублировать тело ветки?


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

Скажем для данного примера это будет A. А если создать более ветвистую иерархию, например:
class A {}
class B : A {}
class C : B {}
class D : A {}
class E : B {}

то для E и C общим будет B, а для других сочетаний A.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.04.23 00:43
Оценка:
Здравствуйте, nmd, Вы писали:

nmd>Код похож на работу обфускатора, с трудом воспринимается.


Это от неопытности. Мозг тоже тренировать надо. Зато потом можно будет куда более сложные задачи решать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Паттерн "или"
От: vaa  
Дата: 22.04.23 03:26
Оценка:
Здравствуйте, VladD2, Вы писали:



VD>Другими словами, аналога вот такого немерлового кода написать нельзя?

VD>
VD>module Program
VD>{
VD>  class A {}
VD>  class B : A {}
VD>  class C : A {}
VD>  class D : A {}

VD>  Main() : void
VD>  {
VD>    def foo() : A { C() }
VD>    match (foo())
VD>    {
VD>      | B as x
VD>      | C as x => WriteLine(x) // в x экземпляр C или B, но не D и не A, а переменная имеет тип A
VD>      | _ => WriteLine("other")
VD>    }
VD>  }
VD>}
VD>


Разве B и C не в одном скоупе и типы разные? Опасная практика по-моему
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[4]: Паттерн "или"
От: Jack128  
Дата: 23.04.23 20:32
Оценка:
Здравствуйте, nikov, Вы писали:

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


TB>>>Только какой тип у этого x внутри блока? B или C?


VD>>Наиболее частный общий.


N>Он может быть неоднозначным, например, у них могут быть несколько общих интерфейсов, не связанных друг с другом. Или, например, у контравариантных делегатов Action<Array> и Action<IList<object>> есть общий базовый тип MulticastDelegate, но он не самый специфичный. Потому что у них ещё есть более узкие общие базовые типы Action<string[]>, Action<string[][]> (и много других), но ни один из них не является более специфичным чем другой, хотя они все более специфичны, чем MulticastDelegate.


Подобная ситуация например при выборе перегрузок. Как то же компилятор решает эту проблему, вот и в подобном паттерне мог бы туже логику использовать.
Re[2]: Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.23 12:35
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Разве B и C не в одном скоупе и типы разные? Опасная практика по-моему


У них общие базовые типы отличные от обжекта.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Паттерн "или"
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.23 14:50
Оценка:
Здравствуйте, nikov, Вы писали:

N>Он может быть неоднозначным, например, у них могут быть несколько общих интерфейсов, не связанных друг с другом. Или, например, у контравариантных делегатов Action<Array> и Action<IList<object>> есть общий базовый тип MulticastDelegate, но он не самый специфичный. Потому что у них ещё есть более узкие общие базовые типы Action<string[]>, Action<string[][]> (и много других), но ни один из них не является более специфичным чем другой, хотя они все более специфичны, чем MulticastDelegate.


По умолчанию для переменных должен выводиться наиближайший общий тип по основному дереву наследования (т.е. без учета интерфейсов). Если сопоставляются интерфейсы, то по их иерархиям выбор осуществлять. Ну а если уж неоднозначность в интерфейсах, то сообщать об ошибке. На классах неоднозначности быть не может.

N>А по поводу твоего исходного вопроса — это можно сделать так:

N>
N>if (foo() is (B or C) and var x)
N>{
N>  // здесь x имеет тип A, но попадаем сюда, только если значение x имеет тип B или С (или более производный)
N>}
N>


Да, то что нужно. Как-то после функциональных языков такой подход в привычный шаблон не влез.

Спасибо!

Остаётся только вопрос, работает ли это с вложенными паттернами содержащими переменные (когда в B и C могут быть вложенные поля/свойства которые тоже хочется сопоставить с переменными). Боюсь, что нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Паттерн "или"
От: vaa  
Дата: 24.04.23 23:56
Оценка:
Здравствуйте, VladD2, Вы писали:

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


vaa>>Разве B и C не в одном скоупе и типы разные? Опасная практика по-моему


VD>У них общие базовые типы отличные от обжекта.


ну да, но вот еще обратил внимание, что foo может быть вычислено дважды в if
если же вычислить перед if, то и переменную не нужно будет объявлять в шаблоне.
☭ ✊ В мире нет ничего, кроме движущейся материи.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.