Здравствуйте, WolfHound, Вы писали:
WH>Однако система типов С++ весьма не формальна и все проверки осуществляются в момент вызова unwrap.
WH>Есть ли языки где можно провернуть такой фокус проверив типы unwrap в месте ее описания, а не в месте вызова.
Можно более подробно описать проблему для ммм... приплюснутых мозгов?
Проверка типа в момент вызова (инстанциации) функции происходит при использовании специализаций шаблона.
В данном случае специализации шаблона нет, есть 2 перегруженные функции, тип агрумента которых уже известен в момент определения.
Немного упрощу предложенное решение, что бы это стало очевидно:
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
WH>Однако система типов С++ весьма не формальна и все проверки осуществляются в момент вызова unwrap.
WH>Есть ли языки где можно провернуть такой фокус проверив типы unwrap в месте ее описания, а не в месте вызова.
На D можно запихнуть в одну compile time функцию, но по сути будет тоже что и в C++ проверка при инициализации.
Здравствуйте, gear nuke, Вы писали:
WH>>Есть ли языки где можно провернуть такой фокус проверив типы unwrap в месте ее описания, а не в месте вызова. GN>Можно более подробно описать проблему для ммм... приплюснутых мозгов?
Честно говоря не понимаю куда подробнее.
Проблема в том что все проверки осуществляются вот в этом месте
unwrap(box(box(box(box(box(box(123)))))))
А хочется чтобы к этому моменту уже все было проверено
GN>Проверка типа в момент вызова (инстанциации) функции происходит при использовании специализаций шаблона. GN>В данном случае специализации шаблона нет, есть 2 перегруженные функции, тип агрумента которых уже известен в момент определения.
А ты хорошо смотрел?
А это что?
typename UnwrapBoxedType<T>::type
Также не стоит забывать вот про эту волшебную строку
return unwrap(box.Get());
разрешение перегрузки опять же происходит в момент вызова функции.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Проблема в том что все проверки осуществляются вот в этом месте WH>unwrap(box(box(box(box(box(box(123))))))) WH>А хочется чтобы к этому моменту уже все было проверено
Задай в Box<> целочисленный параметр-счетчик, определяющий глубину вложения, и перепиши специализации UnwrapBoxedType<> с рекурсивным использованием счетчика, типа ручная проверка.
Только не понятно, зачем? Да, в момент компиляции конкретного места вызова ф-ии, компилятор сам рекурсивно проверит все типы для каждой итерации unwrap(), вплоть до своего ограничения на глубину вложенности шаблонов.
WH>разрешение перегрузки опять же происходит в момент вызова функции.
Хотел сказать, компиляции места вызова?
Да, проблема известная. Это из-за отсутствия частичной специализации ф-ий, вследствии чего приходится использовать пользовательские типы-хелперы, навроде твоего UnwrapBoxedType<T>. Проблема тут в том, что раз хелпер-это другой тип, не связанный с Box<>, то в момент его определения и определения шаблонной ф-ии unwrap компилятор не способен проверить соответствие типов (без того "ручного" счетчика, например). Я в похожих случаях стараюсь давать компилятору больше информации, типа:
template<typename T>
struct Box {
typedef T value_type;
typedef T most_wrapped_type;
...
};
А в самом хелпере UnwrapBoxedType просто перенаправить на Box<>::most_wrapped_type, чтобы уменьшить вероятность ошибки. (Рассматриваемый пример конечно примитивен и не нуждается в этом, но это я об общей практике говорю).
Правда, MS VC все-равно все нафиг игнорирует, т.е. не проверяет толком шаблоны. Дык, зато GCC с версий 4.x более внимательно их проверяет, и частенько ругается на всякие несоответствия еще до инстанциирования, т.е. в момент компиляции самих шаблонных определений, чем приятно радует.
Конечно, нужны явные constrains. До определенной степени их можно эмулировать (и в бусте полно хелперов под распространенные случаи, довольно-таки мощный там раздел type traits), но на уровне языка, т.е. с нормальным синтаксисом, а не тонной угловых скобок, было бы интересней.
Здравствуйте, vdimas, Вы писали:
V>Задай в Box<> целочисленный параметр-счетчик, определяющий глубину вложения, и перепиши специализации UnwrapBoxedType<> с рекурсивным использованием счетчика, типа ручная проверка.
Box менять нельзя.
V>Только не понятно, зачем? Да, в момент компиляции конкретного места вызова ф-ии, компилятор сам рекурсивно проверит все типы для каждой итерации unwrap(), вплоть до своего ограничения на глубину вложенности шаблонов.
Проблема в том что в таком виде unwrap нельзя скомпилировать и положить в отдельный модуль.
V>Да, проблема известная. Это из-за отсутствия частичной специализации ф-ий, вследствии чего приходится использовать пользовательские типы-хелперы, навроде твоего UnwrapBoxedType<T>.
Нука покажи как это можно сделать без использования UnwrapBoxedType.
V> Проблема тут в том, что раз хелпер-это другой тип, не связанный с Box<>, то в момент его определения и определения шаблонной ф-ии unwrap компилятор не способен проверить соответствие типов (без того "ручного" счетчика, например). Я в похожих случаях стараюсь давать компилятору больше информации, типа:
Ты не понял.
Мне интересно решение конкретной задачи.
Причем не абы какое, а формальное.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Есть ли языки где можно провернуть такой фокус проверив типы unwrap в месте ее описания, а не в месте вызова.
Можно точно сформулировать требуемые ограничения на "фокус"? Такое впечатление, что все сложности связаны с полубезумными механизмами терминирования типовой рекурсии на шаблонах.
Почему бы, например, не маркировать завершение рекурсии по типам явно, поименовав конструктор небоксированных данных?
data Boxes a = Value a | Box (Boxes a)
unwrap :: Boxes t -> t
unwrap (Box b) = unwrap b
unwrap (Value v) = v
Здравствуйте, deniok, Вы писали:
D>Почему бы, например, не маркировать завершение рекурсии по типам явно, поименовав конструктор небоксированных данных?
Так не интересно.
Ибо вот эти значения имеют один тип.
(Box (Value 123))
(Box (Box (Value 123)))
В исходной задаче они имеют разные типы.
Хочется вот такое
data Box a = Box a
unwrap :: ??? -> t
???
unwrap (Box(Box(Box(Box(123)))))
Хочется посмотреть на язык в котором такое можно.
Ибо что-то мне подсказывает что если можно такое то система типов позволит еще много интересного.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Мне интересно решение конкретной задачи. WH>Причем не абы какое, а формальное.
Из очевидных формальных — с положительным целочисленным счетчиком в Box и генерацией ошибки на некоем count==some_max. А не меняя Box<> решить в общем виде ИМХО в принципе невозможно, хотя бы из-за потенциальной бесконечной вложенности.
В типах дотнета красивое и строго типизированное решение вообще не представимо. У меня была абсолютно идентичная задача, так вот, без всяких динамиков она решалась примерно так:
interface IBoxedValue { object Value { get; } }
interface IBoxedValue<T> { T Value { get;} }
class Box<T> : IBoxedValue<T>, IBoxedValue { ... }
object GetRealObject(object o) {
object tmp;
while(null != (tmp=(o as IBoxedValue)))
o = tmp.Value;
return o;
}
К тому же, интерфейс IBoxedValue использовался не только в Box<>, бо прием типа ISomethingProvider удобен в массе различных вариаций.
Здравствуйте, deniok, Вы писали:
D>Почему бы, например, не маркировать завершение рекурсии по типам явно, поименовав конструктор небоксированных данных? D>
D>data Boxes a = Value a | Box (Boxes a)
D>unwrap :: Boxes t -> t
D>unwrap (Box b) = unwrap b
D>unwrap (Value v) = v
D>
Здравствуйте, WolfHound, Вы писали:
WH>>>Есть ли языки где можно провернуть такой фокус проверив типы unwrap в месте ее описания, а не в месте вызова. GN>>Можно более подробно описать проблему для ммм... приплюснутых мозгов? WH>Честно говоря не понимаю куда подробнее. WH>Проблема в том что все проверки осуществляются вот в этом месте WH>unwrap(box(box(box(box(box(box(123))))))) WH>А хочется чтобы к этому моменту уже все было проверено
ок. где по твоему все уже должно быть проверенно? (в каком месте)
Здравствуйте, WolfHound, Вы писали:
WH>Хочется вот такое WH>
WH>data Box a = Box a
WH>unwrap :: ??? -> t
WH>???
WH>unwrap (Box(Box(Box(Box(123)))))
WH>
WH>Хочется посмотреть на язык в котором такое можно.
"Такое" мне непонятно. unwrap — это функция, то есть ??? — это тип. Задача — свернуть семейство возможных здесь тИповых конструкций в замкнутую форму для этого типа. Вариант ad hoc множества типов не очень элегантен (ручками писать все возможные перегрузки — задолбаешься) и, вроде, ни кем и не предлагается. Я предложил классический рекурсивный тип; можно ещё забацать индексированное натуральными числами семейство.
Здравствуйте, WolfHound, Вы писали:
WH>Есть ли языки где можно провернуть такой фокус проверив типы unwrap в месте ее описания, а не в месте вызова.
То, чем ты занимаешься, называется "извращение". Присоединюсь, если ты не против
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, IncoherentInstances, TypeFamilies #-}data Box a = Box a
class Boxed b v where
unwrap :: b -> v
instance Boxed b v => Boxed (Box b) v where
unwrap (Box x) = unwrap x
instance (l ~ r) => Boxed l r where
unwrap x = x
> unwrap (Box(Box(Box(Box(123)))))
123
L>{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, IncoherentInstances, TypeFamilies #-}
L>instance (l ~ r) => Boxed l r where
L> unwrap x = x
L>
Здравствуйте, WolfHound, Вы писали:
WH>А это что? WH>typename UnwrapBoxedType<T>::type
Это "вытащенный из коробки" тип T. Он уже известен в момент определения функции.
WH>Также не стоит забывать вот про эту волшебную строку WH>return unwrap(box.Get()); WH>разрешение перегрузки опять же происходит в момент вызова функции.
Оно происходит когда компилятор смотрит тело функиции, то есть в момент определения.
Можно добавить явное инстанциирование (и проверки) перед вызовом:
auto p = &unwrap<Box<Box<Box<Box<Box<int>>>>>>;
Это можно скомпилировать и положить в отдельный модуль. Однако есть проблема с неограниченной вложенностью.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth