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

G>>А явно это как? Особенно интересно, как это "явно" будет выглядеть в обобщенном коде.

EP>Например simplify(v) или какой-нибудь унарный оператор ^^ v

Да я не про это. Кто будет "дергать за веревочку"? И главное — как он будет определять нужно ли "дергать"?

Есть foo(x) -> void и bar(x) -> variant[int, void].

if(x > 0) bar(x) else foo(x)


Нужно "дергать"?

if(x > 0) bar(x)


А теперь?

if(x > 0)
  if(x > 10) x else foo(x)


А если так?

G>>А если автоматически, то получается тип Variant<Variant<T, void>, void> существовать не может? Я вас правильно понимаю?

EP>Хм, наверное да. Точнее существовать может, но до первого использования.

Плохо это. Потеряем возможность поймать "go wrong". Variant<Variant<T, void>, void> вполне может означать — что все ок... ну просто, например, вложеный if-c-else вычислился в void.
Привели к Variant<T, void> — и если "внутрях у неё" void — будем думать, что до вложенного if дело вообще не дошло.

Вывод, нужен таки maybe, а не суррогаты

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

EP>>>Почему?
G>>?! Очевидно, потому что if вернет нам новый variant. С которым "нужно что-то делать"
EP>Когда из if возвращается указатель на какую-нибудь абстрактную базу, при работе с ней придётся точно также выяснять — что же там внутри, и какой именно метод вызывать. Выбор-то никуда не исчезает

def a = if(x > 0) "a" else 1; // "абстракная база" в виде какого-нибудь IConvertable  
def b = if(a is string) stringToX(a) else intToX(a); // Вполне конкретный X


В вашем случае: b — это в лучшем случае variant[X]. Что дальше? Можно и по сложней примеры нарисовать — например, когда "база" таки нужна. Но, в вашем варианте получим очередной variant[T, U] .

G>>Это пример из boost, в который вы мне тыкали, как в пример. И таки да... это называется, двойная диспетчеризация.


EP>Там одинарная диспетчеризация, а не двойная


Да же так

template <typename Visitor, typename Visitable>
inline
    BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
apply_visitor(Visitor& visitor, Visitable& visitable)
{
    return visitable.apply_visitor(visitor);
}

...

template <typename Visitor, typename VoidPtrCV, typename T>
inline
    BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl_invoke_impl(
      int, Visitor& visitor, VoidPtrCV storage, T*
    , mpl::true_// never_uses_backup
    )
{
    return visitor.internal_visit(
          cast_storage<T>(storage), 1L
        );
}


Т.е. вот это все мне мерещится?!

Понимаете, то, что в данном случае диспетчеризация — скорее всего... этожплюсы, в конце концов — статическая (не виртуальная, если хотите) — ничего не меняет.

G>>Что мешает-то на лету "собрать" нужный тип (в вашем примере, это агрегат Widget и Gadget), реализующий _нужный_ интерфейс?!

EP>Пример сборки нужного типа в студию. Мне кажется это будет сложнее чем variant.

А в чем проблема? Я такой тип вам и в C# соберу "налету" — только в run-time. В чем проблемы то?! Нам же нужен только агригат (контейней, если хотите), который делегирует вызовы конкретного интерфейса, конкретному экземпляру.
В Nemerle — такой же фокус можно провернуть в compile-time. А сложность тут вообще не причем... этот код пишется ровно один раз.

EP>Тем что такой синтаксис можно получить на базе boost::variant


Синтаксис-то тут причем?! Скажите лучше во что это вычислится? В variant?

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