Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет kouzdra ([info]kouzdra)
@ 2008-01-02 23:00:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Про throw
Есть такой забавный факт - throw в C++ является не оператором, а операцией - чтобы можно было писать что-то вроде:

(p == NULL ? throw BadPointer (p) : *p)

При этом возникают понятные проблемы с его типом - поскольку никакого осмысленного типа, кроме void, throw в C++ приписать понятно что нельзя. При этом однако возникает трабл - что тип условного выражения получался бы void, что малосодержательно.

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

Решение у трабла по идее простое - заводится парный к void тип - any, который является супертипом всех типов (а значений, как и void не имеет). В функциональных языках примерно так и сделано - только для этих целей используется тип forall a.a, но вот почему кажется ни в одном вообще процедурном языке такого не делали - загадка (в Algol-68, где в аналогичном контексте можно было писать goto, было придумано специально обученное преобразование типа, которое умело преобразовывать goto во что угодно - проблему в общем случае это тоже не решало)


(Добавить комментарий)


[info]illusive_fish
2008-01-03 00:18 (ссылка)
интересная мысль

это даже не Object в Java, поскольку пустой "объект" создать можно

(Ответить) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 00:33 (ссылка)
Это с точностью до наоборот - Object - общий предок, а это - общий наследник.

(Ответить) (Уровень выше)


[info]qwerty
2008-01-03 00:26 (ссылка)
Если разрешить этот тип руками писать в программе, боюсь, ничего хорошего не выйдет.

(Ответить) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 00:33 (ссылка)
А какой может быть криминал? По-моему как раз его отсутствие довольно много криви плодит. Это в общем-то просто тип для выражения, которое никогда не завершается "нормальным образом"

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-03 00:49 (ссылка)
Причем оно автоматичеси приводится к любому типу, но никакой другой тип к нему никаким способом не приводится?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 01:53 (ссылка)
Угу. В типовой науке про типы с пересечением/объединением оно известно - там часто вводят эти два типа - Top и Bottom соотвественно - чтобы получить замкнутость по этим операциям

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-03 01:58 (ссылка)
Это я, естественно, понимаю, но что делать с вынужденным приведением? Генерить аборт?

(Ответить) (Уровень выше)


[info]qwerty
2008-01-03 01:47 (ссылка)
Если естественный вид выражения отличается от этого типа и требуется приведение (вручную ли написан каст или как-нибудь еще), то что с этим делать?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 01:56 (ссылка)
К нему ничего приводится не может. Его смысл как раз в том, что оно ко всему приводится (так же как forall a.a унифицируется с любым типом - в ML если выведшийся тип результата функции - переменная, не зависящая от параметров - оно и значит, что функция никогда не возвращает управления "нормальным" обазом).

Собственно raise там и имеет тип exn -> 'a

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-03 02:00 (ссылка)
Ну что значит "не может"? Если написано, то это ошибка типизации во время компиляции?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 02:06 (ссылка)
Думаю что да. А что тут странного? В Жабе же тоже есть заведомо не приводимые друг к другу классы и там вроде тоже компилер ругается

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-03 02:15 (ссылка)
Если так, то, наверно, ничего особенно плохого, кроме пересмотра типов нескольких не возвращающих стандартных функций. В Ваткоме была соответствующая прагма, но она типизацию, конечно, не лечила.

А указатель на этот тип имел бы какое-нибудь разумное применение?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 02:17 (ссылка)
NULL

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-03 02:25 (ссылка)
Дополнительные правила потребуются, чтобы при сравнении приводить тип указателя.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-03 02:28 (ссылка)
Почему? В С++ по крайней мере в случае отношения класс/подкласс и void * они и так есть. Вроде естественным образом вписывается. В gcc есть такая константа __null (в нее NULL дейфайнится) - у ней тип void * и пляски с бубном про то, что она ко всему приводится

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-03 02:37 (ссылка)
Да, я уж проверил.

(Ответить) (Уровень выше)


[info]qwerty
2008-01-03 02:48 (ссылка)
Кстати, двойной и более указатель все-таки сам не приведется.

