Здравствуйте, reductor, Вы писали:
R>Я в общем уже говорил это — я никого и ничего тут не поддерживаю и не пропагандирую. R>Я не являюсь фанатом или апологетом какого-либо языка, платформы или чего-то подобного. Я всего лишь отвечаю на вопросы.
О, это видно.
R>Да мне в общем-то даже спорить неинтересно. Мне интересно узнавать что-то новое для себя. Затем я здесь.
Аналогично.
R>Если кто-то спрашивает о чем-то, в чем я разбираюсь — могу ответить. R>Ратовать и пропагандировать — не люблю.
Я плякаль. Видимо ответы по производительности Окамла были эдакой шуткой юмора.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, reductor, Вы писали:
R>То, что окамл нацелен на работу со списками — чистой воды фантазии, да девичьи мечты.
Может быть лучше быть несколько более корректным в оценке чужого мнения? После такой аргументации, да еще столь очевидных вещей как-то продолжать конструктивный разговор не хочется.
R>Вот, минут за 20 на коленке mergesort (устойчивая O(n log n) сортировка) in-place на окамле. Почти не использует никаких библиотечных функций: R>
R>open Array;;
R>let msort xs =
R> let rec sort bgn fin =
R> let rec merge bgn mid fin =
R> let shift () = blit xs bgn xs (bgn + 1) (mid - bgn) in
R> if mid >= fin || bgn >= mid then ()
R> else let x, y = xs.(bgn), xs.(mid) in
R> let change () = (shift (); xs.(bgn) <- y) in
R> let bgn, mid = if x <= y then (bgn + 1, mid)
R> else (change (); (bgn, mid + 1))
R> in merge bgn mid fin in
R> if fin - bgn <= 1 then ()
R> else let mid = (fin + bgn) / 2 in
R> let () = sort bgn mid; sort mid fin
R> in merge bgn mid fin
R> in sort 0 (length xs);;
R>
R>Не используя даже матчинг и циклы. R>Тут можно еще раза в полтора сократить, причем, избавившись от всего библиотечного, но мне лень.
Да, надо бы. А то ведь императивный вариант на С++/C# оказывается куда более кратким.
static void SmartQSort<T>(T[] arr, int lo, int hi, IsLess<T> isLess)
{
int i = lo;
int j = hi;
T sep = arr[(lo + hi) >> 1];
while (i <= j)
{
while (isLess(arr[i], sep))
i++;
while (isLess(sep, arr[j]))
j--;
if (i <= j)
{
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
if (lo < j)
SmartQSort(arr, lo, j, isLess);
if (i < hi)
SmartQSort(arr, i, hi, isLess);
}
Если кажется что много строк, то можно записать это по изуверски :
static void SmartQSort<T>(T[] arr, int lo, int hi, IsLess<T> isLess)
{
int i = lo, j = hi; T sep = arr[(lo + hi) >> 1];
while (i <= j) {
while (isLess(arr[i], sep)) i++; while (isLess(sep, arr[j])) j--;
if (i <= j) { T tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i++; j--; }
}
if (lo < j) SmartQSort(arr, lo, j, isLess);
if (i < hi) SmartQSort(arr, i, hi, isLess);
}
Впрочем этого я и ожидал. Красота и краткость быстрой сортировки на Окамле заслуга операторов работы со списками которые принципально не могут работать по месту и с массивми.
R>Слишком усердно не тестировал, но вроде сортирует.
Это не важно. Важно, что от поражающей краткости и простоты не осталось и следа.
А стало быть подобные примеры не больее чем красивый рекламный ход.
VD>>Ну, тебе виднее. Я в Окамле делетант. R>Я правильно вас понимаю, что вы считаете нормальным — являсь дилетантом в языке выдавать агрессивные суждения о нем и еще потом отстаивать свои фантазии?
Незнаю. Ты вор вроде себя делетантом не считашь, но выдашь кучу своих фантазий не имеющих ничего общего с действительность. Причем делашь это крайне агрессивно. Стало быть этот аспект от глубины познания технологии не зависит.
R>Если так, дальнейшая дискуссия не имеет смысла.
Я это уже слышал много раз. Слабенький аргумент.
VD>>Но вот в совершенно не функциональном Руби код получается не более длинный чем в Окамле, а ведь "матчить" то он вроде не умеет.
R>Я правильно вас понимаю, что вы предлагаете всем отказаться от окамла и С++ в пользу руби?
Нет не правльно. Это все твои фантазии.
Я просто привел преимер императивного языка со встроенными средствами работы со списками.
R>Если я не ошибаюсь, то дилетанство было подтверждено от первого лица.
Первокурсники тоже были подтверждены от первого лица?
Возможно я дилетант в Окамле, но это не значит, что я дилитант в программировании или не понимаю о чем говорю. По этому предлагаю придерживаться правил приличия и обсуждать технические вопросы, а не вопросы познания друг-друга в некоторых областях.
R>А что касается лично меня — я пока не начинал переходить на личности.
А как назвать постоянные выпады и эпитеты?
R> И не нужно мне говорить лучший я или не лучший и какие тут перцы — все это меня не волнует ни единой секунды.
А я думаю, нужно. Может это все же остановит тебя и переведет в область конструктивного разговора, а не доказательства от "совсем противного оппонента".
VD>>В общем, общаться на уровне "делетантсва" и "первокурсников" я не намерен. Отвечая таким образом на технический вопрос ты рассписывашся в своей неправоте. Мне этого ответа достаточно. Но если вдруг захочется дейсвительно аргументировано ответить, то я буду очень рад.
R>Интересно бы еще услышать в какой неправоте я здесь рассписываюсь.
Ты сыплешь натянутыми утверждениями которые рассыпаются как только кто-то копнет на штык в глубь. Все твои примеры и ссылки оказались мягко говоря не состоятельными. В конце концов в ход поперли откровенные оскорбления. О какой правоте тут вообще можно вести речь?
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
R>>Нет, разверзгнутся хляви небесные, наступит армагеддон и мы все очутимся в геене огненной.
VD>Смешно. Но ответа как всегда нет.
параметр последнего флага — это опция, которая передастся компилятору gcc. Не забудьте передать ему ваши любимые опции — пусть хоть оптимизнет код немного, штоли. А то пнимаешь, сравнивают здесь... Кодогенератор gcc при отключенной оптимизации c более качественным кодогенератором MSVC.
Короче, не надо передергивать. Сравнивайте gcc с OCamlopt — так будет честно.
Ксатити, по приведенной тобой ссылке используется как раз gcc. А не MSVC последней версии, у которого кодогенератор заметно качественнее.
Короче, твои аргументы в этом грандиозном флейме высосаны из пальца, на самом деле. ocamlopt использует gcc для кодогенерации. Вот и все. Так что для правильного сравнения надо или заставить OCaml использовать MSVC, или использовать gcc (для чего можно и по ссылке сходить — посмотреть, как плюсовая прога немного проиграет окамловой — такие случаи иногда бывают). Если ты, конечно, хочешь сравнить языки.
Я использовал опции компилятора приведённые в оригинальном тесте.
G>Не забудьте передать ему ваши любимые опции — пусть хоть оптимизнет код немного, штоли. А то пнимаешь, сравнивают здесь... Кодогенератор gcc при отключенной оптимизации c более качественным кодогенератором MSVC.
+ из пакета MSVC используются 2 вещи: ml.exe для ассемблирования полученного листинга и link.exe для линковки.
G>Короче, не надо передергивать. Сравнивайте gcc с OCamlopt — так будет честно.
Зачем я буду сравнивать с gcc? Вы мне ещё предложите для компиляции С++ его использовать. Есть куда более качественные бесплатные компиляторы. Я сравниваю со своим _обычным_ инструментом. Меня в первую очередь интересует как будет это работать на платформе, которая нужна _мне_.
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
G>Ксатити, по приведенной тобой ссылке используется как раз gcc. А не MSVC последней версии, у которого кодогенератор заметно качественнее.
Можете конкретезировать где gcc? Мне плохо понятно о чём речь.
G>Короче, твои аргументы в этом грандиозном флейме высосаны из пальца, на самом деле.
Так же как и обвинения в жульничестве.
Потрудитесь привести аргументы.
G>ocamlopt использует gcc для кодогенерации. Вот и все. Так что для правильного сравнения надо или заставить OCaml использовать MSVC, или использовать gcc (для чего можно и по ссылке сходить — посмотреть, как плюсовая прога немного проиграет окамловой — такие случаи иногда бывают).
По какой ссылке?
G>Если ты, конечно, хочешь сравнить языки.
Я хочу сравнивать языки не в теории, а на практике.
Теоретически, самый хороший язык — это ассемблер. Знаете как на нём всё быстро будет работать после ручной оптимизации? А если автоматическую прикрутить? Почему же на нём не пишут? Может быть, люди хотят синицу в руках сейчас, а не журавля в небе к старости?
Мне, честное слово, надоело в этом топике читать ответы "пойди туда, не знаю куда". Сказали скомпилируй и посмотри — так и сделал. Ну, сделал не правильно — покажите, где ошибка. А то просто смешно получается — "ты не прав, потому что не прав".
P.S.
Я могу так же утверждать, что оригинальный тест — подтасовка. Выбрали компилятор, который проигрывает OCaml.
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
Здравствуйте, VladD2, Вы писали:
R>> для этого а) не нужно никакого анализа. б) это прописано в _стандартах_ некоторых языков. R>>как можно _оптимизацией_ называть то, что входит в стандарт?
VD>Пофигу куда что входит. Для ФЯ эта оптимизация жизненно-важна, вот и додумался народ упомянуть о ней в стандарте. Попробуй найти ИЯ в котором такое же упоминание найдется.
Влад, это — не оптимизация. Остановись на секунду и вернись к истокам:
— что такое циклы? цикл — это повторение одних и тех же участков кода.
Для полноты языка в числе прочих требуется присутствие оператора условного перехода (например IF-GOTO), такой язык позволит реализовать ЛЮБОЙ алгоритм.
"Синтаксический сахар" структурного подхода отменил GOTO и предоставил конструкции циклов для аналогичных целей. Т.е., в стандарте языков выросших из структурного подхода так и сказано (например):
— для организации цикла необходимо применить оператор do-while (loop, for, whatever...)
А применительно к Haskell, в том же самом месте сказано примерно следующее:
— для организации цикла необходимо применить хвостовую рекурсию!
В этом языке нет больше ср-в для организации циклов, т.к. нет операторов перехода, да и переходить, собственно, некуда
Тебе же reductor сказал — "условие существования", а ты не обратил внимание.
Понятное дело, что не могли создатели языка ограничить длину обрабатываемых данных глубиной стека. Поэтому то, что внешне выглядит как хвостовая рекурсия, на самом деле является стандартной записью цикла (как do-until в Pascal, например)
R>>в случае со scheme и haskell, например, это "уменьшение быстродействия" приведет к неработоспособному коду R>>вот и все.
VD>С чего бы это? Если ты о линивости, то это несколько другая песня.
Нет, о переполнении стека на обработке любого файла, длина которого больше, навскидку, 250 тыс элементов.
VD>Ненадо излишней философии. Мы говорим об оптимизациях в компиляторах.
Gaperton wrote: > > Ксатити, по приведенной тобой ссылке используется как раз gcc. А не MSVC > последней версии, у которого кодогенератор заметно качественнее.
Это очень спорное утверждение. Например, если скомпилировать
криптографический алгоритм rc4, наивно написанный на C без всяких там
выкрутасов, то gcc 2.95 с чем-то обогнал MSVC 7.1 в два раза по
производительности получившегося кода.
> Короче, твои аргументы в этом грандиозном флейме высосаны из пальца, на > самом деле. ocamlopt использует gcc для кодогенерации. Вот и все. Так
Уй, правда что ли? Вообще-то, он всегда умел сам кодогенерить...
В оригинальном тесте ocamlopt использует gcc для кодогенерации, и сравнивается с gcc. А у тебя — нет. Так что флажки все-таки проставь. Например, -unsafe. Не надо тут вешать мне лапшу, что твой плюсовый код проверяет границы массивов, так что давай поставим их в равные условия. Для начала.
G>>Не забудьте передать ему ваши любимые опции — пусть хоть оптимизнет код немного, штоли. А то пнимаешь, сравнивают здесь... Кодогенератор gcc при отключенной оптимизации c более качественным кодогенератором MSVC.
GN>Где gcc?
Опция -ccopt передает флаги компилятору С. Угадай, какому, и зачем ocamlopt-у нужен компилятор С. Я понятия не имею, какой компилятор С поднимается у тебя на машине. Это уж ты сам разберись, раз взялся reductor-а с дерьмом мешать.
GN>Зачем я буду сравнивать с gcc? Вы мне ещё предложите для компиляции С++ его использовать. Есть куда более качественные бесплатные компиляторы. Я сравниваю со своим _обычным_ инструментом. Меня в первую очередь интересует как будет это работать на платформе, которая нужна _мне_.
Затем, что ты опять в... пытаешься ввести общественность в заблуждение касательно своих намерений. Ты тут недалеко говорил, что ты не согласен с излишне категорично фразой, что ocaml может быть быстрее С++ (делая такой вид). Речь идет не о тебе, и о том что тебе надо (это ни мне ни общественности не интересно), а о самом языке, так что сравнение надо проводить на кодогенераторах одинакового качества. ocamlopt-у для кодогенерации нужен С-шный компилятор, который при сравнении должен быть одинаков, и запускаться с теми же самыми флагами. Короче, взялся флеймить — отвечай за базар.
Здравствуйте, Pzz, Вы писали:
Pzz>Gaperton wrote: >> >> Ксатити, по приведенной тобой ссылке используется как раз gcc. А не MSVC >> последней версии, у которого кодогенератор заметно качественнее.
Pzz>Это очень спорное утверждение. Например, если скомпилировать Pzz>криптографический алгоритм rc4, наивно написанный на C без всяких там Pzz>выкрутасов, то gcc 2.95 с чем-то обогнал MSVC 7.1 в два раза по Pzz>производительности получившегося кода.
Ой, правда штоли? Что же тогда gear nuke так отмахивается от идеи использовать такой хороший gcc при сравнениях с окамлом? А, понял — тогда у нас окамл самый быстрый в мире язык получится. .
А вообще — из того, что один компилятор на одной маленькой проге кого-то там обогнал — не следует ничего ровным счетом. Подумаешь, gcc на маленькой программе за счет unrolling-а короткого цикла (единственный фокус, который может ему помочь) смог чутка выбится вперед. Глупости.
>> Короче, твои аргументы в этом грандиозном флейме высосаны из пальца, на >> самом деле. ocamlopt использует gcc для кодогенерации. Вот и все. Так
Pzz>Уй, правда что ли? Вообще-то, он всегда умел сам кодогенерить...
Неправда. С-шные опции ему тока для сборки с С-шными сорцами нужны Перепутал чутка . Впрочем, -unsafe это не отменяет. И использования кросплатформенного кодогенератора для сравнения — например, того же gcc.
Здравствуйте, gear nuke, Вы писали:
GN>P.S. GN>Я могу так же утверждать, что оригинальный тест — подтасовка. Выбрали компилятор, который проигрывает OCaml.
Почему же, многие люди пользуются gcc, и не считают его таким уж прям плохим. На ряде платформ это вообще единственный компилятор, и ничего. Так что какая такая подтасовка?
Ваша подтасовка в том, что вы подменили в утверждении reductor-а "C++" на MSVC. В то время как reductor не уточнял, о каком компиляторе идет речь. gcc — вполне себе нормальный компилятор С++. Таки в чем подтасовка в статье?
Здравствуйте, Gaperton, Вы писали:
G>В оригинальном тесте ocamlopt использует gcc для кодогенерации, и сравнивается с gcc. А у тебя — нет.
Ну так я и проверяю правомерность оригинального теста.
G>Так что флажки все-таки проставь. Например, -unsafe. Не надо тут вешать мне лапшу, что твой плюсовый код проверяет границы массивов, так что давай поставим их в равные условия. Для начала.
Хорошо. Пробую поставить флажки как советовали:
ocamlopt -inline 100 -unsafe -ffast-math -ccopt -O3 ray.ml -o ray
ocalmopt
(Microsoft-based native Win32 port 3.09.0) Новые результаты
30,60 сек 29,48 сек
30,69 сек 29,48 сек
30,59 сек 29,48 сек
почти на 4 %
G>>>Не забудьте передать ему ваши любимые опции — пусть хоть оптимизнет код немного, штоли. G>>> А то пнимаешь, сравнивают здесь... Кодогенератор gcc при отключенной оптимизации c более качественным кодогенератором MSVC.
GN>>Где gcc? G>Опция -ccopt передает флаги компилятору С. Угадай, какому
Повторю — OCaml сам оптимизирует. cl.exe вызывается только для линковки. В этом можно убедиться переименовав cl.exe:
"cl" не является внутренней или внешней
командой, исполняемой программой или пакетным файлом.
Error during linking
G>и зачем ocamlopt-у нужен компилятор С.
Помоему — незачем.
G> Я понятия не имею, какой компилятор С поднимается у тебя на машине. Это уж ты сам разберись, раз взялся reductor-а с дерьмом мешать.
Ну так я разобрался — никакой.
Красиво обвинять, не разобравшись самому?
GN>>Зачем я буду сравнивать с gcc? Вы мне ещё предложите для компиляции С++ его использовать. Есть куда более качественные бесплатные компиляторы. Я сравниваю со своим _обычным_ инструментом. Меня в первую очередь интересует как будет это работать на платформе, которая нужна _мне_.
G>Затем, что ты опять в... пытаешься ввести общественность в заблуждение касательно своих намерений. Ты тут недалеко говорил, что ты не согласен с излишне категорично фразой, что ocaml может быть быстрее С++ (делая такой вид). Речь идет не о тебе, и о том что тебе надо (это ни мне ни общественности не интересно)
Думаю, той общественности, которая пишет под windows интересно сравнение инструментов именно под эту платформу, а не gcc, который не понятно под какую.
G>а о самом языке, так что сравнение надо проводить на кодогенераторах одинакового качества.
Ну где же взять OCaml'у кодогенератор хорошего качества? Вот будет, тогда и будем его тестировать. Пока что используется то, что есть. Если бы я ставил целью что-то там смешивать, взял бы не бесплатный mainstream компилятор, а что-нибудь за несколько сотен $.
G>ocamlopt-у для кодогенерации нужен С-шный компилятор, который при сравнении должен быть одинаков, и запускаться с теми же самыми флагами.
Не нужен ему компилятор С. У него свой кодогенератор, отдаёт asm файл ассемблеру.
Именно этот asm файл я и анализировал здесь
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
Здравствуйте, reductor, Вы писали:
R>Здравствуйте, vdimas, Вы писали:
R>>>Не так наглядно и главное — в окамле без всяких лишних библиотек, вспомогательных функций и шаблонов
V>>Ну как же, а partition, а базовые представления списков? Все лишнее у тебя уже есть. Сами агрегаты вставлены в язык. В С/С++ никакие агрегаты в язык не вставлены. Кому надо — вставляет оные из стандартной бибиотеки.
R>Представление списков — это _только_ окамловские типы R>Все очень просто:
R>[code] R>(* список — это всего лишь *) R>type 'a list = Nil | Cons of 'a * 'a list
Вот он!!! (выделенное)
Cons — это агрегат из 'a и a' list. Я его и имел ввиду. В моем примере это cell (почти )
В своем примере я мог объявить так:
struct Cell : pair<int, Cell*>;
Кста, еще один важный момент. В моем примере я использовал сложное предствление списков pair<Cell*, Cell*>, с тем, чтобы сделать время конкатенации константным, иначе описанный qsort будет работать медленнее пузырька
Т.е., OCalm-овский список — это просто ячейка Cons (указатель на оную)? Без хранения указателя на последний элемент???
Здравствуйте, Gaperton,
GN>>Я могу так же утверждать, что оригинальный тест — подтасовка. Выбрали компилятор, который проигрывает OCaml.
G>Почему же, многие люди пользуются gcc, и не считают его таким уж прям плохим.
Это их личное право. Я не говорю, что gcc плохой. Просто для многих задач есть компиляторы лучше.
G>На ряде платформ это вообще единственный компилятор, и ничего. Так что какая такая подтасовка?
G>Ваша подтасовка в том, что вы подменили в утверждении reductor-а "C++" на MSVC. В то время как reductor не уточнял, о каком компиляторе идет речь.
Поэтому я взял привычный для меня.
reductor вообще ничего уточнять не любит, не нужно на меня эти проблемы перекладывать.
G>gcc — вполне себе нормальный компилятор С++. Таки в чем подтасовка в статье?
Тесты делались заинтересоваными людьми.
Мне было совершенно неинтересно, кто победит в моих тестах. Я не фанат С++, но выбрал этот язык исходя из практических его качеств, в которых скорость для меня не последнее место занимает. Победил бы OCaml — кинулся бы его изучать. Какая реклама была! Жалко, что с основами маркетинга не знаком рекламирующий, такое только отталкивает
Поймите, что если человек делает 5 утверждений, и одно из них на поверку оказывается неверным, под сомнение ставятся все остальные.
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
Gaperton wrote: > > Pzz>Это очень спорное утверждение. Например, если скомпилировать > Pzz>криптографический алгоритм rc4, наивно написанный на C без всяких там > Pzz>выкрутасов, то gcc 2.95 с чем-то обогнал MSVC 7.1 в два раза по > Pzz>производительности получившегося кода. > Ой, правда штоли? Что же тогда gear nuke так отмахивается от идеи > использовать такой хороший gcc при сравнениях с окамлом? А, понял — > тогда у нас окамл самый быстрый в мире язык получится. . > > А вообще — из того, что один компилятор на одной маленькой проге кого-то > там обогнал — не следует ничего ровным счетом. Подумаешь, gcc на > маленькой программе за счет unrolling-а короткого цикла (единственный > фокус, который может ему помочь) смог чутка выбится вперед. Глупости.
Скорее, в том случае gcc больше повезло с аллокацией регистров. Для
нормальной реализации rc4 на x86 регистров чуть-чуть не хватает.
Вообще, все современные компиляторы в чем-то будут лучше других, в
чем-то будут хуже. Утверждать, что один из них кардинально лучше другого
в плане кодогенерации было бы наивно.
А вот чем MSVC точно плох по сравнению со многими другими компиляторами,
так это отсутствием нормальной поддержки современных стандартов C/C++.
Про C99 в мелкософте, похоже, вообще пока не слышали...
Здравствуйте, vdimas, Вы писали:
R>>Представление списков — это _только_ окамловские типы :) R>>Все очень просто:
R>>
R>>(* список - это всего лишь *)
R>>type 'a list = Nil | Cons of 'a * 'a list
V>Вот он!!! (выделенное)
V>Cons — это агрегат из 'a и a' list. Я его и имел ввиду. В моем примере это cell (почти :) )
V>В своем примере я мог объявить так: V>struct Cell : pair<int, Cell*>;
Cons — это в данном случае _конструктор_ тупла 'a * 'a list
ничего магического в слове нет
можно написать:
type 'a mylist = Nil | Bush 'a * 'a mylist
(* и сразу: *)
# Bush (1, Bush (2, Nil));;
- : int mylist = Bush (1, Bush (2, Nil))
и _ничего_ не изменится.
Этот код можно запустить и уже работать с этой структурой и матчить ее например так:
let rec qsort = function
| Nil -> Nil
| Bush (x, xs) -> let left,right = partition ((>) x) xs
in concat (qsort left) (Bush (x, qsort right));;
V>Кста, еще один важный момент. В моем примере я использовал сложное предствление списков pair<Cell*, Cell*>, с тем, чтобы сделать время конкатенации константным, иначе описанный qsort будет работать медленнее пузырька :) V>Т.е., OCalm-овский список — это просто ячейка Cons (указатель на оную)? Без хранения указателя на последний элемент???
Поскольку списки, как мы выяснили, специфичны для окамла не больше, чем для C++, то никто не мешает создать тип вида: