Re[10]: Что должен возвращать if?
От: Evgeny.Panasyuk Россия  
Дата: 22.10.14 11:20
Оценка:
Здравствуйте, gbear, Вы писали:

G>Представим себе, что у нас есть у нас ф-ция f(int) -> maybe[int]. В какой, по вашему мнению, тип должен быть вычислен if(x > 0) f(x)?

G>Мне, вот, очевидно — в тот же самый maybe[int]. Надеюсь, что и вам тоже. И если это так, то объясните мне, как вы собираетесь провернуть такой "фокус" на "читых" variant'ах?

Явно или автоматически: Variant<Variant<T, void>, void> -> Variant<T, void>

G>>>А зачем вам какой-то явный unbox для variant? Вполне можно обойтись и неявным приведением к.

EP>>А где именно оно будет происходить? if-else будет сразу иметь этот тип? Или при присвоении к значению типа T?
G>Почему только при присвоении?! Везде, где "по смыслу" должно быть T.

Вот тут:
auto foo()
{
    return (if(c) T{1} else T{2});
}

какой должен быть тип результата у foo?

EP>>А для него не будет unbox'а — unbox это только для variant[T], то есть для тех случаев, когда обе ветки if-else имеют одинаковый тип результата, и variant внутри имеет значение только одного определённого типа.

G>Вот уж в этом-то случае, явный unbox смысла не имеет вообще.

Ещё раз (третий?), речь об обобщённом коде:
template<typename T, typename U>
void bar()
{
    auto res = if(c) T{} else U{};
    // use res as variant
}

Если делать здесь неявное преобразование variant[X] в X (в случае когда T == U), то этот код поломается, либо ему придётся вставлять дополнительные проверки.


G>В нашем случае использовать if не получится...


Почему?

G>конечно, если вы не предлагаете "нафантазировать" для этого случая еще один — специальный — "if". Ну, который не будет вычисляться в variant .


Зачем?

G>А вариант с двойной диспетчеризацией — еще хуже. Надеюсь, вы сами это понимаете.


Откуда двойная диспетчеризация-то?

G>>>Nemerle тут вообще не причем Недостаточно вычислить if в variant[A, B, C]. Нужно еще как-то "узнать", что конкретно этот variant сейчас в себе несет... A, B или C. И его нужно будет либо дополнительно проверять...

EP>>Точно также как и в случае с виртуальным вызовом метода результата
G>?! Вы вообще о чем? Как определить этот "метод"? Смысл использования variant'а — по вашей же логике — "впихнуть невпихуемое". Если мы подразумеваем общий интерфейс, то зачем variant-то?!

Я уже приводил пример, придётся скопировать:
Variant<Widget, Gadget> x, y;
// ...
apply(x, y, [](auto &x, auto &y)
{
    draw(x);
    draw(y);
    collide(x, y);
});

Здесь нет общего предка у Widget и Gadget (да и вообще у них нет ни одного метода), а интерфейс использования в данном случае у них одинаковый

G>>>Но просто так (без PM) использовать не получится. Хоть в Nemerle, хоть еще где.

EP>>Во-первых, в Nemerle же есть PM — в чём проблема?
G>Проблему можно выразить так: Если результат if можно обработать только через PM, то зачем нам использовать if? Почему сразу не использовать PM?!

Во-первых, не только через PM.
Во-вторых, претензия не понятна — в коде удобен if, получили из него variant, передали куда-то дальше, там обработали хоть PM'ом хоть ещё чем. В чём проблема-то?

G>Напоминаю, в сабже if — это "сахар" для PM.


И что? Это мешает построить if возвращающий variant?

EP>>Во-вторых — я же приводил уже примеры использования variant'а в C++ — нужен конкретный код?

G>Не нужен. Яж вам говорю... чудес не бывает
G>Одно дело, какой-нибудь условный:

G>
G>match (if (x > 0) getA() else getB())
G>{
G>  | y is A => handleA(y.PropertyOfA)
G>  | y is B => handleB(y.MethodOfB())
G>}
G>

G>А другое — предлагаемые вами "танцы на граблях" (с)

Чем код выше, принципиально отличается от следующего:
MATCH( IF(x>0) { return getA(); } ELSE { return getB(); } )
    CASE(y IS A) { handleA(y.PropertyOfA); }
    CASE(y IS B) { handleB(y.MethodOfB()); }
;

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.