(Ответить) (Уровень выше)


[info]qwerty
2008-01-03 02:52 (ссылка)
Хотя, может, и приведется.

(Ответить) (Уровень выше)


[info]qwerty
2008-01-03 02:53 (ссылка)
Нет ли в пределах системы типов Ц++ жопы в том, что тип автоматически кастится к указателю на себя?

(Ответить) (Уровень выше)


[info]qwerty
2008-01-03 02:27 (ссылка)
Хотя нет.

(Ответить) (Уровень выше)


[info]dluciv.livejournal.com
2008-01-03 13:08 (ссылка)
> заводится парный к void тип - any, который является супертипом всех типов
Подтипом?

Вот только в плюсах самому сделать тяжеловато, думаю :)

(Ответить) (Ветвь дискуссии)


[info]qwerty
2008-01-03 13:17 (ссылка)
Не залазя руками в компилятор, самому это сделать невозможно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dluciv.livejournal.com
2008-01-04 17:14 (ссылка)
Определенно. Учитывая, особенно, то, что быть наследником int, например, в C++ нельзя.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-04 23:50 (ссылка)
А это не наследование. Из типа void тоже не наследуют, однако к нему все при необходимости приводится.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dluciv.livejournal.com
2008-01-05 11:27 (ссылка)
Тоже верно. Хотя не знаю, полноценно ли: связано ли (например, ковариантно) приведение типов к void с приведением указателей к void *, или это две отдельных фичи...

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-08 02:05 (ссылка)
Вы, право, что-то странное спрашиваете. void - очень специальный тип, у которого нет значений, и это много где используется в синтаксисе. Если он написан в списке формальных параметров, это означает, что их нет. Если он использован для типа результата, это означает, что никакого результате нет. Нельзя писать int f(void, void, int). Если void f(void) и void g(void), нельзя писать ни f(1), ни f(g()). И тому и другому можно было бы приписать более или менее естественную семантику, но синтаксис такого не разрешает (не из-за типов) и, думаю, это правильно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-08 02:10 (ссылка)
Нет там ничего специального - там вполне обычный сабтайпинг, только поскольку делался эволюционным методом - то с изрядным количеством лажи ("для совместипости", ага).

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-08 02:12 (ссылка)
Не может быть там никакой ко- тли контра-вариантности. Синтаксис не разрешает.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-08 02:16 (ссылка)
Не только не не может быть, но и просто есть. методы в С++ ковариантны по типу результата и afaik (в стандарт лень лезть) контраварианты по типам аргументов (как и положено). У void специфика ровно одна - он по всяким идиотским соображениям придуман так, что у него нет представления. Оттого прет разный ad hoc гемморой.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-08 02:44 (ссылка)
Ну и как ты собираешься писать параметр типа void? Про void как тип результата это просто неправда.

(Ответить) (Уровень выше)


[info]qwerty
2008-01-08 06:07 (ссылка)
В стандарте, кстати, говорится исключительно про ковариантность методов с результатами типа указателей на классы. Де факто имеет место контравариантность по скрытому параметру this. И то и другое, естественно, понимается в смысле совместимости типов функций и, в частности, перегрузки виртуальных методов. Примерно так:
class A { ... };
class B: A {};

class C {
  virtual A* f(какие-то формальные аргументы);
};

class D: C {
  virtual B* f(формальные аргументы с теми же типами, что и сверху);
}

Для перегрузки необходимо совпадение имен и типов аргументов. Результат может не совпадать и быть надклассом. Если для аргумента написать надкласс для контравариантности (или подкласс для ковариантности, что было бы неестественно, но в данном случае результат тот же), перекрытия не будет.

Теперь возвращаемся к void'у в качестве результата. Если бы void был обычным надтипом, то можно было бы в надклассе написать void f(...), а в подклассе A* f(те же аргументы), и вследствие ковариантности по результату произошла бы перегрузка. Ан хер - перекрытия не будет, а будет ошибка времени компиляции.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2008-01-08 16:19 (ссылка)
this как раз ковариантен - с чем и связаны проблемы с интерпритацией объектности в терминах сабтайпинга - по сабтайпингу аргументы функций контраварианты, что малоосмысленно (потому видимо в С++ и отсутствует)
но корректно.

Теперь возвращаемся к void'у в качестве результата

void не является обычным надтипом - отчасти по историческим причинам, отчасти потому, что в С++ вообще корректно говорить о сабтайпинге только применительно к указателям (сабтайпинг подразумевает совпадение представлений собственно значения). Но такое вот работает:

class C {
public:
  virtual void const * f () const = 0;
};

class D: public C {
public:
  virtual D const * f () const { return 0; }
};


Хотя и с предупреждением:

warning: deprecated covariant return type for ‘virtual const D* D::f(const B*) const

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2008-01-08 21:18 (ссылка)
Да, насчет this я написал странное :) Все-таки жестокая отладка железяки через последовательный порт с трудом совмещается с категориями.

Гм, в VS 6 вышеуказанный фрагмент компилируется с ошибкой. Могу попробовать спросить фронтенд EDG.

(Ответить) (Уровень выше)


[info]qwerty
2008-01-09 02:15 (ссылка)
Гы-гы, наистандартнейший EDG от твоего фрагмента помер, сказав "Segmentation fault" :)

В сухом остатке имеем: нету в Ц++ контравариантности по аргументам, есть ковариантность по this и результату применительно к указателям на классы. Твой компилятор еще позволяет void как всеобщий надтип в позиции результата, ругаясь при этом, что сие устарело.

Хуже ли приходится в Ц++ типу void в позиции аргумента, чем указателям на классы? По-моему, да, поскольку войдового аргумента в произвольной позиции списка формальных параметров просто не написать, за исключением случая единственного войдового аргумента, который не отличим от нуля аргументов. Поправить синтаксис, наверно, было бы просто, разрешив писать ,, или void,. И устроить контравариантность, по-моему, тоже ничего не мешает. Но ее, тем не менее, нет.

Обсуждать ковариантность void в качестве типа this я, пожалуй, не возьмусь - это нужно взывать к духу усопшего Канта и определять, указателем на какой класс-в-себе является void (не void*), а потом обсуждать свойства методов этого класса-в-себе.

Включить void в ковариантность по результату, по-моему, можно с ограничениями - для всего, кроме выдаваемых по значению структур (за исключением маленьких). Можно сделать и для выдаваемых по значению структур, но потребуются нетривиальные подпрыгивания.

(Ответить) (Уровень выше)

офф-топик
[info]nika
2008-01-04 01:02 (ссылка)
завтра вечером оказались неожиданные обстоятельства...
можно ли перенести встречу?

(Ответить) (Ветвь дискуссии)

Re: офф-топик
[info]kouzdra
2008-01-04 01:07 (ссылка)
Ok. а когда примерно.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: офф-топик
[info]nika
2008-01-04 01:18 (ссылка)
в 2 часа в субботу я собираюсь пойти с художниками из группы "Что делать?" в эрмитаж на выставку современного американского искусства. в рассылке написано, "всем кому интересно".
Если тебе интересно, то можем там и встретиться, а потом пойти к нам пить чай (кофе).
если нет, то сразу потом.
вот сюда идти:
http://www.hermitagemuseum.org/html_Ru/13/hm13_2_020.html
текст о выставке запостить не удалось.
в РЛЖ есть ограничения на размер комментов.
послала по мылу


(Ответить) (Уровень выше)

Re: офф-топик
[info]nika
2008-01-04 01:21 (ссылка)
если не удобно, то давай завтра с утра созвонимся.
что-нибудь придумаем.

(Ответить) (Уровень выше)

Re: офф-топик
[info]nika
2008-01-04 01:34 (ссылка)
письмо с описанием выставки вернулось..на какое мыло послать?

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: офф-топик
[info]kouzdra
2008-01-04 02:57 (ссылка)
msk собака nickname ru

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: офф-топик
[info]nika
2008-01-05 12:33 (ссылка)
что-то не дошло ничего про выставку.
но она, правда, хорошая.
Приходи!

(Ответить) (Уровень выше)