Форум: "Прочее";
Текущий архив: 2011.03.20;
Скачать: [xml.tar.bz2];
ВнизВысокий/низкий уровень, ручное/автоматическое управление Найти похожие ветки
← →
DiamondShark © (2010-11-09 21:08) [0]Чтоб не холиварить в тематической, перенесу из
http://delphimaster.net/view/2-1289307984/
DiamondShark © (09.11.10 19:47) [12]
В третьем тысячелетии не имеют права на существование языки без автоматического управления памятью.
----------------------------------------------------------------------
И. Павел © (09.11.10 20:22) [13]
> В третьем тысячелетии не имеют права на существование языки
> без автоматического управления памятью.
Даже assembler?
Или все же только на очень высоком уровне, и если не требуется быстрых вычислений?
----------------------------------------------------------------------
DiamondShark © (09.11.10 20:58) [15]
> И. Павел © (09.11.10 20:22) [13]
> Даже assembler?
Вопрос не имеет смысла: в языке ассемблера отсутствуют сущности, над которыми определены операции создания/уничтожения.
> Или все же только на очень высоком уровне
Человек всегда мыслит только на высоком уровне.
Низкоуровневые языки не для крутости, а от бедности. Когда в 50-х годах прошлого века машинное время было дороже зарплаты программиста, а 100К слов было объёмом памяти суперкомпьютера -- низкий уровень был оправдан.
> и если не требуется быстрых вычислений?
Эффективные алгоритмы человеку легче придумывать на высоком уровне.
А с качественным переводом на машинный язык лучше справляется компьютер. Компилятор с глубокой оптимизацией в общем случае выдаст более быстрый код, чем человек способен вручную написать на ассемблере.
← →
Dimka Maslov © (2010-11-09 21:20) [1]
> Эффективные алгоритмы человеку легче придумывать на высоком
> уровне
В моей практике инженерных расчётов зачастую попадаются модели, требующие нескольких часов машинного времени из-за некачественных алгоритмов, с переводом которых на машинный язык плохо справляется даже компьютер.
> А с качественным переводом на машинный язык лучше справляется
> компьютер. Компилятор с глубокой оптимизацией в общем случае
> выдаст более быстрый код, чем человек способен вручную написать
> на ассемблере
Берём MSVS и пишем динамическую библиотеку, которую компилируем в режиме сверхглубокой оптимизации. Потом дизассеблируем. И видим что? Офигенный по размеру код инициализации при входе в каждую функцию. При большом количестве вызовов функции избавление от этих лишних операций даёт существеннейшую выгоду в скорости работы.
Отсюда вывод: как языки высокого, так и низкого уровня имеют право на существование и каждую конкретную задачу надо разрабатывать на том языке, который даст наибольшую эффективность как в смысле разработки, так и при дальнейшем использовании.
← →
TUser © (2010-11-09 21:42) [2]имхо, сегодня, если алгоритм требует слишком много времени на работу, то принципиальные изменения - в два раза, скажем, - достигаются изменением алгоритма или аппаратного обеспечения, а не средства реализации (языка)
переход на асм, наверное, может ускорить работу на 2% или на 10%, но смена алгоритма или покупка нового железа легко дадут больше
во всяком случае, может ошбаюсь, но большинство даже ресурсоемкого пишется на ЯВУ, а то и даже на интерпретируемых скриптовых языках
конечно, это мир, каким он выглядит с моей маленькой колокольни
← →
Mystic © (2010-11-09 22:08) [3]Для этого надо чтобы все операционные системы поддерживали автоматическое управление памятью. Иначе вся эта концепция помрет в момент входа в режим ядра.
PostMessage(hSomeWnd, WM_DO_SOMETHING, Integer(TObject.Create()), 0);
← →
_Юрий (2010-11-09 22:08) [4]Соглашусь.
проблемы быстродействия чаще всего связаны с явными косяками алгоритма - например выделениями памяти на каждом проходе цикла, лишними вызовами или отсутствием индексирования при поиске.
← →
crux (2010-11-09 22:32) [5]Сразу видно, что люди не знакомы с мощью и мультипарадигменностью C++. Тут вам и смартпоинтеры разнообразные, и Boehm-Demers-Weiser коллектор и ручное управление памятью, что конечно же говорит о том, что С++ и третье тысячелетие переживет.
← →
jack128_ (2010-11-09 22:38) [6]
> имхо, сегодня, если алгоритм требует слишком много времени
> на работу, то принципиальные изменения - в два раза, скажем,
> - достигаются изменением алгоритма или аппаратного обеспечения,
> а не средства реализации (языка)
весьма смелое заявление. языки, они разные бывают. алгоритм в 5 строчек на одном языке, на другом может занять тысячу строк.
← →
TUser © (2010-11-09 22:51) [7]> алгоритм в 5 строчек на одном языке, на другом может занять тысячу строк
Я о скорости работы говорил.
← →
Kerk © (2010-11-09 22:58) [8]
> crux (09.11.10 22:32) [5]
Все-таки сишники часто крайне ограниченные люди. Удивительно даже.
← →
Игорь Шевченко © (2010-11-09 23:03) [9]Между алгоритмом и конкретной его реализацией обычно находится пропасть. Разного размера.
Например, реализация алгоритма анализа текстового файла начинается с загрузки файла в невидимый компонент TMemo, ну а дальше Memo.Lines[I]...
← →
Дмитрий Белькевич (2010-11-09 23:03) [10]Когда машина научится автоматом превращать вот это:
for i := 0 to BuffHigh do
Img.FBuff8[i] := MinMax(0, 255, TempInt - (ShiftMask.FBuff8[i] - ImageSlice.FBuff8[i]) * TempDbl2);
Во что-то такое:
asm
pushad
mov eax, TempInt
movd mm0, eax
punpcklwd mm0, mm0
punpcklwd mm0, mm0
mov eax, TempDbl2
movd mm1, eax
punpcklwd mm1, mm1
punpcklwd mm1, mm1
mov ecx, BuffHigh
and ecx, $fffffffC
mov esi, p1
mov esi, [esi]
mov edi, p2
mov edi, [edi]
mov ebp, p3
mov ebp, [ebp]
pxor mm4, mm4
@@cycle:
movd mm3, [ebp + ecx]
movd mm2, [esi + ecx]
punpcklbw mm2, mm4
punpcklbw mm3, mm4
psubw mm2, mm3
pmullw mm2, mm1
movq mm3, mm0
psubw mm3, mm2
packuswb mm3, mm3
movd [edi + ecx], mm3
sub ecx, 4
jnz @@cycle
emms
popad
end;
Тогда я скажу, что ассемблер не нужен. А раньше - увы...
p.s. оно там чуть-чуть (на BuffHigh mod 4) недосчитывается, знаю.
← →
Юрий Зотов © (2010-11-09 23:07) [11]> В третьем тысячелетии не имеют права на существование языки
> без автоматического управления памятью.
И это высказывание априори ошибочно в силу своей категоричности.
← →
crux (2010-11-09 23:17) [12]Kerk © (09.11.10 22:58) [8]
Таково обыкновенно мнение паскалистов, всей силы C++ не ведающих, ибо коли ведали бы славу Его и благодать, поклонялся бы оракулам Дельфийским да Оберонам эльфийским? [Ст. АРМ 54:12]
Юрий Зотов © (09.11.10 23:07) [11]
Вот же воистину просветленный человек.
← →
Kerk © (2010-11-09 23:36) [13]
> crux (09.11.10 23:17) [12]
Начни с осознания того, что эта ветка вообще не про какой-то конкретный язык программирования.
← →
crux (2010-11-09 23:50) [14]Kerk © (09.11.10 23:36) [13]
Ну так еще не вечер, всегда можем сделать.
Я тут вот просто игриво намекаю на некоторые особенности языка без автоматического управления памятью.
А что до третьего тысячелетия, то откуда мы знаем, что тогда будет? Соханится ли гонка Потребности ПО/Возможности аппаратного обеспечения? Потребности программного обеспечения бесконечно велики, а возможности аппаратного обеспечения априори конечны, поэтому потребность в оптимизации никогда не исчезнет? Выглядит довольно правдоподобным утверждением, если заходить издалека. Доказательство? Опровержение конкретным примером? Кто возьмется?
← →
Kerk © (2010-11-09 23:54) [15]Вообще, я не знаю, как там будет в третьем тысячелетии, но в ближайшие 10-15 лет назревает ренессанс функциональных языков. Мне так кажется, по крайней мере. А их без сборщика мусора сложно себе представить.
← →
Германн © (2010-11-09 23:57) [16]
> А их без сборщика мусора сложно себе представить.
Равно как и без "дворников". :)
← →
crux (2010-11-10 00:00) [17]Kerk © (09.11.10 23:54) [15]
Ну если с функциями как объектами первого класса, то да, действительно сложно. Но сами принципы функциональщины вроде ссылочной прозрачности, отсутствия побочных эффектов, каррингов и сверток вполне реализуемы (и уже реализованы на том же С++, см. Boost library), просто синтаксис будет немного нетрадиционный. Не следует также забывать про подсчет ссылок в лице смартпоинтеров.
← →
Игорь Шевченко © (2010-11-10 00:22) [18]
> Вообще, я не знаю, как там будет в третьем тысячелетии
почему "будет" ?
← →
Kerk © (2010-11-10 00:24) [19]Ну оно только началось и будет довольно длинным :)
← →
Германн © (2010-11-10 01:10) [20]
> Ну оно только началось и будет довольно длинным
А нам постоянно медиа твердит о скором конце света по множеству предсказаний.
← →
RWolf © (2010-11-10 02:06) [21]
> Дмитрий Белькевич (09.11.10 23:03) [10]
а так ли уж сильно эта вставка ускоряет алгоритм? всё равно узким местом остаётся чтение/запись в память.
← →
И. Павел © (2010-11-10 08:21) [22]Никогда не понимал проповедников, едущих в другие места (например, в Новый Свет), чтобы объяснять коренному населению все прелести библии, когда они сами имеют только поверхностное представление о религии коренного населения, а их собственные города погрязают в войнах и коррупции, чему способствует и церковь. Думаю, споры о языках чем то похожи. Так что это все же холивар, а не обсуждение концепций.
А низкий уровень нужен еще и для гибкости. Чем богаче язык высокого уровня, тем больше у него "закос" в определенную сторону. При этом "развернуть" его в другую сторону бывает очень трудно, или невозможно.
Да и автоматическая сборка мусора - не такая уж и сверхполезная штука, чтобы считать ее основным достижением 3 тысячелетия. Опять же, ИМХО, она сделана от бедности. Например, в распоряжении JAVA программы на машине клиента не много ресурсов, и за ними нужно очень тщательно следить.
← →
oxffff © (2010-11-10 08:33) [23]Ничего не понял.
← →
И. Павел © (2010-11-10 08:37) [24]> Ничего не понял.
Я про то, что последнее время очень много посетителей форума пытаются убедить других посетителей в том, что Delphi не имеет права на существование (теперь заявляют об этом в открытую). И заявления такие делают не гуру Delphi. Вот если Анатолий Подгорецкий скажет, что с дельфи пора завязывать, я обеспокоюсь :)
← →
oxffff © (2010-11-10 08:43) [25]Было бы здорово, если бы управление памятью осуществлялось гибридным способом. То есть как я себе это представляю?
Например такая реализация.
Есть два 2 кучи управляемая и не управляемая.
Текущий деструктор или финализатор управляемой сущности так проходит по корням приложения и далее рекурсивно и смотрит какие объекты достижимы по корням. Деструктор/Финализатор смотрит что финализируется по ссылке и делает финализация+деаллокация либо финализация.
Можно оптимизировать разрешив на уровне языка префиксы к корням.
То есть
a:Tobject (принимает только неуправляемые потомки Tobject)
b:managed Tobject
c:uni Tobject ()
Если
a:=a;
a:=b; ошибка. managed and unmanaged ref"s are incompatible
с:=a;
Run time проверки в случае
a:=c;
b:=c;
IMHO.
← →
oxffff © (2010-11-10 08:44) [26]
> И. Павел © (10.11.10 08:37) [24]
Я не понял о чем это ветка. Обо всем и не о чем. :)
← →
oxffff © (2010-11-10 08:46) [27]Вполне возможно что в своем языке YAR я когда-нибудь попробую сделать гибридный способ управления памятью или в одном из потомков.
← →
Думкин © (2010-11-10 08:47) [28]
> про то, что последнее времямерзко хихикает.
← →
12 © (2010-11-10 08:57) [29]В будующем 99%% программистов не будет волновать реализация вообще.
Язык будет описательным.
А как это будет реализовано конкретно - всем будет плевать.
И только 1% Гуру будут знать как и что и поддерживать все это дело.
недавно слушал передачу про наиболее перспективные профессии будующего.
Не услышал "программист"
Какие-то, менеджеры виртуальных пространств - есть. А программиста - нет!
Придурки, кто ж вам будет эти пространства делать и инструменты для менеджерения этих пространств.
А если кто захочет немного другого пространства? Менеджер его сделает, что -ли..
А мобилки умные, стиралки и проч. и проч.
(умный дом, кстати, опять рекламировали по спаму. Это типа с шифоньером Шопенгауэра обсудить, с холодильником в шахматы сыграть?! (знаю-знаю. шучу))
← →
Дмитрий Белькевич (2010-11-10 09:03) [30]
> а так ли уж сильно эта вставка ускоряет алгоритм? всё равно
> узким местом остаётся чтение/запись в память.
Сильно.
← →
Дмитрий Белькевич (2010-11-10 09:05) [31]
> В будующем 99%% программистов не будет волновать реализация
> вообще.
Не будет. Как только будет создан ИИ, он сразу же захватит весь мир. Мы все умрём - нас уже ничего не будет волновать.
← →
12 © (2010-11-10 09:12) [32]
> Не будет. Как только будет создан ИИ,
не стоит утрировать.
Когда ты пишешь from T1 join T2
тебя ж не волнует как там конкретно находится соответствие.
Или применяются ли хеши и какой именно метод сортировки order by
а далее более
надо только абстрагироваться :)
Первым пароходам тоже поначалу парус ставили. Ибо как же так, корабль и без паруса?!
← →
TUser © (2010-11-10 09:21) [33]
> В будующем 99%% программистов не будет волновать реализация вообще
Она и сейчас 99% не волнует. В скриптовых языках и в некоторых компилируемых реализация сокрыта (как устроены хэши в перле или ArrayList в джаве?). Там где не сокрыта - тоже не всякий программист ("программист"?) Делфи ответиит на воросы типа - почему надо вызывать Free, а не Destroy. Хотя исходники открыты и книжки есть.
← →
Дмитрий Белькевич (2010-11-10 09:25) [34]
> надо только абстрагироваться :)
Угу, только потом начинаются такие запросы, что база данных рушится, а у программеров круглые глаза: "оно же компилится"...
И выполняется потом по полчаса на запрос.
← →
Дмитрий Белькевич (2010-11-10 09:29) [35]
> Низкоуровневые языки не для крутости, а от бедности. Когда
> в 50-х годах прошлого века машинное время было дороже зарплаты
> программиста, а 100К слов было объёмом памяти суперкомпьютера
> -- низкий уровень был оправдан.
Если что-то не получается, не трать зря силы, возьми кувалду побольше. (с) Мерфи.
← →
Дмитрий Белькевич (2010-11-10 09:32) [36]
> тебя ж не волнует
Меня - волнует, если что.
← →
12 © (2010-11-10 09:39) [37]TUser © (10.11.10 09:21) [33]
Дмитрий Белькевич (10.11.10 09:25) [34]
значит, уголь кончился, на парусе идем и машина теперь только мешает :)
А сделают так, что угля будет достаточно всегда - парус будет не нужен.
> только потом начинаются такие запросы
вот. А если оптимизатор (подпиленный Гуру, на мегагигатерагерцном/байтном железе ) поймет, что надо от него,
сам, (стандарт Sql 2135года:) ) правильно построит запрос и в течении всего время эксплуатации на основе статистики наиболее правильно сам индексы наставит - база данных будет жива
> Меня - волнует, если что.
и это хорошо! И необходимо.
Но пока.. и в ближайшие лет 100 тоже, имхо
← →
Anatoly Podgoretsky © (2010-11-10 09:44) [38]> Kerk (10.11.2010 00:24:19) [19]
Апологеты говорят будет коротким.
← →
Anatoly Podgoretsky © (2010-11-10 09:46) [39]> И. Павел (10.11.2010 08:37:24) [24]
А ты взятку дай, что бы я не говорил.
← →
Anatoly Podgoretsky © (2010-11-10 09:49) [40]> TUser (10.11.2010 09:21:33) [33]
Это потому что он на delphimaster.ru не ходит, тут бы ему быстро мозги
прочистили, что на весь остаток жизни будет бояться Destroy
← →
Anatoly Podgoretsky © (2010-11-10 09:51) [41]> Дмитрий Белькевич (10.11.2010 09:25:34) [34]
Это не у программиста круглые глаза, а у базы - ну ничего у вас запросики.
← →
Дмитрий Белькевич (2010-11-10 11:09) [42]
> Это не у программиста круглые глаза, а у базы - ну ничего
> у вас запросики.
Угу, ну и запросы у вас, сказала база данных и упала.
> сам, (стандарт Sql 2135года:) ) правильно построит запрос
> и в течении всего время эксплуатации на основе статистики
> наиболее правильно сам индексы наставит - база данных будет
> жива
Что мешает это сделать прямо сегодня? Что принципиально изменится через много лет?
← →
DiamondShark © (2010-11-10 11:14) [43]
> Берём MSVS и пишем динамическую библиотеку, которую компилируем
> в режиме сверхглубокой оптимизации. Потом дизассеблируем.
> И видим что? Офигенный по размеру код инициализации при
> входе в каждую функцию. При большом количестве вызовов функции
> избавление от этих лишних операций даёт существеннейшую
> выгоду в скорости работы.
"А она взяла селёдку и начала ейной мордой мене в харю тыкать".
Зачем вы мне микрософтовскими сями в харю тыкаете? Си над ассемблером выше уровнем чуть более, чем совсем никак.
И что за странное извращение оптимизировать библиотеку, в которой функции слабо связаны друг с другом, а контекст использования вообще не доступен оптимизатору?
Ручная оптимизация прологов функций? Ну, давайте прикинем, сколько на этом можно поиметь профита. Какое у вас там отношение объёма пролога к объёму тела? Один к десяти? Ну так это позорище, а не функция, она вообще инлайниться должна. Вот только из ДЛЛ функцию фиг заинлайнишь, потому что в ДЛЛ утеряна высокоуровневая информация о границах функций. Точки входа есть, а границ нету. Вообще, внутренний код ДЛЛ может быть перемешан как спагетти. Привет от Ассемблера, ага.
Какая же это, к свиням собачим, глубокая оптимизация, если возможность оптимизации В КОНТЕКСТЕ ИСПОЛЬЗОВАНИЯ утеряна безвозвратно?
Вернёмся к нашим прологам. В лучшем случае мы получаем 10% выигрыш ценой утери возможности более шлубокой оптимизации. Но если функции посерьёзнее, чем сотня машинных команд, то выигрыш от ручного опиливания напильником составит от процента до чуть менее, чем нифига.
Стоит оно того? Да ни разу!
Как бы оно могло быть при настоящем высокоуровневом подходе?
Модули представлены не в машинном коде, а в промежуточном представлении. Причём, это не байт-код какой-нибудь, а именно высокоуровневое представление графа алгоритма, с сохранением всей метаинформации, свйственной ЯВУ. Что-нибудь вроде такого:
http://moldovacc.md/acoulichev/th10497.pdf
(обратите внимание на год публикации).
Можно выбирать стратегию кодогенерации. Либо быстро сгенерировать код для быстрого старта приложения, либо глубоко оптимизировать в контексте связей. Можно профилировать на лету или в фоновом режиме, последовательно дооптимизируя критичные куски. Можно сгенерировать и закешировать пребилд нативного оптимизированного кода, опять же в контексте связей и зависимостей.
Вот что такое высокий уровень. А мне тут сями тычут. Си, кстати, разрабатывались в расчёте на то, что из языка будет получаться приемлемого качества машкод БЕЗ ОПТИМИЗАЦИИ, и под одну конкретную систему команд -- PDP. Потому что машинки слабые были. Си -- бай дизайн язык неоптимизируемый, язык, который не смотря на свой примитивизм, снабжён излишествами, призванными ЗАСТАВИТЬ программиста маньячить с мозголомными конструкциями, для ручного запиливания программы в эффективный машкод.
← →
DiamondShark © (2010-11-10 11:20) [44]
> crux (09.11.10 23:50) [14]
> Я тут вот просто игриво намекаю на некоторые
> особенности языка без автоматического управления памятью.
Особенностью языка без автоматического управления памятью является необходимость создания over 9000 костылей, что нам и демонстрирует зоопарк наркоманских библиотек под некоторые особенные языки. В которых одного только стринга можно насчитать десатка полтора реализаций. При том, что без танцев с бубном ни одной нельзя пользоваться.
← →
Дмитрий Белькевич (2010-11-10 11:28) [45]Начинать, как уже говорили, нужно с операционки.
Иначе все эти идеи выльются в очередную недооперационку-песочницу, типа жавы или дотнета.
← →
DiamondShark © (2010-11-10 11:37) [46]
> А низкий уровень нужен еще и для гибкости. Чем богаче язык
> высокого уровня, тем больше у него "закос" в определенную
> сторону. При этом "развернуть" его в другую сторону бывает
> очень трудно, или невозможно.
Это утверждение опровергается фактом существования систем программного обеспечения полного профиля (от бутлоадеара до прикладных сервисов), созданных с нуля и целиком на управляемых языках высокого уровня.
См. Проект "Lilith", Oberon System, Bluebottle, Active Oberon System
Вот что такое высокий уровень и гибкость.
http://www.rol.ru/news/it/press/cwm/19_98/pdp.htm
И на года, блин, смотрим! А то, блин, Жаба, блин, с дотнетом, блин, достижения...
← →
DiamondShark © (2010-11-10 11:42) [47]
> Дмитрий Белькевич (10.11.10 11:28) [45]
> Начинать, как уже говорили, нужно с операционки.
Всё значительно хуже. Начинать нужно с архитектуры.
http://www.rol.ru/news/it/press/cwm/19_98/pdp.htm
Одной из главных проблем неэффективной работы аппаратуры является разрыв между языком программирования и системой команд процессора. Именно это несоответствие и усиливало неприязнь Вирта к существовавшим архитектурам компьютеров, которые отравляли жизнь разработчикам компиляторов. Впечатления от увиденного в Xerox PARC не давали ему покоя. Вирта целиком захватила идея разработать и построить с нуля собственную компьютерную систему, которая состояла бы из аппаратной части, микрокода, компилятора, операционной системы и различных сервисных программ. Фундаментом ее должен был стать новый язык, который мог бы в максимальной степени задействовать возможности будущей станции. Этот язык должен быть компактным и в то же время универсальным, способным одинаково хорошо решать задачи и системного, и прикладного программирования.
Впрочем, начинать уже не нужно. Начало было в 1970-х (!).
Надо просто вытрясти из башки маркетоложескую хрень.
← →
Дмитрий Белькевич (2010-11-10 11:47) [48]
> а так ли уж сильно эта вставка ускоряет алгоритм? всё равно
> узким местом остаётся чтение/запись в память.
Померял - ровно в 4 раза, как и обещано. Да я когда реализацию писал, то видно было, что называется, невооруженным глазом, что разница существенная. Фпс сильно выше (я просто некоторое время в q3 резался, "фпсы" вижу с первых кадров :)).
← →
Дмитрий Белькевич (2010-11-10 11:49) [49]
> Всё значительно хуже. Начинать нужно с архитектуры.
Согласен. Но - мы же живём в реальном мире. Что уже сейчас сделаешь...
← →
RWolf © (2010-11-10 11:59) [50]
> Дмитрий Белькевич (10.11.10 11:47) [48]
вызов функции MinMax даёт большой оверхед.
← →
Дмитрий Белькевич (2010-11-10 12:07) [51]
> вызов функции MinMax даёт большой оверхед.
Извиняюсь, я не эту конкретно функцию мерял. Две реализации существует. Вторая - для 16-ти бит, там MinMax нету:
for i := 0 to BuffHigh do
Img.FBuff16[i] := word(TempInt - ((ShiftMask.FBuff16[i] - ImageSlice.FBuff16[i]) * TempDbl2));
← →
Дмитрий Белькевич (2010-11-10 12:12) [52]Эти куски существуют как раз для "досчёта" BuffHigh mod 4 и BuffHigh mod 8 для 8-ми и 16-ти битных данных. Лень было на ассемблере делать. Как раз тот случай - когда больше возни, чем выигрыша.
← →
Дмитрий Белькевич (2010-11-10 12:13) [53]То есть - в жизни там for i := 0 to BuffHigh mod 4 do и for i := 0 to BuffHigh mod 8 do. Мерялось, конечно, без mod"а для чистоты эксперимента.
← →
crux (2010-11-10 12:14) [54]DiamondShark © (10.11.10 11:20) [44]
>что нам и демонстрирует зоопарк наркоманских библиотек под некоторые особенные языки
Ну а некоторые не очень особенные языки просто не позволяют создавать такие библиотеки, даже наркоманские, поэтому приходится им довольствоваться, чем Создатель послал, в очередной раз применяя TStringList из преисподней для разбиения строк на токены и COM интерфейсы для подсчета ссылок.
DiamondShark © (10.11.10 11:37) [46]
>и целиком на управляемых языках высокого уровня.
Тут дело ведь в чем? Как известно, создание системы, автоматизирующей какую-нибудь деятельность - это тоже определенного рода деятельность. И средство разработки (язык), которое позволяет автоматизировать разработку оказывается в более выигрышном положении, нежели чем то, которое не позволяет. И все поделия Вирта - это очень консервативный слепок трендов индустрии на момент их создания. А индустрия уходит вперед, утыкается в размер транзисторов и извивается в новых корчах. И средству остается либо почить в бозе, либо постоянно развиваться, как, например .NET, либо изначально содержать в себе возможности для развития, как некоторые особенные языки. Поэтому, все то, что делал Вирт - это очень нишево, и далеко ему не улететь, ясно с самого начала.
← →
RWolf © (2010-11-10 12:15) [55]
> [51]
тогда странновато видеть 4-кратное ускорение; разве что если данные уже в кэше.
← →
euru © (2010-11-10 12:21) [56]
> Дмитрий Белькевич (09.11.10 23:03) [10]
> Когда машина научится автоматом превращать вот это:
> . . .
> Тогда я скажу, что ассемблер не нужен. А раньше - увы...
Код, содержащий ассемблерную вставку, невозможно будет скомпилировать для процессоров, которые не имеют хотя бы одну из используемых во вставке команд.
Код, содержащий ассемблерную вставку, не гарантирует наиболее эффективное выполнение для любого процессора, имеющего в своём наборе команд используемые во вставке команды (в том числе и для того процессора, для которого производилась эта оптимизация).
← →
Дмитрий Белькевич (2010-11-10 12:30) [57]
> тогда странновато видеть 4-кратное ускорение; разве что
> если данные уже в кэше.
BuffHigh - около 1 млн. То есть - там обсчитываются две 16-ти битные картинки объёмом по 2 мб, наружу отдаётся одна - объёмом 1 мб. Я не уверен, что это всё влазит в кэш.
← →
Дмитрий Белькевич (2010-11-10 12:31) [58]
> Код, содержащий ассемблерную вставку, невозможно будет скомпилировать
> для процессоров, которые не имеют хотя бы одну из используемых
> во вставке команд.
Но софт-то как-то нужно писать и продавать, не?
← →
Дмитрий Белькевич (2010-11-10 12:31) [59]>наружу отдаётся одна - объёмом 1 мб
Читать:
наружу отдаётся одна - объёмом 2 мб
← →
Дмитрий Белькевич (2010-11-10 12:37) [60]
> Код, содержащий ассемблерную вставку, невозможно будет скомпилировать
> для процессоров, которые не имеют хотя бы одну из используемых
> во вставке команд.
Или ты думаешь, что завтра кто-то начнёт делать процессора, частично несовмстимые с интелом? Так никто не купит. Ну сделал Intel IA 64, много они их продали? И это - "целый" Интел!
← →
DiamondShark © (2010-11-10 12:39) [61]
> crux (10.11.10 12:14) [54]
Вы извините, конечно, но этот зомбический поток сознания даже как-то комментировать неудобно.
Какие языки не позволяют создавать библиотеки? Модула не позволяет библиотеки создавать? Оберон? Жаба с шарпами не позволяют библиотеки создавать? Лисп с хаскелем не позволяют библиотеки создавать?
Какие "такие" библиотеки они не позволяют создать? Очередную стопицотую реализацию смартпоинтера, что-ли? А нафига собаке пятая нога?
В какой перёд ушла "индустрия" от Вирта, если только в 1995 (Жаба) и 2000 (нет) появились "индустриальные" воплощения отработанного в 60-70х (P-код, типобезопасные языки и менеджед-среда исполнения)?
Чего "нишево" в полном цикле разработки от ядра и драйверов до окошечек с прозрачностью и полного комплекта прикладных сервисов?
Чего вы бредите? Третий том страусного трупа на голову упал? Или корпоративных флэш-роликов обсмотрелись? Ну так приложите холодное, поспите.
← →
Дмитрий Белькевич (2010-11-10 12:41) [62]Ну вот сделали. Всё круто. И где они сейчас?
"Эта архитектура, известная под названием Intel Architecture-64 (IA-64), полностью "порывает с прошлым". IA-64 не является как 64-разрядным расширением 32-разрядной архитектуры х86 компании Intel, так и переработкой 64-разрядной архитектуры PA-RISC компании HP. IA-64 представляет собой нечто абсолютно новое - передовую архитектуру, использующую длинные слова команд (long instruction words -- LIW), предикаты команд (instruction predication), устранение ветвлений (branch elimination), предварительную загрузку данных (speculative loading) и другие ухищрения для того, чтобы "извлечь больше параллелизма" из кода программ."
Увы - мы живём в реальном мире. И от витела, в текущем виде, фантастически сложно уйти. Даже самому винтелу.
← →
euru © (2010-11-10 12:43) [63]
> DiamondShark © (10.11.10 11:14) [43]
> Модули представлены не в машинном коде, а в промежуточном
> представлении. Причём, это не байт-код какой-нибудь, а именно
> высокоуровневое представление графа алгоритма, с сохранением
> всей метаинформации, свйственной ЯВУ.
Смахивает на .NET. Или нет?
← →
DiamondShark © (2010-11-10 12:45) [64]
> Или ты думаешь, что завтра кто-то начнёт делать процессора,
> частично несовмстимые с интелом? Так никто не купит.
Я вам открою страшную тайну: процессоров, "несовместимых с интелом", выпускается и продаётся огромное множество. В том числе и самим Интелом.
Вот, кстати, ещё один плюс высокоуровневого подхода: смена процессора сугубо до фонаря.
← →
DiamondShark © (2010-11-10 12:47) [65]
> Смахивает на .NET. Или нет?
Угу. Только на 15 лет раньше.
← →
Дмитрий Белькевич (2010-11-10 12:51) [66]
> Я вам открою страшную тайну: процессоров, "несовместимых
> с интелом", выпускается и продаётся огромное множество.
> В том числе и самим Интелом.
Вообще, я, по одной из специальностей, инженер-электронщик. Я как бы в курсе :) Что для чайников и утюгов и прочих свистоперделок выпускается множество всякого.
Мы же говорим про персоналки? Или нет? Даже эппл (из массового) - и тот не выдержал - на ител перешёл.
← →
DiamondShark © (2010-11-10 12:53) [67]
> и другие ухищрения для того, чтобы "извлечь больше параллелизма"
> из кода программ."
Вместо логичного решения рассматривать архитектуру и программирование как единую систему.
Это ж Вирт, семидесяты год... FFFUUUUUU!!!!!!!!
"Фигли думать! Трясти надо!"
← →
Дмитрий Белькевич (2010-11-10 12:54) [68]
> Угу. Только на 15 лет раньше.
Ну так всё не на ровном месте сделано. Многие алгоритмы и концепции придуманы были еще тогда, когда эвм (в современном виде) еще не было.
← →
crux (2010-11-10 12:56) [69]DiamondShark © (10.11.10 12:39) [61]
>Какие языки не позволяют создавать библиотеки?
Вы, видимо, не понимаете, о чем речь. Как вы объясните, например то, что в Delphi, к примеру, нельзя создать тип делегата, который может делегировать и обычную функцию, и метод, и результат биндинга функцией bind, а в C++, например, можно, и при этом, при дизайне языка никто о таком вообще не помышлял?
>А нафига собаке пятая нога?
Я же рассказал зачем - для автоматизации процесса разработки, пожалуйста, читайте внимательнее.
>В какой перёд ушла "индустрия" от Вирта
Ну, например, software transaction memory, встроенный параллелизм, актеры, агенты, предпосылок для чего не было и уже не будет в его наследии, хотя в более гибких универсальных язхыках это появится или уже появилось.
>Чего "нишево" в полном цикле разработки от ядра и драйверов до окошечек с прозрачностью и полного комплекта прикладных сервисов?
Как раз в разработке полного комплекта прикладных сервисов и. Создавать еще раз, что успешно было создано и отработано уже в нескольких реализациях? Java не маялась такой маятой (хотя, маялась, но вовремя поняла, что не стоит) и таким образом выжила.
>Чего вы бредите?
Я несу светлый завет свободы от оков просвещенного консерватизма.
← →
DiamondShark © (2010-11-10 13:00) [70]
> Мы же говорим про персоналки?
Рабочих станций на том же ARM -- уже есть немало. И вроде бы собирается быть ещё больше.
Если в какой-нибудь Windows-2015 мелкомягкие решат совсем отказаться от поддержки х86, то эта рахитектура сдохнет за год.
> Даже эппл (из массового) - и тот не выдержал - на ител
> перешёл.
Эппл ваще не показатель. Вот ващщщще.
← →
Дмитрий Белькевич (2010-11-10 13:01) [71]
> > и другие ухищрения для того, чтобы "извлечь больше параллелизма"
> > из кода программ."
Кстати, в моём случае с mmx"ом, как раз параллелизм даёт такое увеличение. Ну, да я думаю, сами знаете.
← →
Дмитрий Белькевич (2010-11-10 13:04) [72]
> Рабочих станций на том же ARM -- уже есть немало
0.05 процентов? Или уже 0.5?
> Эппл ваще не показатель
Ага, 10% рынка.
> Если в какой-нибудь Windows-2015 мелкомягкие решат совсем
> отказаться от поддержки х86, то эта рахитектура сдохнет
> за год.
Не верно, если в какой-нибудь win 2015 мелкомягкие решат откзаться от поддержки x86, то сдохнут мелкомягкие.
← →
Дмитрий Белькевич (2010-11-10 13:06) [73]Они-то от доса никак отказаться не могут. А ты говоришь - x86. Ну ну.
← →
Anatoly Podgoretsky © (2010-11-10 13:07) [74]> DiamondShark (10.11.2010 13:00:10) [70]
Показатель, после стольких лет издевательства, битья в грудь - взять и
перейти на то, что они называли гадостью.
← →
Игорь Шевченко © (2010-11-10 13:11) [75]12 © (10.11.10 08:57) [29]
> В будующем 99%% программистов не будет волновать реализация
> вообще.
а грамотность уже сейчас не волнует
← →
Kerk © (2010-11-10 13:12) [76]
> Anatoly Podgoretsky © (10.11.10 13:07) [74]
>
> > DiamondShark (10.11.2010 13:00:10) [70]
>
> Показатель, после стольких лет издевательства, битья в грудь
> - взять и перейти на то, что они называли гадостью.
Они по команде Джобса что угодно будут любить и что угодно гадостью называть :)
← →
DiamondShark © (2010-11-10 13:16) [77]
> Anatoly Podgoretsky © (10.11.10 13:07) [74]
А-а... Ну разве что в таком аспекте ;)
← →
Sapersky (2010-11-10 13:17) [78]Дмитрий Белькевич (10.11.10 12:07) [51]
Подозреваю, что 4 раза - это "привет" от дельфийского компилятора.
Лень проверять, но там наверняка неоптимальное распределение переменных по регистрам, не соображает делать инкремент указателей и т.д.
Я учился оптимизировать в основном по FastLib, которая примечательна как раз весьма скромным использованием ассемблера, но при этом все паскалевские функции написаны в "ассемблерном" стиле, так, чтобы даже у самого, гхм, альтернативно одарённого компилятора не было возможности тупить. При этом паскалевский код всё же остаётся компактнее и читабельнее asm-a.
Говорят, что сишные компиляторы попродвинутее, в том числе и SIMD умеют применять. Intel C++ хвалят, например, хотя сам не пробовал.
Понятно, что для компиляции в SIMD нужно писать в том самом "ассемблерном" стиле, причём ещё более суровом из-за негибкости SIMD. Однако это всё-таки прогресс (теоретически) по сравнению с компилятором Дельфи, который нужно пинать, чтобы он обычный asm использовал мало-мальски прилично.
Хотя, конечно, против перехода на Си есть два существенных аргумента - Лень и Привычка :)
← →
DiamondShark © (2010-11-10 13:18) [79]
> Дмитрий Белькевич (10.11.10 13:04) [72]
Я точных процентов не знаю, но движуха есть.
← →
Дмитрий Белькевич (2010-11-10 13:26) [80]
> Подозреваю, что 4 раза - это "привет" от дельфийского компилятора.
Ну, как говориться, за что купил...
> Говорят, что сишные компиляторы попродвинутее, в том числе
> и SIMD умеют применять.
Умеют, но их нужно вот так же - хитро описывать. Векторы и прочие навороты. Вот так - что бы взять, прямо из цикла, и сконвертить в simd - пока не видел.
> Понятно, что для компиляции в SIMD нужно писать в том самом
> "ассемблерном" стиле, причём ещё более суровом из-за негибкости
> SIMD.
Ага, так и есть.
> Я точных процентов не знаю
А вот зря. Нет полноты картины.
> Хотя, конечно, против перехода на Си есть два существенных
> аргумента - Лень и Привычка :)
Да меня как-то и BASM не напрягает... Зачем еще C изучать, всё равно я на нём никогда не буду. Сильно нужно - найму кого. Что, бывает, и делаю.
← →
Игорь Шевченко © (2010-11-10 13:27) [81]Sapersky (10.11.10 13:17) [78]
> Лень проверять, но там наверняка неоптимальное распределение
> переменных по регистрам, не соображает делать инкремент
> указателей
А ты проверь. Команда View|Debug Windows|CPU доступна в любой версии. Глядишь, пургу не будешь нести.
← →
Дмитрий Белькевич (2010-11-10 13:32) [82]
> > переменных по регистрам, не соображает делать инкремент
> > указателей
Посмотрел - делает. Грамотный компилятор. Так что, думаю, что таки процессор не поспевает, как ни удивительно.
← →
Дмитрий Белькевич (2010-11-10 13:34) [83]В смысле - инкремент указателей делает, всех трёх сразу: inc esi, здесь всё исто.
← →
DiamondShark © (2010-11-10 13:35) [84]
> crux (10.11.10 12:56) [69]
> а в C++, например, можно, и при этом, при дизайне
> языка никто о таком вообще не помышлял?
Я ведь не против C++.
Знаете, как работают биотехнологические станции? Берут какие-нибудь линии организмов, поливают их мутагенами или облучают гамма-излучением, и смотрят что получилось. Потом составляют библиотеки признаков. Вам понадобилась для нового сорта длинная нога? Пожалуйте, вот линия, несколько скрещиваний и получите нужный признак в чистой линии.
Вот и плюсанутое сообщество -- это этакое радиоактивное болотце, где плодятся и скрещиваются мутанты. Иногда туда можно пипеточкой -- чпок! -- и подцепить чего-нибудь забавное. Потом, конечно, потребуется кропотливая лабораторная работа по выделению интересного фрагмента в чистом виде. Но это уже дело техники.
> Ну, например, software transaction memory, встроенный параллелизм,
> актеры, агенты, предпосылок для чего не было и уже не будет
> в его наследии, хотя в более гибких универсальных язхыках
> это появится или уже появилось.
Я так понял, что с историей программирования до 1990 года вы не знакомы.
> >Чего "нишево"
>Как раз в разработке полного комплекта
Вы со своими сями и русский-то скоро забудете.
"Нишевое" -- это значит "в узко-специальной области".
> Я несу светлый завет
А, не... С религией не связываюсь.
← →
DiamondShark © (2010-11-10 13:37) [85]
> Дмитрий Белькевич (10.11.10 13:26) [80]
> А вот зря. Нет полноты картины.
Мне аж самому интересно стало. Буду копать.
← →
Anatoly Podgoretsky © (2010-11-10 13:53) [86]> Kerk (10.11.2010 13:12:16) [76]
Я знаю что - Power PC
← →
Anatoly Podgoretsky © (2010-11-10 13:55) [87]> Sapersky (10.11.2010 13:17:18) [78]
Хорошо там, где нас нет.
← →
RWolf © (2010-11-10 13:56) [88]
> Sapersky (10.11.10 13:17) [78]
> Подозреваю, что 4 раза - это "привет" от дельфийского компилятора.
так и есть — в приведённом коде умножение скомпилируется в вызов функции _llmul (если я правильно понял, и tempdbl2 — это dword).
← →
crux (2010-11-10 13:58) [89]DiamondShark © (10.11.10 13:35) [84]
>Я так понял, что с историей программирования до 1990 года вы не знакомы.
Ну как же. Думаете про Вирта я от вас узнал? Я и блюботл как-то даже устанавливал. Очень скучно. Только консерваторы из 80-х годов будут в нем разрабатывать приложения.
>"Нишевое" -- это значит "в узко-специальной области".
Ну я это как раз и имел в виду. Где же ваш хваленый Оберон-то? На вертолетах скорость винтов регулирует?
← →
Anatoly Podgoretsky © (2010-11-10 14:11) [90]> DiamondShark (10.11.2010 13:35:24) [84]
Так С++ это мутанты?
← →
Anatoly Podgoretsky © (2010-11-10 14:13) [91]> crux (10.11.2010 13:58:29) [89]
Вирт талантливый ученый, но отвратительный коммерсант, даже не понятно как
это с Паскалем получилось, но явно не благодаря ему.
← →
Дмитрий Белькевич (2010-11-10 14:20) [92]
> если я правильно понял, и tempdbl2 — это dword
Название tempdbl2 - пережитки прошлого. Нужно было переименовать, да:
TempDbl2, TempInt: integer;
Тем не менее, imul есть.
← →
euru © (2010-11-10 14:25) [93]
> Дмитрий Белькевич (10.11.10 13:01) [71]
> Кстати, в моём случае с mmx"ом, как раз параллелизм даёт
> такое увеличение. Ну, да я думаю, сами знаете.
Кстати, современные процессоры Intel содержат несколько ядер. Если посмотреть на код, написанный на ЯВУ, то видно, что теоретически ничто не мешает распараллелить его на несколько ядер. Такая возможность предусмотрена в ассемблерной вставке?
← →
Дмитрий Белькевич (2010-11-10 14:31) [94]
> Такая возможность предусмотрена в ассемблерной вставке?
Нет.
← →
RWolf © (2010-11-10 14:33) [95]
> Дмитрий Белькевич (10.11.10 14:20) [92]
на моей машине (атлон 3000+ 2 ГГц) дельфовая и ассемблерная версии показывают 25 млн и 11 млн тактов соответственно.
← →
Дмитрий Белькевич (2010-11-10 14:37) [96]У меня на буке, Intel Core 2 Duo T9400, разница - ровно 4 раза. Тестовую обвязку прибил, если нужно - опять сделаю.
← →
RWolf © (2010-11-10 14:37) [97]
> RWolf © (10.11.10 14:33) [95]
правда, тестировал 4-Мбайт массивы.
← →
Дмитрий Белькевич (2010-11-10 14:38) [98]Кстати, посмотрел - не исключено, что таки в кэш влазит:
6 MБ кэш-памяти, тактовая частота 2,53 Ггц.
← →
Дмитрий Белькевич (2010-11-10 14:42) [99]Можете для 16 бит попробовать:
asm
pushad
mov eax, TempInt
movd mm0, eax
punpcklwd mm0, mm0
punpcklwd mm0, mm0
mov eax, TempDbl2
movd mm1, eax
punpcklwd mm1, mm1
punpcklwd mm1, mm1
mov ecx, BuffHigh
add ecx,ecx
and ecx, $fffffff8
mov esi, p1
mov esi, [esi]
mov edi, p2
mov edi, [edi]
mov ebp, p3
mov ebp, [ebp]
@@cycle:
movq mm2, [esi + ecx]
psubusw mm2, [ebp + ecx]
pmullw mm2, mm1
movq mm3, mm0
psubusw mm3, mm2
movq [edi + ecx], mm3
sub ecx, 8
jnz @@cycle
emms
popad
end;
for i := 0 to BuffHigh{ mod 8} do
Img.FBuff16[i] := word(TempInt - ((ShiftMask.FBuff16[i] - ImageSlice.FBuff16[i]) * TempDbl2));
← →
Дмитрий Белькевич (2010-11-10 14:49) [100]FBuff16 - array of word
FBuff8 - array of byte
← →
tesseract © (2010-11-10 14:53) [101]
> Если посмотреть на код, написанный на ЯВУ, то видно, что
> теоретически ничто не мешает распараллелить его на несколько
> ядер.
Типа так ? http://ru.wikipedia.org/wiki/Grand_Central_Dispatch
← →
RWolf © (2010-11-10 14:54) [102]
> Дмитрий Белькевич (10.11.10 14:49) [100]
хм, до этого я сравнивал асм из [10] с кодом из [51].
процедуры из [99] работают практически с одинаковой производительностью.
← →
Sapersky (2010-11-10 15:25) [103]FBuff16 - array of word
FBuff8 - array of byte
Ну если вынести всё в отдельную процедуру, работающую с элементарными типами (и передавать массивы как const) - тогда будет оптимально. Именно это я имел в виду под "ассемблерным стилем".
А вот если в точности как в оригинале, с Img, ShiftMask, ImageSlice, да ещё где-то в середине большой функции - тогда компилятор может насочинять странного. Не утверждаю, что обязательно насочиняет - но может.
← →
Дмитрий Белькевич (2010-11-10 15:33) [104]
> Ну если вынести всё в отдельную процедуру, работающую с
> элементарными типами (и передавать массивы как const) -
> тогда будет оптимально.
Угу, есть такое. Еще если обращаться к элементам массива по указателям. Но тогда получается такой pas, что уж лучше asm.
> процедуры из [99] работают практически с одинаковой производительностью.
Чуть позже на другой машине попробую еще - на семпроне 2600.
← →
RWolf © (2010-11-10 15:55) [105]
> Дмитрий Белькевич (10.11.10 15:33) [104]
я замерял время выполнения вот так: http://pastebin.ca/1987203
← →
Дмитрий Белькевич (2010-11-10 16:19) [106]
> я замерял время выполнения вот так: http://pastebin.ca/1987203
Так, на 1000-е циклов:
Коре дуо:
1.89 млрд
4.73 млрд
Семпрон:
10.54 млрд
11.53 млрд.
Таки кэш?
← →
Sapersky (2010-11-10 17:07) [107]Вообще да, CoreDuo / данные влезают в кэш / реализация в виде отдельной функции - разница 3.5 раза.
Хм... ну значит CoreDuo любит MMX больше других... я в своё время тестировал преимущественно P4 и получал обычно около 2-х раз.
Но вариант с MMX немного странный - если mullw лихо отбрасывает старшие разряды от умножения, то что там, в этих word"ах - исключительно байты? Взятие младшего слова - это ведь не clamp (как часто хотелось бы), или я что-то путаю?
← →
Дмитрий Белькевич (2010-11-10 18:35) [108]На реальных картинках вариант с асмом даже лучше, не считая того, что быстрее. Сильно пересвеченные участки удаляются. Они как раз больше мешают.
← →
Дмитрий Белькевич (2010-11-10 18:36) [109]Но, таки да - сравнение не честное. По хорошему - лучше переписать, или с 8-ю битами пробовать.
← →
Дмитрий Белькевич (2010-11-10 18:43) [110]It"s not a bug, it"s a feature :) Как раз тот случай :)
← →
Mystic © (2010-11-10 19:35) [111]
> В будующем 99%% программистов не будет волновать реализация
> вообще.
> Язык будет описательным.
Тут свои грабли, на которые наступаешь тогда, когда что-то перестает работать. Или работает с жуткими тормозами. В этом случае необходимо восстановить реализацию, которая сокрыта в недрах.
Причем, ощущение, что это уже проходили. В одной книжке я читал, что с появлением языка SQL программисты перестали быть нужны, ибо любой бухгалтер сможет набрать текст запроса на понятном английском языке и получить нужный ему результат :)
Лично мне проще написать что надо делать и в какой последовательности, чем устранять "непонимание", когда я думаю одно, а меня поняли совсем по другому. Ибо это проще.
← →
_oxffff (2010-11-10 19:40) [112]А есть что по делу?
← →
Anatoly Podgoretsky © (2010-11-10 19:42) [113]> Mystic (10.11.2010 19:35:51) [111]
Были такие фантазии у ИБМ, а кончилось тем, что появилась новая профессия, в
переводе SQL Запросчик.
← →
DiamondShark © (2010-11-10 20:00) [114]А вот ещё такое соображение, навеяное соседней веткой.
Грядёт эра дешёвых параллельных архитектур. Уже сейчас четырёхядерные процессоры пихают куда попало, а двухъядерные считаются чуть ли не бюджетным решением, на серверах так уже давно количество камней ограничено лишь санитарными нормами по шуму.
В связи с этим встаёт вопрос о программной поддержке всей этой красоты.
Как тут уже упоминали, некоторые производители пытаются "извлечь больше параллелизма из кода программ", изобретая всякие штучки на уровне процессора. Но, очевидно, что это паллиатив.
Требуется разработка исполняющих сред и языков, реализующих легковесный и автоматический параллелизм. Вот тут-то низкому уровню и ручному управлению памятью окончательный и бесповоротный северный зверёк.
← →
RWolf © (2010-11-10 20:26) [115]
> Дмитрий Белькевич (10.11.10 16:19) [106]
запустил на домашнем Core2Duo E6300 (2 MB L2 cache); ассемблерная процедура выполняется за ~3,7 млн. тактов, дельфовая — за ~4,8 млн.
← →
Mystic © (2010-11-10 20:26) [116]> DiamondShark © (10.11.10 20:00) [114]
Ты рассуждаешь в общем, без конкретной привязки к задачам. Лично для меня более предпочтительны те системы, где о параллелизме думали с самого начала. В отличие от систем, где понадеялись на автоматические средства. Пока что доверия им нету большого, хотя бы потому, что я плохо понимаю, как это будет работать. Скажем так, возможность модифицировать переменные для меня важнее автоматического параллелизма.
Если брать шахматы, то я абсолютно не понимаю, как там можно прикрутить автоматическое управление памятью и автоматический параллелизм. По первому пункту в требованиях задачи обычно стоит возможность настройки максимального размера памяти, которые движок может использовать движок. Иначе он просто сожрет все. Так что все равно, как только хэш позиций заполняется, надо думать о том, какие позиции неактуальны и должны быть удалены из него. Второй пункт входит в противоречие со всякими эвристиками типа "ходов-киллеров" и т. д. и т. п., что подразумевает изменяемые глобальные переменные.
← →
Pavia © (2010-11-10 20:31) [117]
> Требуется разработка исполняющих сред и языков, реализующих
> легковесный и автоматический параллелизм. Вот тут-то низкому
> уровню и ручному управлению памятью окончательный и бесповоротный
> северный зверёк.
Да вы просто Cuda с OpenCl не видели. Там тот же самый низкий уровень. Код надо писать для векторных данных как SSE. А параллелизмом управлять. На видео картах тежи самые проблемы с кэшем что и на проще. Главное задействовать быструю память.
Тот же Visual С++ умеет делать код который будет работать на разных ядрах. Но так никто не делают. Все используют OpneMP вставки.
По поводу того что компиляторы C++ хорошо оптимизируют это сказки. ДА лучше чем Delphi но проблемы все тежи. С чего бы в друг им использовать инстриксы или ассемблерные вставки если и так хорошо? А они используются во всех высоко оптимизированных библиотеках.
Вот и все дела инструмент вроде бы есть, а вроде бы его и нет.
← →
_oxffff (2010-11-10 20:45) [118]
> . Вот тут-то низкому уровню и ручному управлению памятью
> окончательный и бесповоротный северный зверёк.
А как связана параллельность языка с управляемой кучей?
← →
DiamondShark © (2010-11-10 21:21) [119]
> Ты рассуждаешь в общем, без конкретной привязки к задачам.
С "конкретной привязкой к задачам" рассуждения обычно строятся следующим образом.
Село Нижние Подмышки, Урюпинский уезд, 1810 год.
- Слышал, Петрович, чяво те агличане выдумали?
- Чяво?
- Берут воду в медный жбан запирають, да на уголья ставють. А пар-то с той воды пускают в чугунную машину.
- А эт зачем?
- А машина та колесо крутит. Хошь -- мельницу цепляй, хошь -- станок на мануфактуре.
- Мельница эвон у нас на запруде стоит. Чево на ей уголье жечь-то?
- А ещё, говорят, машину ту на колёса ставят, так она потом сама едет.
- Эк же она сама поедет? Машина-то чугунная, тяжёлая, да жбан-то, с кипятком-то. Тут пару ломовых запряги -- и то не сдвинешь.
- Дык, машина-то колёса и вертит. От того и едет.
- А каково вода-то остынет?
- Дык, к машине телегу с угольем-то цепляют, то уголье и жгут.
- Хех. Потонет-то машина в наших колдоёбинах-то.
- А её для того по железным брусьям пускают.
- Как так по брусьям?
- Да так. Кладут ровнёшенько брусья, да по тем брусьям она и едет.
- Ну, брат, либо ты про агличан врёшь всё, либо тои агличане все с катушек сбрендили. Того железа не напасёшся, уголья-то накопай, да как жбан-то лопнет, всех-то и поварит. Эх, а с лошадушкой-то нашей нигде не пропадёшь.
← →
DiamondShark © (2010-11-10 22:09) [120]
> Лично для меня более предпочтительны те системы, где о параллелизме
> думали с самого начала. В отличие от систем, где понадеялись
> на автоматические средства.
На самом деле, "думать с самого начала" и "использовать автоматические средства" ни в коем случае не являются взаимосключающими. Скорее, даже наоборот.
> Пока что доверия им нету большого, хотя бы потому, что я
> плохо понимаю, как это будет работать.
Argumentum ad ignoratio. Волшебно.
> Скажем так, возможность модифицировать переменные для меня
> важнее автоматического параллелизма.
Расскажи, как возможность модифицировать переменные препятствует параллелизму?
> Если брать шахматы, то я абсолютно не понимаю, как там можно
> прикрутить автоматическое управление памятью и автоматический
> параллелизм.
Я не спец по шахматным задачам, но там, где используются динамические структуры данных и существуют ветви алгоритма без взаимных влияний, могут и должны применяться автоматическое управление памятью и автоматический параллелизм.
Если в шахматных задачах не используются динамические структуры данных и не существуют ветви алгоритма без взаимных влияний, то да, шахматным задачам пофиг на автоматическое управление памятью и автоматический параллелизм.
> По первому пункту в требованиях задачи обычно стоит возможность
> настройки максимального размера памяти, которые движок может
> использовать движок.
Ну так автоматическое управление памятью не означает, что алгоритм не должен и не может контролировать число создаваемых объектов.
> Так что все равно, как только хэш позиций заполняется, надо
> думать о том, какие позиции неактуальны и должны быть удалены
> из него.
Хочешь верь, хочешь нет, но автоматическое управление памятью этому не мешает нисколько.
> Второй пункт входит в противоречие со всякими эвристиками
> типа "ходов-киллеров" и т. д. и т. п., что подразумевает
> изменяемые глобальные переменные.
Если ветки алгоритма обращаются к глобальным переменным, то они просто не будут признаны инвариантами и будут сериализованы.
> Да вы просто Cuda с OpenCl не видели.
А вы просто параллельных языков не видели.
Да ещё и SIMD c MIMD путаете.
> Тот же Visual С++ умеет делать код который будет работать
> на разных ядрах.
И как это ему удаётся, если ОС такого не поддерживает?
> Все используют OpneMP вставки.
Это не то. OpenMP использует потоки. В лучшем случае -- пул потоков. Потоки слишком тяжёлые. А других средств в ОС нет.
Отвлекитесь от существующих ОС и реализации многопоточности в них. Я говорю не о многозадачности, а о внутреннем параллелизме алгоритмов.
> А как связана параллельность языка с управляемой кучей?
Очень просто связана. Явное управление кучей вносит паразитные зависимости, которые сильно мешают параллельности.
Примитивнейший пример:
a := new(TA);
DoInvariant1(a); // эти ветки
DoInvariant2(a); // выполняются параллельно
dispose(a); // здесь точка синхронизации, но она тут нафиг не нужна
// дальше код, независимый от а
// но он не может выполняться до завершения обоих
// DoInvariant1(a) и DoInvariant2(a)
← →
_oxffff (2010-11-10 22:15) [121]
> Очень просто связана. Явное управление кучей вносит паразитные
> зависимости, которые сильно мешают параллельности.
> Примитивнейший пример:
>
> a := new(TA);
> DoInvariant1(a); // эти ветки
> DoInvariant2(a); // выполняются параллельно
> dispose(a); // здесь точка синхронизации, но она тут нафиг
> не нужна
> // дальше код, независимый от а
> // но он не может выполняться до завершения обоих
> // DoInvariant1(a) и DoInvariant2(a)
Видимо имелось ввиду не dispose и не finalize.
А просто очистка корня
a:=nil?
По сему
1. А подсчет ссылок религия не позволяет?
2. Пометить объект на удаление(поместить в список на удаление), который например разделяется DoInvariant1 и DoInvariant2 и последний закончивший его обрабатывает.
← →
Mystic © (2010-11-10 22:52) [122]
> Расскажи, как возможность модифицировать переменные препятствует
> параллелизму?
Я знаю, что только в функциональных языках а-ля Haskell существует автоматический параллелизм, который и обусловлен этим условим. В этом случае автоматом параллелится вычисление аргументов функций, последовательное выполнение и т. д. и т. п. В случае наличия контеста, типаSelf.Method1();
Self.Method2();
определить, можно ли параллелить вызовы Method1 и Method2 очень тяжело. По крайней мере мне неизвестны системы такого рода.
> Я не спец по шахматным задачам, но там, где используются
> динамические структуры данных и существуют ветви алгоритма
> без взаимных влияний, могут и должны применяться автоматическое
> управление памятью и автоматический параллелизм.
Да, используются динамические структуры данных. Но это тот случай, когда за динамической памятью надо следить, так что от ручного управления никуда. Ветки без взяимных влияний, ну скажем так, такие конфликты можно порешать руками. Самые сильные движки написаны на C/C++ (средней силы иногда встречаются Delphi/Pascal), а все прочие языки нервно курят в сторонке.
← →
DiamondShark © (2010-11-11 10:34) [123]
> Видимо имелось ввиду не dispose и не finalize. А просто
> очистка корняa:=nil?
Нет. Имелось в виду именно явное удаление динамического объекта.
> По сему 1. 2.
Это и есть частные случаи автоматического управления.
← →
oxffff © (2010-11-11 10:36) [124]
> DiamondShark © (11.11.10 10:34) [123]
>
> > Видимо имелось ввиду не dispose и не finalize. А просто
>
> > очистка корняa:=nil?
>
> Нет. Имелось в виду именно явное удаление динамического
> объекта.
Дык и не ставь ее туда и будет счастье. В чем сложность?
← →
oxffff © (2010-11-11 10:48) [125]
> DiamondShark © (11.11.10 10:34) [123]
>
> > Видимо имелось ввиду не dispose и не finalize. А просто
>
> > очистка корняa:=nil?
>
> Нет. Имелось в виду именно явное удаление динамического
> объекта.
А как ты собрался удалить или финализировать(также синхронизируя доступ к членам объекта ) объект в управляемой куче, если на него есть ссылки в DoInvariant1 и в DoInvariant2?
← →
DiamondShark © (2010-11-11 11:29) [126]
> В случае наличия контеста, типа Self.Method1(); Self.Method2();
> определить, можно ли параллелить вызовы Method1 и Method2
> очень тяжело.
Но не невозможно.
Во-первых, автоматический анализ кода вполне возможен. Результат будет хуже, чем в спецязыках, но будет.
Во-вторых, можно ввести декларирование инвариантов, что-то вроде:
class A
int i;
procedure Method1; const; // метод задекларирован как не изменяющий состояние класса
end
procedure A.Method1;
begin
i = 123; // compiller error;
end;
В-третьих, таки да, можно (и нужно) разрабатывать специальные языки.
> Но это тот случай, когда за динамической памятью надо следить,
> так что от ручного управления никуда.
У вас тут причина со следствием попутана.
За динамической памятью надо следить, потому что доступно только ручное управление.
> Ветки без взяимных влияний, ну скажем так, такие конфликты
> можно порешать руками.
Можно, конечно.
Можно, например, и без водопровода жить.
> Самые сильные движки написаны на C/C++ (средней силы иногда
> встречаются Delphi/Pascal), а все прочие языки нервно курят
> в сторонке.
К свойствам языков эта кухонная статистика вообще не имеет никакого отношения.
Почему кухонная? Ну, потому что это рассуждение вроде такого:
"Моя соседка тётя Маша родом из Пскова, и она готовит самые вкусные щи, которые я ел. Значит во Пскове готовят лучшие щи."
Вы не замечаете, как вы передёргиваете?
Есть множество движков.
Есть подмножества: А=самые сильные, Б=средние. Мощность Б много больше мощности А.
Дельфи встречается в Б но не встречается в А.
Какой из этого может следовать вывод? Строго говоря -- никакого. Правдопоподобной гипотезой может быть то, что в общем множестве программ на Дельфи вообще мало.
Больше ничего из такой статистики не следует.
Кстати, C и C++ -- это совершенно разные языки. C семантически изоморфен подмножеству Дельфи, значит программу на C можно абсолютно формально перевести на подмножество Дельфи.
Значит ли это, что сильный движок на C после этого станет средней руки, а то и вообще пойдёт курить?
← →
DiamondShark © (2010-11-11 11:34) [127]
> Дык и не ставь ее туда и будет счастье. В чем сложность?
И что с ним делать, если управление памятью только ручное?
> А как ты собрался удалить или финализировать(также синхронизируя
> доступ к членам объекта ) объект в управляемой куче, если
> на него есть ссылки в DoInvariant1 и в DoInvariant2?
Я -- никак.
А автоматический сборщик -- либо по счётчику ссылок, либо по графу доступности.
← →
oxffff © (2010-11-11 11:45) [128]
> DiamondShark © (11.11.10 11:34) [127]
>
> > Дык и не ставь ее туда и будет счастье. В чем сложность?
>
>
> И что с ним делать, если управление памятью только ручное?
>
>
>
> > А как ты собрался удалить или финализировать(также синхронизируя
>
> > доступ к членам объекта ) объект в управляемой куче,
> если
> > на него есть ссылки в DoInvariant1 и в DoInvariant2?
>
> Я -- никак.
> А автоматический сборщик -- либо по счётчику ссылок, либо
> по графу доступности.
Ну так и нужно предоставлять нормальный код, а не код [120], выдавая его за неуправляемый
Поэтому я правильно и написал,что видимо имелось ввиду не dispose и не finalize, а просто обнуление ссылки или работа дальше сразу.
Поэтому проблема надуманна. Ее здесь нет.
← →
DiamondShark © (2010-11-11 12:02) [129]
> Ну так и нужно предоставлять нормальный код, а не код [120],
> выдавая его за неуправляемый
В [120] пример именно неуправляемого кода.
← →
oxffff © (2010-11-11 12:13) [130]
> DiamondShark © (11.11.10 12:02) [129]
>
> > Ну так и нужно предоставлять нормальный код, а не код
> [120],
> > выдавая его за неуправляемый
>
> В [120] пример именно неуправляемого кода.
Хочешь сказать, что он правильный?
В одном стиле задачи решаются одним способом. А в другом другим.
Но они решаются. А кто не решает, тот идет лесом. :)
← →
oxffff © (2010-11-11 12:16) [131]Ровно с таким же успехом в управляемом коде можно получить такие же грабли при детерминированной финализации неуправляемых ресурсов. Попытаться заюзать еще аллокированный, но уже финализированный объект.
Циклические ссылки-Да.
А в остальном дело удобства и привычки.
← →
DiamondShark © (2010-11-11 12:21) [132]
> Хочешь сказать, что он правильный?
Слово "псевдокод" слышал?
Это пример гипотетического языка, в котором внутренний параллелизм есть, а автоматического управления памятью нет.
Предусловия простые: обе процедуры заведомо не имеют взаимозависимостей.
Результат: требование явного освобождения памяти формирует паразитную зависимость.
Непонятно, что в примере может быть непонятно.
← →
oxffff © (2010-11-11 12:28) [133]
> DiamondShark © (11.11.10 12:21) [132]
>
> > Хочешь сказать, что он правильный?
>
> Слово "псевдокод" слышал?
>
> Это пример гипотетического языка, в котором внутренний параллелизм
> есть, а автоматического управления памятью нет.
>
> Предусловия простые: обе процедуры заведомо не имеют взаимозависимостей.
>
>
> Результат: требование явного освобождения памяти формирует
> паразитную зависимость.
>
> Непонятно, что в примере может быть непонятно.
Что подразумевается под вызовом dispose(a) в этом языке?
← →
euru © (2010-11-11 12:28) [134]
> oxffff © (11.11.10 12:13) [130]
> Хочешь сказать, что он правильный?
Как мне показалось, он как раз-таки наоборот хочет сказать, что такой код или несколько некорректен или избыточен.
← →
DiamondShark © (2010-11-11 12:28) [135]
> можно получить такие же грабли при детерминированной финализации
> неуправляемых ресурсов.
Неуправляемых ресурсов быть не должно.
Сама ОС должна быть средой исполнения управляемого кода.
Специально же писал, ссылки на Вирта давал. Как об стену горох.
← →
DiamondShark © (2010-11-11 12:30) [136]
> Что подразумевается под вызовом dispose(a) в этом языке?
то же, что и в Дельфи.
← →
oxffff © (2010-11-11 12:30) [137]
> euru © (11.11.10 12:28) [134]
>
> > oxffff © (11.11.10 12:13) [130]
> > Хочешь сказать, что он правильный?
>
> Как мне показалось, он как раз-таки наоборот хочет сказать,
> что такой код или несколько некорректен или избыточен.
Если человек не может написать этот код правильно, это чьи проблемы? :)
← →
oxffff © (2010-11-11 12:34) [138]
> DiamondShark © (11.11.10 12:30) [136]
>
> > Что подразумевается под вызовом dispose(a) в этом языке?
>
>
> то же, что и в Дельфи.
Тогда [137].
Подзадача финализации+деаллокации этого примера решаема несколькими способами. Если кто-то хочет переложить решение на установление достижимости объекта автоматически, то он просто обленился решать задачи.
А
Результат: требование явного освобождения памяти формирует паразитную зависимость.
Абсурдно в неуправляемом окружении.
← →
euru © (2010-11-11 12:35) [139]
> oxffff © (11.11.10 12:30) [137]
Ну так вы же выступаете в защиту явного управления временем жизни объекта. А этот пример показывает, что при использовании параллельного программирования такое управление может привести, например, к неоправданной потере производительности.
← →
oxffff © (2010-11-11 12:41) [140]
> euru © (11.11.10 12:35) [139]
>
> > oxffff © (11.11.10 12:30) [137]
>
> Ну так вы же выступаете в защиту явного управления временем
> жизни объекта. А этот пример показывает, что при использовании
> параллельного программирования такое управление может привести,
> например, к неоправданной потере производительности.
Этот пример показывает, как можно потерять в производительности решая задачу неверно.
Тем не менее с таким же успехом можно потерять в производительности при "проходе по графу сборщиком мусора " в момент остановки исполнителей DoInvariant1 и DoInvariant2.
← →
euru © (2010-11-11 12:42) [141]
> oxffff © (11.11.10 12:34) [138]
> Если кто-то хочет переложить решение на установление достижимости
> объекта автоматически, то он просто обленился решать задачи.
В принципе механизмы ООП можно сэмулировать и в обычных языках. А если кто-то для использования этих механизмов хочет предложит ООП-языки, то он тоже просто обленился решать задачи?
← →
oxffff © (2010-11-11 12:43) [142]
> euru © (11.11.10 12:42) [141]
>
> > oxffff © (11.11.10 12:34) [138]
> > Если кто-то хочет переложить решение на установление достижимости
>
> > объекта автоматически, то он просто обленился решать задачи.
>
>
> В принципе механизмы ООП можно сэмулировать и в обычных
> языках. А если кто-то для использования этих механизмов
> хочет предложит ООП-языки, то он тоже просто обленился решать
> задачи?
Может и обленился.
Но этому разве дается термин паразитивность?
← →
DiamondShark © (2010-11-11 12:46) [143]
> euru © (11.11.10 12:35) [139]
Я уж думал, что действительно настолько непонятно выражаюсь. ;)
> oxffff © (11.11.10 12:34) [138]
> Подзадача финализации+деаллокации этого примера решаема
> несколькими способами.
Без автоматического управления памятью эффект будет ровно такой же: появление зависимости.
> то он просто обленился решать задачи.
Анекдот про "в гамаке и на лыжах" знаете?
Умение решать задачи подразумевает, в числе прочего, умение не решать те задачи, без решения которых можно обойтись.
Впрочем, настоящие индейцы могут не согласиться.
> Абсурдно в неуправляемом окружении.
Именно. Неуправляемое окружение состоит из абсурда чуть менее, чем полность. Именно эту мысль я стараюсь донести.
← →
oxffff © (2010-11-11 12:48) [144]
> euru © (11.11.10 12:42) [141]
>
> > oxffff © (11.11.10 12:34) [138]
> > Если кто-то хочет переложить решение на установление достижимости
>
> > объекта автоматически, то он просто обленился решать задачи.
>
>
> В принципе механизмы ООП можно сэмулировать и в обычных
> языках.
Более того я читал об этой реализации на параметризованном лямбда исчислении год назад. Это мягко говоря запутанно и не всегда выразительно. И то пришлось им вводить дополнительную абстракцию как экзистенциальный тип. Видел объектное исчисление Карделли. Но не читал.
Хотя они эквивалентны по выразительности.
← →
euru © (2010-11-11 12:48) [145]
> oxffff © (11.11.10 12:41) [140]
> Этот пример показывает, как можно потерять в производительности
> решая задачу неверно.
А как эту задачу решить верно?
> Тем не менее с таким же успехом можно потерять в производительности
> при "проходе по графу сборщиком мусора " в момент остановки
> исполнителей DoInvariant1 и DoInvariant2.
Сборщик это сделает в либо в свободное время либо по необходимости (например, отсутствие свободной памяти в куче).
← →
DiamondShark © (2010-11-11 12:49) [146]
> Но этому разве дается термин паразитивность?
Русский -- не родной?
Паразитность. Без "-ив-". Технический термин. Общепринятый.
← →
oxffff © (2010-11-11 12:51) [147]
> DiamondShark © (11.11.10 12:46) [143]
>
> > euru © (11.11.10 12:35) [139]
>
> Я уж думал, что действительно настолько непонятно выражаюсь.
> ;)
>
>
> > oxffff © (11.11.10 12:34) [138]
> > Подзадача финализации+деаллокации этого примера решаема
>
> > несколькими способами.
>
> Без автоматического управления памятью эффект будет ровно
> такой же: появление зависимости.
Больше похоже на "зависимость" программиста от сборщика мусора. Но это как говорится каждому свое.
Привел бы циклические ссылки я бы согласился.
Поэтому мне интересен гибридный способ управления.
← →
euru © (2010-11-11 12:56) [148]
> oxffff © (11.11.10 12:48) [144]
О кучах, стеках и прочем:"...фундаментальная проблема заключается в ошибочной вере в то, что система типов имеет какое-либо отношение к стратегии выделения памяти. Просто неверно, что выбор использования стека или кучи имеет какое-либо отношение к типу сущности, располагаемой в памяти. Правда заключается в том, что выбор механизма распределения памяти имеет отношение только к требованию времени жизни области памяти."
http://blogs.msdn.com/b/ruericlippert/archive/2010/10/25/the-truth-about-value-types.aspx
← →
DiamondShark © (2010-11-11 13:06) [149]
> Больше похоже на "зависимость" программиста от сборщика
> мусора.
Вот смотри: была задача написать две процедуры, не обладающие побочным эффектом относительно а.
Написали.
Нафига при этом думать об их ВОЗМОЖНОЙ зависимости? Если, ёлкин клин, задача была НАПИСАТЬ блин НЕЗАВИСИМЫЕ ПРОЦЕДУРЫ.
> Привел бы циклические ссылки я бы согласился.
О! Циклические ссылки -- это круто.
Особенно, при ручном управлении. Гы. :))))))))))
> Поэтому мне интересен гибридный способ управления.
А зачем? Объясни, мне правда интересно.
Только, пожалуйста, не ссылайся на проблемы в гибридных средах, вроде дотНЕТ.
Вот есть ОС, которая вся целиком -- исполняющая среда управляемого кода.
Куда здесь гибридный способ управления?
← →
oxffff © (2010-11-11 14:10) [150]
> euru © (11.11.10 12:56) [148]
>
> > oxffff © (11.11.10 12:48) [144]
>
> О кучах, стеках и прочем:
> "...фундаментальная проблема заключается в ошибочной вере
> в то, что система типов имеет какое-либо отношение к стратегии
> выделения памяти. Просто неверно, что выбор использования
> стека или кучи имеет какое-либо отношение к типу сущности,
> располагаемой в памяти. Правда заключается в том, что выбор
> механизма распределения памяти имеет отношение только к
> требованию времени жизни области памяти."
> http://blogs.msdn.com/b/ruericlippert/archive/2010/10/25/the-
> truth-about-value-types.aspx
А где [144] я указал на эту связь?
← →
oxffff © (2010-11-11 14:17) [151]
> DiamondShark © (11.11.10 13:06) [149]
>
> > Больше похоже на "зависимость" программиста от сборщика
>
> > мусора.
>
> Вот смотри: была задача написать две процедуры, не обладающие
> побочным эффектом относительно а.
Интересно, а как это 2 ссылки на одну сущность лишились побочного эффекта? Эти процедуры не являются чистыми функциями. И обладают побочным эффектом.
← →
oxffff © (2010-11-11 14:22) [152]
> euru © (11.11.10 12:48) [145]
>
> > oxffff © (11.11.10 12:41) [140]
> > Этот пример показывает, как можно потерять в производительности
>
> > решая задачу неверно.
>
> А как эту задачу решить верно?
Я выше написал. :)
> > Тем не менее с таким же успехом можно потерять в производительности
>
> > при "проходе по графу сборщиком мусора " в момент остановки
>
> > исполнителей DoInvariant1 и DoInvariant2.
>
> Сборщик это сделает в либо в свободное время либо по необходимости
> (например, отсутствие свободной памяти в куче).
1. А если нет столько памяти?
2. А если есть ограничения на размер кучи?
3. А если есть требования освобождать в момент последней потери корня.
Управляемая куча спасет Вас? :)
← →
tesseract © (2010-11-11 14:27) [153]
> Сборщик это сделает в либо в свободное время либо по необходимости
> (например, отсутствие свободной памяти в куче).
Или по просьбе трудящихся. По крайней мере в MacOS и iOS таки возможно.
← →
tesseract © (2010-11-11 14:27) [154]
> 1. А если нет столько памяти?
А что неуправляемая куча решит данный вопрос?
← →
oxffff © (2010-11-11 14:28) [155]
> DiamondShark © (11.11.10 13:06) [149]
>
>
> > Привел бы циклические ссылки я бы согласился.
>
> О! Циклические ссылки -- это круто.
> Особенно, при ручном управлении. Гы. :))))))))))
>
>
> > Поэтому мне интересен гибридный способ управления.
>
> А зачем? Объясни, мне правда интересно.
> Только, пожалуйста, не ссылайся на проблемы в гибридных
> средах, вроде дотНЕТ.
> Вот есть ОС, которая вся целиком -- исполняющая среда управляемого
> кода.
> Куда здесь гибридный способ управления?
Я бы использовал в качестве решения проблемы циклических ссылок управляемую кучу. Для остального неуправляемую.
У меня это Windows. Я бы с удовольствие в данный момент использовал гибридный способ. Есть у меня такая сейчас задача.
А если у кого исполняющая среда управляемого кода. Тогда пусть он и думает.
← →
oxffff © (2010-11-11 14:30) [156]
> tesseract © (11.11.10 14:27) [154]
>
> > 1. А если нет столько памяти?
>
>
> А что неуправляемая куча решит данный вопрос?
А если нет памяти, придется собирать мусор и дефрагменировать кучу.
А это время.
← →
Mystic © (2010-11-11 14:34) [157]
> Во-первых, автоматический анализ кода вполне возможен. Результат
> будет хуже, чем в спецязыках, но будет.
Что в свою очередь увеличит время компиляции, усложнит уровень вхождения в язык (надо будет разбираться со всей этой кухней чтобы управлять этим), и приведет к разным хитрым багам/фичам + добавит радости в отладке.
> Во-вторых, можно ввести декларирование инвариантов, что-
> то вроде:
Такое дополнительное декларирование это тоже дополнительная работа. Может оказаться, что ручками распараллелить критичный кусок будет быстрее, чем по всему проекту поддерживать инварианты.
Во-вторых, есть случаи, когда такие инварианты доступны только через обращение к чему-то внешнему, вроде базы данных, DLL, ... В этом случае компилятор никак не сможет проверить инвариантность, посему надо будет писать в коде "мамой клянусь!". Что опять может породить интересные баги.
> > Но это тот случай, когда за динамической памятью надо
> следить,
> > так что от ручного управления никуда.
>
> У вас тут причина со следствием попутана.
> За динамической памятью надо следить, потому что доступно
> только ручное управление.
Нет, за динамической памятью надо следить, потому что стоит задача максимально полно и эффективно использовать ограниченный объем памяти. В процессе перебора вариантов мы исчерпали отведенный нам объем памяти. Что делать? И в том и в другом случае надо пройтись по дереву и обнулить ссылки на неактуальные позиции, что равносильно удалению объектов. Только потом надо запускать сборщик мусора, который выполнит еще кучу лишней работы.
> Кстати, C и C++ -- это совершенно разные языки. C семантически
> изоморфен подмножеству Дельфи, значит программу на C можно
> абсолютно формально перевести на подмножество Дельфи.
> Значит ли это, что сильный движок на C после этого станет
> средней руки, а то и вообще пойдёт курить?
Используется C с классами обычно. Все возможности ООП не юзаются, только некий минимум. C/C++ лучший выбор больше из-за того, что есть поддержка x64, что дает 30% производительности. Но в целом это задача, где возможностей C хватает и в чем-то большем большой нужды нет.
А так ситуация такая. Если реализовать базовые техники (генерация ходов с использованием битбордов, альфа-бета, киллеры, Z-Orbice, стандартные элементы оценки позиции, нулевой ход, ...), то получаем движок средней силы. Это можно реализовать на C, можно на Delphi. Уже в случае всяких C# возникает небольшой геморрой: в погоне а производительностью нужно постоянно раскручивать ту или иную конструкцию на предмет того, а что это будет нам стоить.
← →
tesseract © (2010-11-11 14:36) [158]
> А это время.
Сборка мусора навряд ли займёт время больше свалки / загрузки выгружаемой памяти процесса по нужде системы.
← →
euru © (2010-11-11 14:54) [159]
> oxffff © (11.11.10 14:10) [150]
> А где [144] я указал на эту связь?
Да это больше к слову "читал" относилось. :)
Основной посыл: "Пусть компилятор и среда времени выполнения заботятся о времени жизни хранилища; это то, для чего они предназначены."
В любом случае низкоуровневая оптимизация, выполняемая вручную, либо будет эффективна только в уском сегменте её использования (как на примере ассемблерных вставок), либо усложнит дальнейшую поддержку и сопровождение.
← →
oxffff © (2010-11-11 14:54) [160]
> tesseract © (11.11.10 14:36) [158]
>
> > А это время.
>
>
> Сборка мусора навряд ли займёт время больше свалки / загрузки
> выгружаемой памяти процесса по нужде системы.
А это уж совсем быстро. Пару тактов. :)
← →
tesseract © (2010-11-11 15:05) [161]
> А это уж совсем быстро. Пару тактов. :)
Может все таки пару-десяток сотен? А сама вот оптимизация кучи в случае двухпроцессорной машинки вообще может тактов не занять. Т.к. коллектор носится в соседнем потоке.
← →
euru © (2010-11-11 15:06) [162]
> oxffff © (11.11.10 14:22) [152]
> Я выше написал. :)a := nil;
- этот?
И каково должно быть дальнейшее поведение программы/среды выполнения после этого выражения?
← →
tesseract © (2010-11-11 15:07) [163]Кстати вот офф рекомендации от Apple. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/GarbageCollection/Articles/gcAdoption.html#//apple_ref/doc/uid/TP40002457
Собственно почти все недостатки описаны замечательно.
← →
oxffff © (2010-11-11 15:11) [164]
> tesseract © (11.11.10 15:05) [161]
>
> > А это уж совсем быстро. Пару тактов. :)
>
>
> Может все таки пару-десяток сотен? А сама вот оптимизация
> кучи в случае двухпроцессорной машинки вообще может тактов
> не занять. Т.к. коллектор носится в соседнем потоке.
Коллектор не может нестить в другом процессе сам по себе. Поскольку куча разделяемая. Тормозятся все потоки управляемого кода.
← →
DiamondShark © (2010-11-11 15:11) [165]Я сейчас пишу под мобильные девайсы на NET-Compact. Девайсы довольно хиленькие, как по процессору, так и по объёмам памяти. Если верить профилировщику, то мусорщик ходит не часто, а весьма часто. Каких-нибудь неудобств в связи с этим не заметно вообще.
Так что опасения про время сборки мусора считаю сильно преувеличенными.
Теперь другой момент.
Тот проект, что я пишу, раньше вёлся (другими людьми) на нативном С++. Он не был завершён, потому что упёрся в две вещи:
- в сложность
- в, таки да, дефицит памяти.
К моменту смерти проекту исполнилось два года.
Чуть более, чем за пол-года я не только переписал его с нуля до уровня коммерческого внедрения, но и вижу неплохие перспективы развития. А пределов ресурсов платформы -- наоборот, даже и на горизонте не вижу.
Я не фанат шарпа и не считаю дотНЕТ идеалом менеджед-сред, но, пользуясь случаем, хочу передать превед любителям С++.
ЗЫ
Разумеется, я знаю, что то были неправильные программисты на С++.
← →
oxffff © (2010-11-11 15:12) [166]
> euru © (11.11.10 15:06) [162]
>
> > oxffff © (11.11.10 14:22) [152]
> > Я выше написал. :)
>
> a := nil; - этот?
> И каково должно быть дальнейшее поведение программы/среды
> выполнения после этого выражения?
А если a:ISomeStuff?
← →
oxffff © (2010-11-11 15:14) [167]
> Коллектор не может нестить в другом процессе сам
Потоке естественно.
← →
DiamondShark © (2010-11-11 15:18) [168]
> У меня это Windows. Я бы с удовольствие в данный момент
> использовал гибридный способ. Есть у меня такая сейчас задача.
Так и у меня пока что это Windows. Только подход прямо противоположный: ручное управление ТОЛЬКО при интеропе с неуправляемым окружением, потому что "куды ты денешься с подводной лодки".
Интересует обоснование ручного управления именно в менеджед-окружении. А этого я пока не увидел.
← →
euru © (2010-11-11 15:27) [169]
> oxffff © (11.11.10 15:12) [166]
> А если a:ISomeStuff?
Допустим. Т.е. имеем:a: ISomeStuff
. . . // код, использующий a
a := nil;
. . . // продолжение программы
Что должно произойти послеa := nil;
?
← →
oxffff © (2010-11-11 15:30) [170]
> DiamondShark © (11.11.10 15:18) [168]
>
> > У меня это Windows. Я бы с удовольствие в данный момент
>
> > использовал гибридный способ. Есть у меня такая сейчас
> задача.
>
> Так и у меня пока что это Windows. Только подход прямо противоположный:
> ручное управление ТОЛЬКО при интеропе с неуправляемым окружением,
> потому что "куды ты денешься с подводной лодки".
>
> Интересует обоснование ручного управления именно в менеджед-
> окружении. А этого я пока не увидел.
Кого интересует? Меня? Совершенно не интересует. У меня native код.
Я собственнно все о том примере.
← →
oxffff © (2010-11-11 15:34) [171]
> euru © (11.11.10 15:27) [169]
>
> > oxffff © (11.11.10 15:12) [166]
> > А если a:ISomeStuff?
>
> Допустим. Т.е. имеем:
> a: ISomeStuff
> . . . // код, использующий a
> a := nil;
> . . . // продолжение программы
>
> Что должно произойти после a := nil;?
Ничего. На a ссылаются еще два корня. Как только завершат заботу потоки и управляемые параметры финазируются объект финализируется и деаллокируется. Только правильно это сделать "защищенно".
← →
tesseract © (2010-11-11 15:51) [172]
> Если верить профилировщику, то мусорщик ходит не часто,
> а весьма часто. Каких-нибудь неудобств в связи с этим не
> заметно вообще.
Я помню только один недостаток WinCe с которым работал - там память была медленная независимо от того родной там код или управляемый, и она кончалась моментально. Но это было ещё 4.1 где механизмы радикально отличались от 5 и выше.
← →
DiamondShark © (2010-11-11 15:56) [173]
> Mystic © (11.11.10 14:34) [157]
> Что в свою очередь увеличит время компиляции, усложнит уровень
> вхождения в язык (надо будет разбираться со всей этой кухней
> чтобы управлять этим), и приведет к разным хитрым багам/фичам
> + добавит радости в отладке.
Про время компиляции, уровень вхождения и радость в отладке вы уже сейчас можете побеседовать с программистами на С++, юзающими какую-нибудь библиотеку с шаблонами.
А ещё лучше примите такой проект на сопровождение. ;)
Почему-то, когда хвастаются глубокой оптимизацией в Си-компиляторах и фичами библиотек шаблонов, то это типа круто.
А в другие языки фичи нельзя добавлять, потому что время компиляции.
Не чувствуете тут фигни с логикой?
> Такое дополнительное декларирование это тоже дополнительная
> работа. Может оказаться, что ручками распараллелить критичный
> кусок будет быстрее, чем по всему проекту поддерживать инварианты.
Ручками не получится быстрее, потому что ручками придётся писать кучу инфраструктурного кода.
> Во-вторых, есть случаи, когда такие инварианты доступны
> только через обращение к чему-то внешнему, вроде базы данных,
> DLL, ... В этом случае компилятор никак не сможет проверить
> инвариантность,
DLL быть не должно. Для управляемых модулей доступна вся метаинформация.
А если компилятор что-то не сможет формально проверить, то просто не будет генерировать параллельный код.
> посему надо будет писать в коде "мамой клянусь!
> ". Что опять может породить интересные баги.
Буквально пару предложений выше вас не смущала необходимость ручками написать "мамой клянусь!" с возможностью багов, более того, вы пытаетесь доказать что иной способ не нужен.
Возражая мне, не противоречьте сами себе. Хотябы в пределах абзаца ;)
> Нет, за динамической памятью надо следить, потому что стоит
> задача максимально полно и эффективно использовать ограниченный
> объем памяти.
Я про разработку на девайсах уже написал. Там с памятью вообще очень грустно всё.
Это всё предрассудки, боязнь мнимой потери контроля.
> Но в целом это задача, где возможностей C хватает и в чем-
> то большем большой нужды нет.
Ну так значит ваша задача к сравнению возможностей языков не имеет отношения никакого. С -- примитивный язык.
← →
crux (2010-11-11 16:04) [174]oxffff © (11.11.10 12:51) [147]
>Поэтому мне интересен гибридный способ управления.
По крайней мере в Managed C++ (до того, как он стал C++/CLI) была возможность совмещать мусорособираемые объекты .NET с нативными (через нестандартный синтаксис). Осталось ли эта возможность сейчас, не уверен (похоже, что осталась, убирать ее было бы не логично).
← →
tesseract © (2010-11-11 16:06) [175]
> С -- примитивный язык.
Нормальный он язык. И для определенных целей - например консольных приложений он лучше огорода ООП.
> Ручками не получится быстрее, потому что ручками придётся
> писать кучу инфраструктурного кода.
Хорошо приучает к экономии идентификаторов и запихивании логики по функциям кстати. Но это уже другая история.
← →
oxffff © (2010-11-11 16:10) [176]
> crux (11.11.10 16:04) [174]
> oxffff © (11.11.10 12:51) [147]
>
> >Поэтому мне интересен гибридный способ управления.
>
> По крайней мере в Managed C++ (до того, как он стал C++/CLI)
> была возможность совмещать мусорособираемые объекты .NET
> с нативными (через нестандартный синтаксис). Осталось ли
> эта возможность сейчас, не уверен (похоже, что осталась,
> убирать ее было бы не логично).
Она никуда не делать. Это называется pinned оbject.
Сборщику запрещено перемещать объект в куче.
← →
euru © (2010-11-11 16:27) [177]
> oxffff © (11.11.10 15:34) [171]
> Ничего.
Т.е. это просто декларация компилятору, что как только все остальные также перестанут ссылаться на этот элемент, то его можно смело удалять из кучи? Ну так при анализе кода компилятор и сам может об этом догадаться и пометить данную ссылку неактивной. А если компилятор этого делать не умеет, а программист, в свою очередь, не продекларирует, то мы получим утечку памяти.
> На a ссылаются еще два корня.
Это только в том случае, если у обеих процедурDoInvarian1
иDoInvariant2
описание параметров выглядит как(var b: ISomeStuff)
. В противном случае переменнаяa
и параметры процедур независимо друг от друга ссылаются на один и тот же объект в памяти.
> Как только завершат
> заботу потоки и управляемые параметры финазируются объект
> финализируется и деаллокируется. Только правильно это сделать
> "защищенно".
Эти потоки могут, в свою очередь, создать другие потоки, также использующие данный параметр. Так что завершение этих потоков не гарантирует освобождение всех ссылок на объект в памяти.
← →
Дмитрий Белькевич (2010-11-11 16:27) [178]
> Разумеется, я знаю, что то были неправильные программисты
> на С++.
"К свойствам языков эта кухонная статистика вообще не имеет никакого отношения."
← →
Дмитрий Белькевич (2010-11-11 16:32) [179]> и радость в отладке
Расскажу про свою. Как-то либу пытался отлаживать. Модулей под тысячу. На каждый пук - класс. На каждый класс - модуль+хидер.
Пришлось таки человека нанимать. Ну не моё это :)
Человек переписали на делфю. На делфе - 5 модулей. Функциональность - в 5 раз больше. Код можно охватить одним мозгом :)
И, да, "К свойствам языков эта кухонная статистика вообще не имеет никакого отношения."
← →
Дмитрий Белькевич (2010-11-11 16:33) [180]Но осадочек остался :)
← →
Mystic © (2010-11-11 17:12) [181]
> Про время компиляции, уровень вхождения и радость в отладке
> вы уже сейчас можете побеседовать с программистами на С++,
> юзающими какую-нибудь библиотеку с шаблонами.
> А ещё лучше примите такой проект на сопровождение. ;)
Шаблоны C++ это верх идеи о том, что все должно быть автоматизировано компилятором. Соответственно, в результате имеем определенный геморрой. Мне больше нравятся простые языки, тот же C например.
> Ручками не получится быстрее, потому что ручками придётся
> писать кучу инфраструктурного кода.
Я не утверждал на 100%. Но сравнительно часто инфраструктурного кода оказывается не так уж и много, написал да забыл :)
> DLL быть не должно.
Под Windows все конечном итоге все сводится к вызовам DLL. Но лучше подождем, когда такие возможность появится, пока что мы обсуждаем то, чего нет и близко.
> Я про разработку на девайсах уже написал. Там с памятью
> вообще очень грустно всё.
А я где-то писал, что мало памяти? Мало память, маленькая куча, ею легко управлять :) Тут наоборот, у движка солидный хэш, (например, 512M или 1G), который надо эффективно использовать. Если брать чисто генерацию ходов, то современные движки прекрасно выжимают 1 000 000 (=1M) позиций в секунду. Допустим, одна позиция это 128 байт данных, итого получает 128M секунду, таким образом наш хэш заполнится за пять секунд. После этого я, допустим, нашел еще 2.5M неактуальных позиций и очистил ссылки на них. После чего должен запуститься сборщик мусора, который должен проанализировать все наши 5M объектов в памяти, чтобы найти 2.5M объектов, к которым нельзя добраться по ссылкам...
> С -- примитивный язык.
И в этом его недостаток, но и его преимущество.
← →
DiamondShark © (2010-11-11 17:26) [182]
> tesseract © (11.11.10 16:06) [175]
>> С -- примитивный язык.
> Нормальный он язык. И для определенных
> целей - например консольных приложений он лучше огорода
> ООП.
Вы не обижайтесь так, "примитивный" -- это не ругательство, это термин.
Вот Int, например -- примитивный тип. Вы ж не возразите, что он нормальный тип. ;)
>> Ручками не получится быстрее, потому что ручками
>> придётся писать кучу инфраструктурного кода.
> Хорошо приучает
> к экономии идентификаторов и запихивании логики по функциям
> кстати. Но это уже другая история.
Фигасе. Идентификаторы -- это уже ресурс, который надо экономить? %(
А логика должна не "запихиваться" (с оглядкой, блин, на экономию идентификаторов), а проектироваться. Желательно, чтобы этому процессу ничего (вроде БДСМ-ных замашек языка, который "приучает") не мешало.
← →
tesseract © (2010-11-11 17:47) [183]
> Вы не обижайтесь так, "примитивный" -- это не ругательство,
> это термин.
Я не обижаюсь. Собственно Си начал осваивать когда баловался с *nix и OS-софтом. Читабельность кода у него распологает.
> Фигасе. Идентификаторы -- это уже ресурс, который надо экономить?
> %(
Если не любишь того, кто твой код поддерживать будет можешь не экономить. Лучше не распалятся :-)
> Желательно, чтобы этому процессу ничего (вроде БДСМ-ных
> замашек языка, который "приучает") не мешало.
Это к любому языку относится. BSDM-ные замашки на паскале встречаются повсеместно, не смотря на его вроде-как логичность.
← →
DiamondShark © (2010-11-11 17:54) [184]
> Mystic © (11.11.10 17:12) [181]
> Шаблоны C++ это верх идеи о том, что все должно быть автоматизировано
> компилятором. Соответственно, в результате имеем определенный
> геморрой.
Я выше писал, что как генератор идей C++ весьма очень даже.
Сама идея шаблонов, параметризованного кода, обобщённого программирования -- хороша есть весьма.
Реализация -- ни к чёрту.
Плюсные шаблоны вообще нельзя реюзать иначе, как в виде исходного кода. Отсюда и все прелести со скоростью компиляции и радостью в отладке.
А теперь ищем чуть выше ссылку на Франца, и видим, что для той технологии шаблоны -- как родные.
> Под Windows все конечном итоге все сводится к вызовам DLL.
> Но лучше подождем, когда такие возможность появится, пока
> что мы обсуждаем то, чего нет и близко.
Я и хотел пообсуждать то, чего пока нет.
> После чего должен запуститься сборщик мусора, который должен
> проанализировать все наши 5M объектов в памяти, чтобы найти
> 2.5M объектов, к которым нельзя добраться по ссылкам...
Это очень быстро. Медленнее, чем в Дельфи, но вы выиграете на времени выделения. В среднем не будет большой разницы.
Где-то были бенчмарки по работе с памятью. Можно поискать.
Результаты, если правильно помню, такие: самая тормознутая -- стандартная С-библиотека, самая шустрая дельфийская ФастММ. ДотНЕТ где-то посередине ПО СРЕДНЕМУ времени.
Да и дотнетовский менеджер не самый оптимальный по скорости из возможных алгоритмов автоматических менеджеров. Что и не скрывалось никогда.
← →
tesseract © (2010-11-11 18:02) [185]
> Сама идея шаблонов, параметризованного кода, обобщённого
> программирования -- хороша есть весьма.
Посмотри smalltalk. Почитал синию книжку - вот где кладезь идей был. В 1972 ! Все обобщено и без лишних костылей.
← →
Mystic © (2010-11-11 18:33) [186]
> Я выше писал, что как генератор идей C++ весьма очень даже.
>
> Сама идея шаблонов, параметризованного кода, обобщённого
> программирования -- хороша есть весьма.
В данном случае идея стырена из ады. И адский подход мне нравится куда больше, ибо в нем больше строгости. По крайней мере всяких валидольных ошибок с кишками нету :)generic
type Element is private;
package Stacks is
procedure Push(E : in Element);
procedure Pop(E : out Element);
function Empty return Boolean;
private
The_Stack : array(1..200) of Element;
top : Integer range 0..200 := 0;
end Stacks;
> Я и хотел пообсуждать то, чего пока нет.
А смысл? У меня даже нет никаких идей по реализации таких систем. Нет, у меня хватит фантазии преставить систему, на вход которой подается T3 на естественном языке, а на выходе получаем программу. Но принципы ее фунционирования для меня загадка. Так и тут, я конечно могу представить, что есть система, которая берет текст на C# и параллелит его автоматом. Но на этом пути я вижу пока что кучу проблем, и считаю его нереальным.
А вот адский подход к многозадачности, уже 25 лет как реализованый:
with Ada.Text_IO;
procedure Multitasking_Demo is
-- спецификация анонимной задачи
task Anonimous_Task;
-- тело анонимной задачи
task body Anonimous_Task is
begin -- для Anonimous_Task
for Count in 1..5 loop
Ada.Text_IO.Put_Line("Hello from Anonimous_Task");
end loop;
end Anonimous_Task;
-- спецификация типа задачи
task type Simple_Task (Message: Character);
-- тип задачи имеет тело
task body Simple_Task is
begin -- для Simple_Task
for Count in 1..5 loop
Ada.Text_IO.Put_Line("Hello from Simple_Task " & Message);
end loop;
end Simple_Task;
-- переменная задачного типа
Simple_Task_Variable: Simple_Task(Message => "A");
begin -- для Multitasking_Demo
-- в отличие от процедур, задачи не вызываются,
-- а активируются автоматически
-- выполнение обоих задач начинается как только
-- управление достигнет этой точки, то есть, сразу
-- после "begin", но перед выполнением первой инструкции
-- головной процедуры Multitasking_Demo
null;
end Multitasking_Demo;
Кстати, иногда хочется побыть в альтернативной реальности, где Borland вы выбрал вместо паскаля аду :)
> Это очень быстро. Медленнее, чем в Дельфи, но вы выиграете
> на времени выделения. В среднем не будет большой разницы.
>
> Где-то были бенчмарки по работе с памятью. Можно поискать.
Смысл искать, если объекты имеют одинаковый размер? Соответственно эффективный менеджер памяти пишется за 15 минут: все свободные объекты поместили в список. Нужен новый объект --- взяли его из списка. Не нужен --- поместили обратно :)
← →
DiamondShark © (2010-11-11 19:52) [187]
> В данном случае идея стырена из ады.
Да не важно, откуда она стырена. Я ж говорю: С++ -- это как заповедник.
> Нет, у меня хватит фантазии преставить систему
Что вы, я маниловщину и не предлагаю.
> Так и тут, я конечно могу представить, что есть система,
> которая берет текст на C# и параллелит его автоматом. Но
> на этом пути я вижу пока что кучу проблем, и считаю его
> нереальным.
Похожее умел ещё Турбо-Паскаль 5.5. Он старался сгенерировать код, максимально использующий возможность параллельной работы CPU и FPU. Чем не прообраз многоядерного параллелизма?
Сейчас вот интел изобретает примочку в процессор, для анализа непосредственно потока команд и раскидывания по ядрам. Видимо, решил не ждать милостей от разработчиков компиляторов %(
Подчеркну, что я не многозадачность говорю, а именно про внутренний параллелизм. Что-то типа такого:
a := (X + Y) * (U - V);
Подвыражения "(X + Y)" и "(U - V)" можно вычислить на разных ядрах параллельно.
Это могут быть не только сложные выражения, но и, скажем, разные участки линейной последовательности операторов. Или, например, цикл, когда тело не зависит от предыдущих итераций, можно выполнить в несколько параллельных линий.
Это не многозадачность/многопоточность! Здесь не требуется, например, изоляция контекстов потоков.
Должен быть механизм быстрого дешёвого порождения таких параллельных веток.
← →
Дмитрий Белькевич (2010-11-11 20:07) [188]
> Это не многозадачность/многопоточность
И как же данные "размажутся" между ядрами? Чудесным образом?
← →
DiamondShark © (2010-11-11 20:21) [189]
> И как же данные "размажутся" между ядрами? Чудесным образом?
Я не знаю как, ведь ядра доступа к общей памяти не имеют.
Наверное, придётся ждать разработки процессора, у которого ядра умеют читать из одной и той же области памяти.
← →
_oxffff (2010-11-11 20:25) [190]
> DiamondShark © (11.11.10 17:54) [184]
>
> > Mystic © (11.11.10 17:12) [181]
> > Шаблоны C++ это верх идеи о том, что все должно быть автоматизировано
>
> > компилятором. Соответственно, в результате имеем определенный
>
> > геморрой.
>
> Я выше писал, что как генератор идей C++ весьма очень даже.
>
> Сама идея шаблонов, параметризованного кода, обобщённого
> программирования -- хороша есть весьма.
The .NET generics are parameterized types with homogenous constrained
parameter lists, while C++ templates represent parameterized types with heterogeneous unconstrained parameter lists.
Тем не менее templates беспорно мощнее generics. Однако за такую мощь необходимо платить type checking в момент инстанцирования. В то время как тело generic возможно проверить в момент его определения.
> Реализация -- ни к чёрту.
А что есть уверенность что можно сделать по другому?
← →
_oxffff (2010-11-11 20:30) [191]
> Сейчас вот интел изобретает примочку в процессор, для анализа
> непосредственно потока команд и раскидывания по ядрам. Видимо,
> решил не ждать милостей от разработчиков компиляторов %(
Больно подозрительно выглядит!
Может имелось ввиду совместное использование исполнительных устройств между ядрами в зависимости от нагрузки.
У AMD в следующем году выйдет процессор Bulldozer c разделяемым FPU между двумя ядрами. FLEX FP
http://www.bit-tech.net/news/hardware/2010/10/28/amd-unveils-flex-fp/1
http://www.xbitlabs.com/news/cpu/display/20101026234515_AMD_Calls_New_FPU_Flex_FP_Defends_Dual_FMAC_Approach.html
← →
_oxffff (2010-11-11 20:40) [192]
> Сейчас вот интел изобретает примочку в процессор, для анализа
> непосредственно потока команд и раскидывания по ядрам. Видимо,
> решил не ждать милостей от разработчиков компиляторов %(
>
> Подчеркну, что я не многозадачность говорю, а именно про
> внутренний параллелизм. Что-то типа такого:
> a := (X + Y) * (U - V);
> Подвыражения "(X + Y)" и "(U - V)" можно вычислить на разных
> ядрах параллельно.
Это есть и сейчас и называется внеочередным исполнением команд. Зависимости отслеживаются еще со времен Intel Pentium PRO.
← →
Mystic © (2010-11-11 20:45) [193]
> Тем не менее templates беспорно мощнее generics. Однако
> за такую мощь необходимо платить type checking в момент
> инстанцирования. В то время как тело generic возможно проверить
> в момент его определения.
Сделать как в Ada: вместе с описанием типа необходимо описать все требования к нему? Например:generic
type Element is limited private;
with function "="(E1, E2 : Element) return Boolean;
with procedure Assign(E1, E2 : Element);
package Stuff is . . .
← →
Дмитрий Белькевич (2010-11-11 20:46) [194]
> внеочередным исполнением команд
В пределах одного ядра, не?
← →
_oxffff (2010-11-11 21:00) [195]
> Mystic © (11.11.10 20:45) [193]
Если между параметрами типами можно определить ограничения например так:
ClassA<T,U> where T:U.
{
a:T;
b:U;
..
{b:=a; } безопасно поскольку T является подтипом U.
Тело можно проверить.
..
}
Это generics.
Теперь templates
ClassA< Func(U->T), Z, Func2(U,Z->E)>
{
a:Func<nteger>;
b:Func<Z>;
c:Func2<integer,Z>
d:Func2<integer,Func<Z>>
..
{b:=a;
c:=d;
} Проверить нельзя поскольку тело Func и Func2(функции из вида в вид)
неизвестно.
..
}
где вид-это тип, или функция из вида в вид.
Вводить отношения между функциями из вида в вида сложно(с ограничениями) если вообще возможно . Поскольку для
одних параметров они коварианты, для других контвариантны, для других инварианты.
Так что не нужно катить бочку на С++.
Я хоть не сторонник C++. Но тем не менее его уважаю. :)
← →
_oxffff (2010-11-11 21:08) [196]
> Дмитрий Белькевич (11.11.10 20:46) [194]
>
> > внеочередным исполнением команд
>
>
> В пределах одного ядра, не?
Мне видится, что они могут сделать общий пул исполнительных устройств на несколько ядер. В зависимости от нагрузки ядра они могут распределяться динамически. Сейчас у каждого ядра свой набор таких устройств.
← →
Pavia © (2010-11-11 21:26) [197]
> Похожее умел ещё Турбо-Паскаль 5.5. Он старался сгенерировать
> код, максимально использующий возможность параллельной работы
> CPU и FPU. Чем не прообраз многоядерного параллелизма?
Автор жжет. Пиши ясчё.
← →
Дмитрий Белькевич (2010-11-11 21:51) [198]
> Автор жжет. Пиши ясчё.
Ну я уже не стал комментировать :) Но таки да.
> Сейчас у каждого ядра свой набор таких устройств.
Ну как я себе представляю, то ядра на кристалле разделены топографически, или я не прав, и ядра могут юзать куски друг друга?
← →
tesseract © (2010-11-11 22:07) [199]
> В зависимости от нагрузки ядра они могут распределяться
> динамически.
itanium или Cell такое таки умеют.
> или я не прав, и ядра могут юзать куски друг друга?
Аппаратно не умеют. SMP от intel вообще отделены намертво. От AMD могут плевать друг в друга данными почти без потерь на синхронизацию.
Софтверно - я же давал ссылку на GrandCentral - она умеет куски кода нарезать и отправлять по процессорам. Но это только при их сборщике мусора.
← →
_oxffff (2010-11-11 22:07) [200]
> Дмитрий Белькевич (11.11.10 21:51) [198]
>
> > Сейчас у каждого ядра свой набор таких устройств.
>
>
> Ну как я себе представляю, то ядра на кристалле разделены
> топографически, или я не прав, и ядра могут юзать куски
> друг друга?
Разделение на физические ядра условно.
Прочитайте про архитектуру AMD Bulldozer.
это первая страница
http://www.realworldtech.com/page.cfm?ArticleID=RWT082610181333&p=1
Внизу оглавление
← →
tesseract © (2010-11-11 22:10) [201]
> Прочитайте про архитектуру AMD Bulldozer.
Оно уже вышло? Если llvm победит, то разделение и на архитектуру процессоров можно будет считать условной :-)
← →
_oxffff (2010-11-11 22:18) [202]
> tesseract © (11.11.10 22:10) [201]
В 2011.
← →
Pavia © (2010-11-11 22:30) [203]
> Ну как я себе представляю, то ядра на кристалле разделены
> топографически, или я не прав, и ядра могут юзать куски
> друг друга?
Смотря что понимать под ядрами. К примеру core 2 due это двух ядерный. Но имеют общий кэш третьего уровня. Через которое и происходит общение.
А вот Pentium D хоть и считается одноядерным имеет HT. Фактически это 2 ядра тесно связанных друг с другом и имеющие общие блоки такие как АЛУ, мэнеджер питания и др которые они делят между друг другом.
К примеру Pentium pro имеет два АЛУ. Которые может загружать параллельно.
А вот на видео карте нет ядер как таковых там АЛУ но их много. И производитель называет их ядрами. При этом АЛУ связанны в виде матрицы и данные из одного АЛУ в другое передаются по цепочки.
А вообще при производстве процессора ядра получают не столько физическим дублированием сколько программным при проектировании. И там уже разводят связи. Так что топографический они всё-таки связаны.
Хотя раньше были разделены.
← →
картман © (2010-11-11 22:40) [204]
>
> А вот Pentium D хоть и считается одноядерным имеет HT. Фактически
> это 2 ядра тесно связанных друг с другом и имеющие общие
> блоки такие как АЛУ, мэнеджер питания и др которые они делят
> между друг другом.
ага, два, конечно, а ты попробуй создай по потоку на ядро HT и посчитай, что получится
← →
Pavia © (2010-11-11 22:48) [205]
> ага, два, конечно, а ты попробуй создай по потоку на ядро
> HT и посчитай, что получится
А зачем считать? Это и так известно. И в книжках было описано еще до моего появления на свет.
1. Проблема вытеснения. Два потока будут просто мешать друг дружке.
2. Либо проблема балансировки нагрузки. Не до загруженности второго даже при наличии свободных блоков.
← →
картман © (2010-11-11 22:54) [206]
> Pavia © (11.11.10 22:48) [205]
я к тому, что ядро там одно, если судить по работе процессора
← →
Дмитрий Белькевич (2010-11-11 22:58) [207]По поводу гипертридинга я вкурсе, больше инетересовали полноценные ядра.
Вообще, возможно были бы интересны некие "надпроцессные" команды. Т.е. такой расширенный набор надпроцессных команд, который бы помогал параллелить код. Думается, что тут со стороны железа можно было что-то сделать. Типа - вот отсюда начинается много-процессный кусок, считать его 2-4-8-ю ядрами, вот здесь - конец куска.
← →
Дмитрий Белькевич (2010-11-11 22:59) [208]>"надпроцессные"
читать - надпроцессорные. или надядерные.
← →
Pavia © (2010-11-11 23:02) [209]
> Вообще, возможно были бы интересны некие "надпроцессные"
> команды. Т.е. такой расширенный набор надпроцессных команд,
> который бы помогал параллелить код. Думается, что тут со
> стороны железа можно было что-то сделать. Типа - вот отсюда
> начинается много-процессный кусок, считать его 2-4-8-ю ядрами,
> вот здесь - конец куска.
Уже существу причем как 10 лет. 10 лет по компьютерным меркам эпоха. Называется OpenMP. Но правда доступен для C++ и ряда других языков в которые Delphi не входит.
← →
_oxffff (2010-11-11 23:05) [210]
> Дмитрий Белькевич (11.11.10 22:58) [207]
Зачем? Есть VLIW.
Эльбрус. Itanium
← →
Дмитрий Белькевич (2010-11-11 23:07) [211]Ну, OpenMP это, как я понял, софтверные надстройки над уже имеющимся железом. Больше интересны железячные надстройки.
← →
Дмитрий Белькевич (2010-11-11 23:10) [212]
> Эльбрус. Itanium
На x86 бы, остальное экзотично и неитересно.
← →
Дмитрий Белькевич (2010-11-11 23:12) [213]Я понимаю, что, по хорошему, нужно глобально всю компьютерную архитектуру менять. Но, давайте будет реалистами, этого никто не сможет и не будет делать. По крайней мере, до появления 100% работоспособных эмуляторов винтела.
← →
Pavia © (2010-11-11 23:28) [214]Все мультимедийные расширения такими являлись.
Pentium ввели парализация исполнения команд. Два ALU
Pentium II ввели MMX. Одна команда обрабатывает вектор данных. 8 байт или 4 Word или 2 int. Тут вопрос в том как считать это одно алу обрабатывает или 8, 4, 2 ? Интел считает что одно. А некоторые разработчики считают что это 2,4,8 ядер!
Дальше парализация шла также.
Pentium III SSE регистр стал 128битным те поддерживают в 2 раза больше данных.
Pentium 4. Просто подняли скорость. Но разрешили на одном такте выполнять несколько команд.
Зато AMD пошла известным путем больше регистр больше данных можно обрабатывать. И ввела 256битные регистры.
← →
DiamondShark © (2010-11-11 23:40) [215]
> Я понимаю, что, по хорошему, нужно глобально всю компьютерную
> архитектуру менять.
Зачем менять?
Разработки процессоров, языков, компиляторов и ОС должны быть согласованы.
Вот это и будет реализм.
← →
Игорь Шевченко © (2010-11-12 00:09) [216]Pavia © (11.11.10 23:28) [214]
Изучай http://www.intel.com/Assets/PDF/manual/253665.pdf
← →
Pavia © (2010-11-12 00:22) [217]
> Игорь Шевченко © (12.11.10 00:09) [216]
> Pavia © (11.11.10 23:28) [214] Изучай http://www.intel.
> com/Assets/PDF/manual/253665.pdf
От предыдущего издания сильно отличается?
← →
Игорь Шевченко © (2010-11-12 00:30) [218]Pavia © (12.11.10 00:22) [217]
История изменений архитектуры - вряд ли :)
← →
Mystic © (2010-11-12 10:20) [219]
> Вводить отношения между функциями из вида в вида сложно(с
> ограничениями) если вообще возможно . Поскольку для
> одних параметров они коварианты, для других контвариантны,
> для других инварианты.
Ну вот в Ada нужно все это описать. Мне этот подход нравится больше, потому что накрывает самый часто используемый случай, оставляя в стороне всякие запутанные вещи.
← →
oxffff © (2010-11-12 10:47) [220]
> Mystic © (12.11.10 10:20) [219]
>
> > Вводить отношения между функциями из вида в вида сложно(с
>
> > ограничениями) если вообще возможно . Поскольку для
> > одних параметров они коварианты, для других контвариантны,
>
> > для других инварианты.
>
>
> Ну вот в Ada нужно все это описать. Мне этот подход нравится
> больше, потому что накрывает самый часто используемый случай,
> оставляя в стороне всякие запутанные вещи.
Например
То есть видовая функция T->U из типа в типа(читай параметризованный тип).
Есть две реализации этого вида. Например
ParametrizedClassA<T>=inteface
A:T;
function (a:T):integer;
end;
ParametrizedClassB<T>=inteface
A:T;
function (a:T):integer;
end;
ParametrizedClassС<T>=record
A:T;
function (a:T):integer;
end;
Есть еще параметризованный тип:
TemplateMain<A,B, C(T->U),D(T->U))=class
a:C<A>;
b:D;
{
a:=b <-Как проверить, что это безопасно?
}
end;
Для
TemplateMain<Tform,TControl,ParametrizedClassA,ParametrizedClassB> это безопасно.
А для
TemplateMain<TControl,Tform,ParametrizedClassA,ParametrizedClassB> это ошибка.
И для
TemplateMain<TControl,Tform,ParametrizedClassA,ParametrizedClassC> это ошибка.
Как задать такое в Ada(написать отношения между функциями из типа в тип например)?
Мне представляется, что никак.
← →
oxffff © (2010-11-12 10:49) [221]Есть еще параметризованный тип:
TemplateMain<A,B, C(T->U),D(T->U))=class
a:C < A >;
b:D < B >;
{
a:=b <-Как проверить, что это безопасно?
}
end;
Для
TemplateMain<Tform,TControl,ParametrizedClassA,ParametrizedClassB> это безопасно.
А для
TemplateMain<TControl,Tform,ParametrizedClassA,ParametrizedClassB> это ошибка.
И для
TemplateMain<TControl,Tform,ParametrizedClassA,ParametrizedClassC> это ошибка.
Как задать такое в Ada(написать отношения между функциями из типа в тип например)?
Мне представляется, что никак.
← →
Вариант (2010-11-12 11:52) [222]
> oxffff © (12.11.10 10:49) [221]
Когда в ада создается (описывается) какой-либо новый тип - программист обязан написать все необходимые преобразования нового типа в другие. Если преобразования не существует - то это не пройдет на этапе компилятора. Если тип является наследуемым(подтипом), то он может и унаследовать существующие правила преобразования. А потому в ADA95 (2005 не знаю) преобразование типа в тип безопасно - компилятор не пропустит, если нет правила преобразования
← →
Mystic © (2010-11-12 12:09) [223]Что мешает для этой операции присваивания определить специальную функцию, которую нужно будет описывать руками?
Вообще, пример достаточно мутный, если честно.
← →
Mystic © (2010-11-12 12:12) [224]
a = b;
По сути этоA& operator = (A& a, const B& b) { /* ... */ }
Что мешает дополнить шаблон явным указанием такой функции?
← →
oxffff © (2010-11-12 12:17) [225]
> Вариант (12.11.10 11:52) [222]
Между конкретным типом(integer,Tlist<integer>) и просто функцией из типа в тип(TList<>) есть разница.
Generic Ada не позволяет принимать качестве параметра другой generics, только конкретный тип, либо экземпляр другого generic"а, но не сам generic.
Так что Ada generics не являются аналогом С++ templates.
← →
Mystic © (2010-11-12 12:25) [226]
> Generic Ada не позволяет принимать качестве параметра другой
> generics, только конкретный тип, либо экземпляр другого
> generic"а, но не сам generic.
> Так что Ada generics не являются аналогом С++ templates.
Что мешает его явно описать и передать?
generic
type Element is private;
package XXX is
type ElementArray is array(1..200) of Element;
private
-- implementation
end Stacks;
и потом
package YYY is new XXX(Element => Boolean);
package ZZZ is new XXX(Element => YYY.ElementArray);
← →
oxffff © (2010-11-12 12:26) [227]
> Mystic © (12.11.10 12:12) [224]
> a = b;
>
> По сути это
>
> A& operator = (A& a, const B& b) { /* ... */ }
>
> Что мешает дополнить шаблон явным указанием такой функции?
>
В С++ шаблоны можно передевать в качестве параметра другие шаблоны. А поскольку шаблон является параметром шаблона проверить его в использующем шаблоне нельзя пока не будет предоставлено его тело(инстанцирование шаблона)
Еще раз
Два шаблона
ParametrizedType1<T>=inteface
...
end;
ParametrizedType2<T>=inteface
....
end;
Шаблон принимающий другие шаблоны.
MainClass<typeparam, templateparam1,templateparam2>=class
{
a:templateparam1<typeparam>; <- это некий тип построен по шаблону параметру templateparam1
b:templateparam2<integer>; <- это некий другой тип построен по шаблону параметру templateparam2
}
a:=b; <- нельзя проверить поскольку шаблоны параметры неизвестны(здесь нет их тела!!!)
end
Однако теперь проверить можно
MainClass<integer,ParametrizedType1,ParametrizedType2>
поскольку теперь известно тело типа.
a:ParametrizedType1<typeparam>
b:ParametrizedType1<integer>
Так понятней? :)
← →
oxffff © (2010-11-12 12:27) [228]
> a:ParametrizedType1<typeparam>
> b:ParametrizedType1<integer>
a:ParametrizedType1<typeparam>
b:ParametrizedType2<integer>
← →
Вариант (2010-11-12 12:29) [229]
> oxffff © (12.11.10 12:17) [225]
Абстрактный тип - так это называется в ADA95. Аналогом чего-либо в с++ не является. Не может быть использован явно, только для порождения других типов. (с этим и не спорят) -
Преобразования порожденных типов в другие типы является безопасным см[222] - это ответ на вопрос
> oxffff © (12.11.10 10:47) [220]
> {
> a:=b <-Как проверить, что это безопасно?
> }
← →
oxffff © (2010-11-12 12:32) [230]
> Mystic © (12.11.10 12:25) [226]
>
> > Generic Ada не позволяет принимать качестве параметра
> другой
> > generics, только конкретный тип, либо экземпляр другого
>
> > generic"а, но не сам generic.
> > Так что Ada generics не являются аналогом С++ templates.
>
>
>
> Что мешает его явно описать и передать?
>
>
> generic
> type Element is private;
>
> package XXX is
> type ElementArray is array(1..200) of Element;
> private
> -- implementation
> end Stacks;
>
> и потом
>
>
> package YYY is new XXX(Element => Boolean);
> package ZZZ is new XXX(Element => YYY.ElementArray);
Это не аналогичный финт. Поскольку ZZZ интанцируется уже готовым типом,
но вот так(я не знаю синтасис. Учусь по твоему примеру)
generic
type Element is private;
package XXX is
is new Element(integer);
....
generic
type Element is private;
package YYY is
....
package ZZZ is new XXX(YYY);
но вот так в Ada нельзя. А в С++ можно.
← →
oxffff © (2010-11-12 12:33) [231]
> Вариант (12.11.10 12:29) [229]
>
> > oxffff © (12.11.10 12:17) [225]
>
> Абстрактный тип - так это называется в ADA95. Аналогом
> чего-либо в с++ не является. Не может быть использован явно,
> только для порождения других типов. (с этим и не спорят)
> -
> Преобразования порожденных типов в другие типы является
> безопасным см[222] - это ответ на вопрос
>
> > oxffff © (12.11.10 10:47) [220]
>
>
>
> > {
> > a:=b <-Как проверить, что это безопасно?
> > }
Твой ответ неверный. Перечитай еще раз.
← →
Mystic © (2010-11-12 12:34) [232]
>
> В С++ шаблоны можно передевать в качестве параметра другие
> шаблоны. А поскольку шаблон является параметром шаблона
> проверить его в использующем шаблоне нельзя пока не будет
> предоставлено его тело(инстанцирование шаблона)
Проведи инстанцирование ручками и передай полученный тип в качестве параметра... В C++ typedef это не определение типа и не приводит к инстанцированию. Но в Ada это же не так.
← →
Mystic © (2010-11-12 12:38) [233]
> package ZZZ is new XXX(YYY);
> но вот так в Ada нельзя. А в С++ можно.
Я и говорю, что это легко можно обойти, напрямую ручками перечислив все фичи YYY, которые используются в XXX.
← →
oxffff © (2010-11-12 12:40) [234]
> Mystic © (12.11.10 12:34) [232]
>
> >
> > В С++ шаблоны можно передевать в качестве параметра другие
>
> > шаблоны. А поскольку шаблон является параметром шаблона
>
> > проверить его в использующем шаблоне нельзя пока не будет
>
> > предоставлено его тело(инстанцирование шаблона)
>
>
> Проведи инстанцирование ручками и передай полученный тип
> в качестве параметра... В C++ typedef это не определение
> типа и не приводит к инстанцированию. Но в Ada это же не
> так.
Это ограничение позволяет проверять типы в теле generic.
Но не позволяет достраивать(изменять) тело шаблона в момент его инстанцирования. Это все приводит к тому что для generics выводят некий общий интерфейс которому все соответствует и работают с ним. А в С++ получается duck typying(привет Alkid"у).
← →
Вариант (2010-11-12 12:43) [235]
> oxffff © (12.11.10 12:33) [231]
Ада, язык, типы - сильно отличаются от дельфи или с#. Там упор сделан на безопасности программировании, вылавливании блох на этапе компиляции. А потому правильней сказать что вопрос в [220] по отношению к ADA неверный - преобразование типов всегда будет безопасным, допустимым - ибо его прописали. Если нет преобразования, то это не пройдет на этапе компиляции. И проверять тип будет компилятор на этапе компиляции, а не на этапе выполнения программы
← →
Mystic © (2010-11-12 12:49) [236]
> Но не позволяет достраивать(изменять) тело шаблона в момент
> его инстанцирования. Это все приводит к тому что для generics
> выводят некий общий интерфейс которому все соответствует
> и работают с ним. А в С++ получается duck typying(привет
> Alkid"у).
Ну все это можно обойти :) Например:
template<typename X>
class Y
{
X x;
public:
Y(): x() { x.init(); }
}
Тут мы не можем узнать, имеет ли тип x метод init с нужной сигнатурой, можем проверить только на этапе инстанцирования (duck typing). Но что мешает поступить так?
generic
type X is private;
with procedure Init_X(Arg_X: X);
package ...
Т. е. нам надо будет указывать руками дополнительно функцию, которую мы хотим использовать в качестве функции init.
← →
oxffff © (2010-11-12 12:52) [237]
> Mystic © (12.11.10 12:38) [233]
>
> > package ZZZ is new XXX(YYY);
> > но вот так в Ada нельзя. А в С++ можно.
>
>
> Я и говорю, что это легко можно обойти, напрямую ручками
> перечислив все фичи YYY, которые используются в XXX.
Это не совсем так. То есть для того чтобы это обойти придется городить общий для всех таких разновидностей YYA,YYB,YYC.. некий общий интерфейс YYY, через который по факту будет происходить вызов.
Поэтому .NET C# generics на параметрами типами можно производить только
операции присваивания, все остальное (+,-,*,/ ,сравнения) через общий интерфейс. Например такой IComparer<T,Z>=function (left:T;right:Z):boolean;
Но вот тут начинаются настоящие грабли.
Дано:
generic<T,Z,comparer<T,Z>) Z:T;
{
a:T;
b:Z;
a:=b;
adder(a,b);
}
Экземпляр
<Tcontrol,Tform,Unicomparer>
перегрузка неразрешима и придется делать так
Unicomparer(a:Tobject,b:Form)
{
if a is TWinControl and b is Tform1 then
.....
begin
end
else
if a is TGraphicControland b is Tform1 then
...
........
}
А это проблема!!!!!
← →
Mystic © (2010-11-12 13:02) [238]
> oxffff © (12.11.10 12:52) [237]
generic
type X is private;
type Y is private;
package Unicomparer
procedure Something(Arg_X: X; Arg_Y: Y);
-- .......
Далее
generic
type X is private;
type Y is private;
with procedure Something(Arg_X: X; Arg_Y: Y);
package DifficultCase
-- ...
Ну и в коде
package ComparerForm is new Unicomparer(X => TControl, Y => TForm);
package ExtraDifficultCase is new DifficultCase(X => TControl, Y => TForm; Something = ComparerForm.Something);
← →
Какой кыашмар (2010-11-12 14:17) [239]Дмитрий Белькевич (10.11.10 12:51) [66]
> Вообще, я, по одной из специальностей, инженер-электронщик.
> Я как бы в курсе :) Что для чайников и утюгов и прочих
> свистоперделок выпускается множество всякого.
Я Вам по секрету скажу, как инжинер инженеру. Архитектуры x86 уже нету, давно. С выхода P4, ага. Система команд x86 эмулируется. Вот такой вот интерпретатор встроен в процессор, который преобразует x86-фигню в удобоваримый набор инструкций. На IA-64 уже свой набор инструкций, доступный программисту и компилятору. И присобаченный эмулятор для разбора x86-фигни. Тока работает он в режиме эмуляции x86 куда медленней. Не за горами момент когда эту обузу - поддержку x86-совместимости - отправят на свалку истории.
← →
Anatoly Podgoretsky © (2010-11-12 14:26) [240]> Какой кыашмар (12.11.2010 14:17:59) [239]
В пользу простых, симметричных инструкций, без команд умножения/деления.
← →
oxffff © (2010-11-12 14:53) [241]
> Mystic © (12.11.10 13:02) [238]
>
> > oxffff © (12.11.10 12:52) [237]
>
>
>
> generic
> type X is private;
> type Y is private;
> package Unicomparer
> procedure Something(Arg_X: X; Arg_Y: Y);
> -- .......
>
>
> Далее
>
>
> generic
> type X is private;
> type Y is private;
> with procedure Something(Arg_X: X; Arg_Y: Y);
> package DifficultCase
> -- ...
>
>
> Ну и в коде
>
>
> package ComparerForm is new Unicomparer(X => TControl,
> Y => TForm);
> package ExtraDifficultCase is new DifficultCase(X => TControl,
> Y => TForm; Something = ComparerForm.Something);
Не принимается. :)
Хех. Насколько я понял из этого кода это специализация конкретных типов конкретным comparerом. Причем для каждой пары все это делается ручками программистом, а не компилятором.
Это извините совершенно не обобщенное программирование, а сплошное "специализирование".
← →
Какой кыашмар (2010-11-12 15:14) [242]
> Anatoly Podgoretsky © (12.11.10 14:26) [240]
> В пользу простых, симметричных инструкций, без команд умножения/деления.
Или наоборот. Не, ну в ядре процессора - однозначно квази-RISK. А вот снаружи запросто что-то высокоуровневое может встрять. Плюс отдельное ядро для сборщика мусора - и goodbye, unmanaged :)
← →
Какой кыашмар (2010-11-12 15:18) [243]
> С выхода P4, ага.
Это я конечно просвистел. По факту в первом пентюхе уже мало что от x86 осталось.
← →
Mystic © (2010-11-12 16:03) [244]
> Хех. Насколько я понял из этого кода это специализация конкретных
> типов конкретным comparerом. Причем для каждой пары все
> это делается ручками программистом, а не компилятором.
> Это извините совершенно не обобщенное программирование,
> а сплошное "специализирование".
По мощности тоже самое, только надо чуть больше уточнений прописывать руками. 90% основных потребностей в шаблонах это накрывает. А если говорить об оставшихся экзотических 10%, то это можно сделать руками. Хуже, когда основное внимание уделяется экзотическим 10% случаев, из-за которых страдают 90% остальных (например, невозможность проверить шаблон на этапе компиляции, дикие ошибки при инстанцировании в несколько строчек со всеми кишками). А тут все просто: имеет процедура Something неправильную сигнатуру, тут же в строкеpackage ExtraDifficultCase is new DifficultCase(X => TControl,
> Y => TForm; Something = ComparerForm.Something);
это выяснится, да еще и с указанием, где конкретно что не так :)
← →
oxffff © (2010-11-12 16:15) [245]
> Mystic © (12.11.10 16:03) [244]
С возрастанием числа параметров сложность возрастает. Но тем не менее удобство generics неспорно.
:)
Я кстати долго вспоминал С++ космический код из
template<typename X>
class Y
{
X x;
public:
Y(): x() { x.init(); }
}
Никак не воспринимается эта конструкция. Хотя дело привычки.
Язык неплохой, но синтаксис ....
← →
Mystic © (2010-11-12 17:04) [246]> С возрастанием числа параметров сложность возрастает.
Что-то мне подсказывает, что с таким возрастанием параметров приближается пушной зверек. Скажем так, эта штука не для массового злоупотребления.
← →
_oxffff (2010-11-12 19:09) [247]
> Mystic © (12.11.10 17:04) [246]
Тем не менее template позволяют сделать работу за программиста, в то время как с generics специалисту придется выполнять работу самому.
Поэтому возможности template шире generics. Мы еще не рассматривали в качестве параметров константы. :)
← →
Mystic © (2010-11-12 19:15) [248]
> Мы еще не рассматривали в качестве параметров константы.
> :)
Легко:generic
type Element is private;
Size: Positive := 200;
package Stacks is
-- ...
Вот что допустимо в Ada из классов:
type T is limited private -- тип T - любой тип
type T is private -- тип T - любой не лимитированный тип
type T is (<>) -- тип T любой дискретный тип
-- (целочисленный или перечислимый)
type T is range <> -- тип T любой целочисленный тип
type T is mod <> -- тип T любой модульный целочисленный тип
type T is digits <> -- тип T любой вещественный тип с плавающей точкой
type T is delta <> -- тип T любой вещественный тип с фиксированной точкой
type T is delta <> digits <> -- тип T любой вещественный децимальный тип
type T is access Y; -- тип T любой ссылающийся на Y ссылочный тип
type T is access all Y; -- тип T любой "access all Y" ссылочный тип
type T is access constant Y; -- тип T любой "access constant Y" ссылочный тип
-- примечание: тип Y может быть предварительно описанным
-- настраиваемым параметром
type T is array(Y range <>) of Z; -- тип T любой неограниченный массив элементов типа Z
-- у которого Y - подтип индекса
type T is array(Y) of Z; -- тип T любой ограниченный массив элементов типа Z
-- у которого Y - подтип индекса
type T is new Y; -- тип T любой производный от Y тип
type T is new Y with private; -- тип T любой не абстрактный тэговый тип
-- производный от Y
type T is abstract new Y with private; -- тип T любой тэговый тип производный от Y
type T is tagged private; -- тип T любой не абстрактный не лимитированый
-- тэговый тип
type T is tagged limited private; -- тип T любой не абстрактный тэговый тип
type T is abstract tagged private; -- тип T любой не лимитированый тэговый тип
type T is abstract tagged limited private; -- тип T любой тэговый тип
← →
_oxffff (2010-11-12 19:22) [249]
> Mystic © (12.11.10 19:15) [248]
То есть ты продолжаешь считать, что выразительность generics наравне c templates?
← →
_oxffff (2010-11-12 19:26) [250]
> Mystic © (12.11.10 19:15) [248]
И тебя совершенно не смущает, что c generics тебе придется часть обобщать вручную сложные вещи.
2 года назад я дискутировал на эту тему в комментариях у Craig Stuntz
http://blogs.teamb.com/craigstuntz/2008/08/29/37832
Представь себе обобщенное выражение
(U+T*Z-V*10*(cast to V) (U.Stuff(Z*E)))/U
С generics программисту придется разобрать это выражение и задать все ограничения и все обобщенные операторы самому. С template этого делать не нужно. Хочешь разобрать его вручную?
← →
_oxffff (2010-11-12 19:39) [251]
> Mystic © (12.11.10 19:15) [248]
Я поклонник обобщенного программирования, однако
-мощность template сводит на нет поиски ошибки в ней,
-безопасность generics сводит на нет необходимость делать часть работы за компилятор и сопутствующие задержки в вызове обобщенных операторов.
:)
← →
Mystic © (2010-11-12 19:46) [252]
> То есть ты продолжаешь считать, что выразительность generics
> наравне c templates?
Мне больше импонирует строгий адский синтаксис, чем C++ ный. Пусть там и больше букв :) По возможностям они менее-более одинаковы. В Ada больше тавтологии в том, что надо все прописать руками. В C++ больше тавтологии в том, что generic в Ada относится к пакету (package, модуль, аналог Delphi-йского uint), а в C++ template относится к классу или функции (ибо модулей нет), поэтому иногда приходится дублировать описания типов в каждом классе. Например, если у меня есть шаблонный параметр типа T, то я могу в самом пакете один раз определить массив объектов типа T, и потом его юзать во всем коде модуля. А в C++ мне надо будет писать template<typename T> буквально перед каждым классом и шаблоном. Например, в хидере <vector> от M$ строка "typedef typename _Alloc::difference_type " встречается четыре раза. Два раза (vector const iterator и vector iterator) встречается_Myt& operator-=(difference_type _Off)
{ // decrement by integer
return (*this += -_Off);
}
← →
Mystic © (2010-11-12 19:55) [253]
> Представь себе обобщенное выражение
>
> (U+T*Z-V*10*(cast to V) (U.Stuff(Z*E)))/U
>
> С generics программисту придется разобрать это выражение
> и задать все ограничения и все обобщенные операторы самому.
> С template этого делать не нужно. Хочешь разобрать его
> вручную?
Я не вижу смысла в этом выражении. Это некая абстракция. Более того, как это происходит в C++? Я в таких выражениях я как минимум в половине случаев допускаю опечатки, ошибки, мне выдает компилятор сообщение об ошибке на пару экранов. Я матерюсь, и все равно разбираю все вручную. Точнее, любуюсь на текст вродеtypename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const _Key&) [with _Key = unsigned int, _Tp = phrase_info_t, _Compare = std::less<unsigned int>, _Alloc = std::allocator<std::pair<const unsigned int, phrase_info_t> >]
потом копирую текст ошибки в notepad, там его привожу к нормальному виду, смотрю чего не хватает, исправляю, иду дальше. И мне кажется, это занимает куда больше времени, чем описать вручную, что откуда надо брать, да и вероятность ошибки при этом меньше. А если приходится возвращаться к написанному ранее коду, то это сразу вгоняет меня в состояние вселенской тоски и депрессии :)
← →
Игорь Шевченко © (2010-11-12 19:55) [254]Какой кыашмар (12.11.10 15:18) [243]
Как бы ни Пентиум, ни Пентиум 4 не IA-64 ни разу.
Потому трындеть про "давно отсутствует архитектура x86" можно, но бессмысленно.
← →
Какой кыашмар (2010-11-12 21:40) [255]
> Как бы ни Пентиум, ни Пентиум 4 не IA-64 ни разу.
Сам-то понял, чё сказал?
> Потому трындеть про "давно отсутствует архитектура x86"
> можно, но бессмысленно.
Ну дык и не трынди.
← →
DiamondShark © (2010-11-12 21:44) [256]
> Я поклонник обобщенного программирования
Есть языки, на которые обобщённое программирование ложится более естественно.
Например, в функциональных языках с автоматическим выводом типов обобщённое программирование получается "даром", т.е. вообще без каких-либо специальных синтаксических примочек.
← →
_oxffff (2010-11-12 21:58) [257]
> Mystic © (12.11.10 19:46) [252]
>
> > То есть ты продолжаешь считать, что выразительность generics
>
> > наравне c templates?
>
>
> Мне больше импонирует строгий адский синтаксис, чем C++
> ный. Пусть там и больше букв :) По возможностям они менее-
> более одинаковы.
Тогда и с машинными кодами по возможностям одинаковые. Букв чуть больше.
:)
← →
TUser © (2010-11-12 22:00) [258]Читаю тут:
М.В.Мозговой. Алгоритмы, языки, автоматы, компиляторы. 2006.
С. 101: "на любую хорошую идею найдется неприятность в виде слишком рьяных последователей"
Это автор про парадигмы программирования, струтурное, объектно-ориентированное, автоматное ...
Нуи до кучи
- всякий овощ ...
- любую идею можно довести до состояния абсолютного идиотизма
- и т.д.
← →
DiamondShark © (2010-11-12 22:11) [259]
> - любую идею можно довести до состояния абсолютного идиотизма
Интересно, можно ли довести до состояния абсолютного идиотизма идею о том, что любую идею можно довести до состояния абсолютного идиотизма?
← →
_oxffff (2010-11-12 22:26) [260]
> DiamondShark © (12.11.10 22:11) [259]
>
> > - любую идею можно довести до состояния абсолютного идиотизма
>
> Интересно, можно ли довести до состояния абсолютного идиотизма
> идею о том, что любую идею можно довести до состояния абсолютного
> идиотизма?
Есть в теории типов "Про рекурсивные типы". Это туда.
← →
Игорь Шевченко © (2010-11-12 22:33) [261]Какой кыашмар (12.11.10 21:40) [255]
Я тут ссылку давал на интеловскую доку, читай, воздастся и тебе
← →
Дмитрий Белькевич (2010-11-13 00:47) [262]
> Система команд x86 эмулируется
Ну, вообще, это для меня не новость, токо не с P4, а уже давно.
> Не за горами момент когда эту обузу - поддержку x86-совместимости
> - отправят на свалку истории.
Оптимистично, но не реалистично.
>Это я конечно просвистел. По факту в первом пентюхе уже мало что от x86 осталось.
А наружу всё равно торчит х86, странно, да?
>С. 101: "на любую хорошую идею найдется неприятность в виде слишком рьяных последователей"
Ну, не знаю. На Delphi почему-то какой-то особенной неприятности не замечено. Все нормальные библиотеки написаны более-менее единообразно. Шаблонов в Delphi, к счастью, нету. Шаблонной каши - тоже.
← →
Какой кыашмар (2010-11-13 06:05) [263]
> Игорь Шевченко © (12.11.10 22:33) [261]
> Я тут ссылку давал на интеловскую доку, читай, воздастся
> и тебе
Я тех доков начитался по немогу, так что сам почитай.
Во-первых, пальцем покажи, гдя я говорил что IA-64 это пентиум.
Дальче, пентиум - суперскаляр, хоть и с покоцанной суперскалярностью. Какое нафиг отношение к этому имеет x86, кроме сэмулированной системы команд? Разница в архитектуре между IA-64 и пеннтюхом куда меньше, чем между пентюхом и 386-486. По архитектуре она скорее количественная, чем качественная - больше конвейеров, больше одинаковых функциональных блоков, собственная более развитая система команд - и благодаря отказу от прямой поддержки опкодов x86 тоже.
← →
Какой кыашмар (2010-11-13 06:12) [264]
> А наружу всё равно торчит х86, странно, да?
Ты лучше вспомни, когда он вышел, и странно не будет. А потом подумай, почему в IA-64 эта эмуляция сбоку, и какой следующий шаг.
Производители давно считают опкоды x86 тормозом. Да для этого и не надо быть разработчиком процессоров, чтобы понять что в суперскалярность x86 хреново вписывается.
← →
Дмитрий Белькевич (2010-11-13 12:23) [265]
> Ты лучше вспомни, когда он вышел, и странно не будет
Так для меня этот как раз таки не странно. Всё логично и объяснимо. Удивиться должен ты, ведь это ты утверждаешь, что x86 скоро умрёт. Однако его давно и упорно эмулируют.
> А потом подумай, почему в IA-64 эта эмуляция сбоку
Да. И где этот IA 64? Загляни на свалку истории - там много интересного.
> Производители давно считают опкоды x86 тормозом. Да для
> этого и не надо быть разработчиком процессоров, чтобы понять
> что в суперскалярность x86 хреново вписывается.
Ну так я же не спорю с тем, что х86 морально устарел уже тогда, когда его начали эмулировать. Да, тормоз, да хреново вписывается. Но - так уж случилось, и это изменить очень сложно, читай - дорого. Но и делать с этим, уже имеющимся, "счастьем" что-то нужно.
← →
euru © (2010-11-13 12:47) [266]
> oxffff © (12.11.10 14:53) [241]
> Не принимается.
> :)Хех. Насколько я понял из этого кода это
> специализация конкретных типов конкретным comparerом. Причем
> для каждой пары все это делается ручками программистом,
> а не компилятором. Это извините совершенно не обобщенное
> программирование, а сплошное "специализирование".
Значит, в случае сборки мусора вы не доверяете ЯП и среде выполнения и настаиваете на сборке руками программиста, что не гарантирует корректности работы программы.
А в случае с шаблонами вы требуете от ЯП того, что и программист-то не сможет выполнить.
Странно как-то это.
← →
DiamondShark © (2010-11-13 14:01) [267]
> Ну так я же не спорю с тем, что х86 морально устарел уже
> тогда, когда его начали эмулировать.
х86 морально устарел уже тогда, когда его только начали выпускать.
← →
oxffff © (2010-11-13 14:21) [268]
> euru © (13.11.10 12:47) [266]
>
> > oxffff © (12.11.10 14:53) [241]
> > Не принимается.
> > :)Хех. Насколько я понял из этого кода это
> > специализация конкретных типов конкретным comparerом.
> Причем
> > для каждой пары все это делается ручками программистом,
>
> > а не компилятором. Это извините совершенно не обобщенное
>
> > программирование, а сплошное "специализирование".
>
> Значит, в случае сборки мусора вы не доверяете ЯП и среде
> выполнения и настаиваете на сборке руками программиста,
> что не гарантирует корректности работы программы.
> А в случае с шаблонами вы требуете от ЯП того, что и программист-
> то не сможет выполнить.
> Странно как-то это.
Разве я где-то требовал? :)
1. Мне было бы интересно использовать гибридный способ управления ссылками на объекты кучи в одном языке.
Есть конечно Microsoft C++ /mixed.
Но он мне бы хотелось больше удобства и Паскалеподобности
2. Также бы мне хотелось совместить безопасность generics с мощностью templates. Например, чтобы ограничения (отношения между типами выводились автоматически, а не налагались программистом). Как вам?
Хотеть конечно не вредно. Но и не хотеть тоже.
← →
euru © (2010-11-13 15:40) [269]А какое имеют отношение детали реализации процессоров к ЯВУ?
← →
DiamondShark © (2010-11-13 17:41) [270]
> euru © (13.11.10 15:40) [269]
> А какое имеют отношение детали реализации процессоров к
> ЯВУ?
Есть мнение, что архитектура вычислительных систем должна проектироваться комплексно.
← →
Дмитрий Белькевич (2010-11-13 18:52) [271]
> х86 морально устарел уже тогда, когда его только начали
> выпускать.
Тогда было что-то лучшее за те же деньги?
← →
euru © (2010-11-15 10:12) [272]
> DiamondShark © (13.11.10 17:41) [270]
> Есть мнение, что архитектура вычислительных систем должна
> проектироваться комплексно.
Т.е. "серебряная пуля" всё-таки существует? И можно создать идеальный процессор, для которого можно создать универсальный идеальный язык программирования?
Или предполагается для каждого ЯВУ использовать специально для него разработанный процессор, учитывающий все особенности языка?
← →
euru © (2010-11-15 10:23) [273]
> oxffff © (13.11.10 14:21) [268]
> 1. Мне было бы интересно использовать гибридный способ управления
> ссылками на объекты кучи в одном языке.
А какие явные преимущества даёт такой способ управления? Мне также до сих пор непонятно назначение выраженияa := nil;
, если оно всё равно ничего не делает.
> 2. Также бы мне хотелось совместить безопасность generics
> с мощностью templates.
Есть предложения, как это можно сделать?
← →
oxffff © (2010-11-15 10:50) [274]
> euru © (15.11.10 10:23) [273]
>
> > oxffff © (13.11.10 14:21) [268]
>
> > 1. Мне было бы интересно использовать гибридный способ
> управления
> > ссылками на объекты кучи в одном языке.
>
> А какие явные преимущества даёт такой способ управления?
> Мне также до сих пор непонятно назначение выражения a :
> = nil;, если оно всё равно ничего не делает.
>
Это откуда a:=nil?
>
> > 2. Также бы мне хотелось совместить безопасность generics
>
> > с мощностью templates.
>
> Есть предложения, как это можно сделать?
В том или ином виде такой вывод делается программистом. Поэтому существует некий алгоритм как это делает человек.
Осталось его только формализовать и закодировать. По сути type checker при проверки типов, может устанавливать выводить отношения между левой и правой части при которых это выраженеи корректно. Например
U:=T; => T подтип U, либо есть ImplicitCast(T):U. вот Два ограничения.
Вы же это делаете явно для generics.
← →
euru © (2010-11-16 14:01) [275]
> oxffff © (15.11.10 10:50) [274]
> Это откуда a:=nil?
Если вкратце, то [121] [169] [171] [177].
> U:=T; => T подтип U, либо есть ImplicitCast(T):U. вот Два ограничения.
В принципе, я согласен, что в данном случае это можно было бы делать автоматически. Но, возможно, есть ситуации, когда такой вывод будет некорректен.
← →
oxffff © (2010-11-16 14:24) [276]
> euru © (16.11.10 14:01) [275]
>
> > oxffff © (15.11.10 10:50) [274]
> > Это откуда a:=nil?
>
> Если вкратце, то [121] [169] [171] [177].
Там был пример не мой. Я лишь пытался выяснить причину "паразита".
Как оказалось причины нет. Во всяком случае для меня нет сложности переписать код нормально в рамках обычной кучи.
Вопрос ко мне я не понял. Если можно повторить подробно и точно, чтобы не было раpночтений. Повторю, что мне интересен гибридный вариант управления кучами.
> > U:=T; => T подтип U, либо есть ImplicitCast(T):U. вот
> Два ограничения.
>
> В принципе, я согласен, что в данном случае это можно было
> бы делать автоматически. Но, возможно, есть ситуации, когда
> такой вывод будет некорректен.
Аналогично такую информацию можно вывести из примера.
T+U*Z-U.ABC(U,T).
То есть действительно это не будет тривиальная информация об отношениях в generics. Однако позволила бы выдать более понятную информацию. Например Отсутствует компонент abc у Tmytype принимающий integer и integer и возвращающий тип который бы удовлетворял оператору - принимающего этот тип и double и т.д. Хотя возможно оставить и ручное ограничение и автоматическое. Смысл в том, что информация об ошибке была понятна.
← →
oxffff © (2010-11-16 14:31) [277]
> Аналогично такую информацию можно вывести из примера.
> T+U*Z-U.ABC(U,T).
> То есть действительно это не будет тривиальная информация
> об отношениях в generics. Однако позволила бы выдать более
> понятную информацию. Например Отсутствует компонент abc
> у Tmytype принимающий integer и integer и возвращающий тип
> который бы удовлетворял оператору - принимающего этот тип
> и double и т.д. Хотя возможно оставить и ручное ограничение
> и автоматическое. Смысл в том, что информация об ошибке
> была понятна.
То есть по сути это был даг отношений между типами и их компонентами соответствующий обобщенному выражению.
← →
euru © (2010-11-23 17:36) [278]
> oxffff © (16.11.10 14:24) [276]
> Повторю, что мне интересен гибридный вариант управления
> кучами.
>Какие преимущества даёт такой вариант? Чем плох вариант, когда в языке вообще нет понятия кучи?
← →
DiamondShark © (2010-11-23 18:13) [279]> > U:=T; => T подтип U, либо есть ImplicitCast(T):U. вот
> Два ограничения.
>
> В принципе, я согласен, что в данном случае это можно было
> бы делать автоматически. Но, возможно, есть ситуации, когда
> такой вывод будет некорректен.
Это невозможно делать автоматически. Ограничения "T подтип U" и "есть ImplicitCast(T):U" -- семантически очень разные.
Компилятор не долен заниматься телепатией (из этого ничего хорошего не получается).
> Аналогично такую информацию можно вывести из примера.
> T+U*Z-U.ABC(U,T).
Здесь вообще туши свет.
В С++ любая часть этого выражения может означать ВООБЩЕ ВСЁ ЧТО УГОДНО. Да ещё и разные вещи в разных контекстах! Потому что "+", "*", "-", "( )" -- это всё перегружаемые операции. Из лексического анализа этого выражения ВООБЩЕ НЕЛЬЗЯ извлечь никакой информации, кроме того, что тут в данном месте стоят вот эти вот лексемы. Семантика этого выражения будет разной в разных контекстах, а контекст может быть в стопицотом по вложенности инклюде.
Плюсные шаблоны -- это ТЕКСТОВЫЕ макросы, в шаблоне вне контекста НЕТ СЕМАНТИКИ языка С++.
Шаблон -- это не код, не алгоритм. Это правило преобразования текста.
Шаблоны С++ -- это не часть языка С++, это погружённый в С++ ДРУГОЙ ЯЗЫК, язык описания преобразований исходных текстов С++.
Я же говорю: С++ проектировали шизофреники.
Генирики -- это, наоборот, семантически определённые, независимые, логически завершённые единцы кода. Они могут быть независимо скомпилированы, их семантика не зависит от контекста.
← →
_oxffff (2010-11-23 18:37) [280]
> euru © (23.11.10 17:36) [278]
>
> > oxffff © (16.11.10 14:24) [276]
> > Повторю, что мне интересен гибридный вариант управления
>
> > кучами.
>
> >Какие преимущества даёт такой вариант? Чем плох вариант,
> когда в языке вообще нет понятия кучи?
А что есть?
← →
_oxffff (2010-11-23 18:47) [281]
> DiamondShark © (23.11.10 18:13) [279]
> > > U:=T; => T подтип U, либо есть ImplicitCast(T):U. вот
>
> > Два ограничения.
> >
> > В принципе, я согласен, что в данном случае это можно
> было
> > бы делать автоматически. Но, возможно, есть ситуации,
> когда
> > такой вывод будет некорректен.
>
> Это невозможно делать автоматически. Ограничения "T подтип
> U" и "есть ImplicitCast(T):U" -- семантически очень разные.
>
> Компилятор не долен заниматься телепатией (из этого ничего
> хорошего не получается).
В нестрогих языках допустимо использование операция неявного преобразования при присвоении. В ней ничего плохого нет.
Если думать абстрактно, то это две "одинаковые операции"
позволяющие T трактовать как U.
>
>
> > Аналогично такую информацию можно вывести из примера.
> > T+U*Z-U.ABC(U,T).
>
> Здесь вообще туши свет.
> В С++ любая часть этого выражения может означать ВООБЩЕ
> ВСЁ ЧТО УГОДНО. Да ещё и разные вещи в разных контекстах!
> Потому что "+", "*", "-", "( )" -- это всё перегружаемые
> операции. Из лексического анализа этого выражения ВООБЩЕ
> НЕЛЬЗЯ извлечь никакой информации, кроме того, что тут в
> данном месте стоят вот эти вот лексемы. Семантика этого
> выражения будет разной в разных контекстах, а контекст может
> быть в стопицотом по вложенности инклюде.
>
Причем здесь анализаторы. Речь о следующей стандии после лексических и синтаксических анализаторах, а именно о семантическом анализе.
> Плюсные шаблоны -- это ТЕКСТОВЫЕ макросы, в шаблоне вне
> контекста НЕТ СЕМАНТИКИ языка С++.
И?
Templates C++ это параметризованные типы с разнородными параметрами без задания отношений между типами или функциями из типа в тип.
> Шаблон -- это не код, не алгоритм. Это правило преобразования
> текста.
> Шаблоны С++ -- это не часть языка С++, это погружённый в
> С++ ДРУГОЙ ЯЗЫК, язык описания преобразований исходных текстов
> С++.
>
> Я же говорю: С++ проектировали шизофреники.
>
> Генирики -- это, наоборот, семантически определённые, независимые,
> логически завершённые единцы кода. Они могут быть независимо
> скомпилированы, их семантика не зависит от контекста.
Знакомы с полиморфным лямбда исчислением?
Это два случая одного и того же.
← →
euru © (2010-11-24 01:36) [282]
> DiamondShark © (23.11.10 18:13) [279]
> Это невозможно делать автоматически. Ограничения "T подтип
> U" и "есть ImplicitCast(T):U" -- семантически очень разные.
> Компилятор не долен заниматься телепатией (из этого ничего
> хорошего не получается).
Почему невозможно? Это же взаимоисключающие условия: либо T - подтип U, либо T - не подтип U, но поддерживает операцию неявного привидения типа T к типу U.
← →
euru © (2010-11-24 01:52) [283]
> _oxffff (23.11.10 18:37) [280]
> А что есть?
Например, убрать из языка оператор new. Тогда, возможно, и dispose (или его аналоги) не понадобятся.
← →
euru © (2010-11-24 02:07) [284]
> _oxffff (23.11.10 18:47) [281]
> > > Аналогично такую информацию можно вывести из примера.
> > > T+U*Z-U.ABC(U,T).
> > Здесь вообще туши свет.
>
> Причем здесь анализаторы. Речь о следующей стандии после
> лексических и синтаксических анализаторах, а именно о семантическом
> анализе.
Если оператор *(U, Z) будет в обоих типах U и Z, то и семантический анализ не поможет однозначно выбрать нужный оператор.
← →
_oxffff (2010-11-24 08:32) [285]
> euru © (24.11.10 01:52) [283]
>
> > _oxffff (23.11.10 18:37) [280]
> > А что есть?
>
> Например, убрать из языка оператор new. Тогда, возможно,
> и dispose (или его аналоги) не понадобятся.
То есть нет объектов вне записи активации. Тогда все объекты будут вычищаться при финализации записи активации(по выходу из функции\процедуры\методу). То есть динамических структрур данных нет.
Только глобальные преопределенные объекты.
Суть примененения такого языка мне не понятна.
← →
_oxffff (2010-11-24 08:36) [286]
> euru © (24.11.10 02:07) [284]
>
> > _oxffff (23.11.10 18:47) [281]
> > > > Аналогично такую информацию можно вывести из примера.
>
> > > > T+U*Z-U.ABC(U,T).
> > > Здесь вообще туши свет.
> >
> > Причем здесь анализаторы. Речь о следующей стандии после
>
> > лексических и синтаксических анализаторах, а именно о
> семантическом
> > анализе.
>
> Если оператор *(U, Z) будет в обоих типах U и Z, то и семантический
> анализ не поможет однозначно выбрать нужный оператор.
1. Ничего страшного. Не все generics можно инстанцировать. Будет выведено сообщение о неоднозначности выбора при выборе оператора.
2. Современные языки отслеживают конфликты перегруженных операторов.
Поэтому сообщение об ошибке определения U и Z могут появиться еще до использования generics.
← →
euru © (2010-11-24 10:42) [287]
> _oxffff (24.11.10 08:32) [285]
> То есть нет объектов вне записи активации. Тогда все объекты
> будут вычищаться при финализации записи активации(по выходу
> из функции\процедуры\методу). То есть динамических структрур
> данных нет. Только глобальные преопределенные объекты.
Если в языке нет явных конструкций для работы с динамическими структурами, то это не означает, что такая возможность не может существовать неявно.
Примеры: массивы в Бейсике, строки в Паскале.
← →
euru © (2010-11-24 11:06) [288]
> _oxffff (24.11.10 08:36) [286]
> 1. Ничего страшного. Не все generics можно инстанцировать.
> Будет выведено сообщение о неоднозначности выбора при выборе
> оператора.2. Современные языки отслеживают конфликты перегруженных
> операторов.Поэтому сообщение об ошибке определения U и Z
> могут появиться еще до использования generics.
Допустим, есть два класса:class U
{
int operator *(U value1, Z value2)
{
return 1;
}
}
class Z
{
int operator *(U value1, Z value2)
{
return 2;
}
}
Далее определим ещё один класс:class A<T>
{
U field1 = new U();
T field2;
int field3;
A(T field)
{
field2 = field;
field3 = field1 * field2;
}
}
И где-то дальше в коде определим переменную:A<Z> a = new A<Z>(new Z());
Какое сообщение должен выдать компилятор, чтобы разработчику было понятно, почему его код не компилируется?
← →
DiamondShark © (2010-11-24 11:08) [289]
> Почему невозможно? Это же взаимоисключающие условия: либо
> T - подтип U, либо T - не подтип U, но поддерживает операцию
> неявного привидения типа T к типу U.
Потому что есть три возможности сгенерировать констрейнт
- (T is U)
- (ImplicitCast(T):U)
- (T is U) or (ImplicitCast(T):U)
Компилятор не должен угадывать, что имел в виду пользователь.
> 2. Современные языки отслеживают конфликты перегруженных
> операторов.
Эти перегрузки могут быть описаны в разных библиотеках.
Эти перегрузки могут быть вообще не известны на момент компиляции определения генерика.
Генерики должны обеспечивать возможность независимой компиляции, что становится невозможным, если семантический анализ откладывается до момента инстанцирования.
С++ такими вещами не заморачивается, потому что в месте инстанцирования происходит ЛЕКСИЧЕСКАЯ подстановка, и сгенерированный код далее компилируется обычным образом.
Это, кстати, и обуславливает шизофреничность диагностики при ошибках инстанцирования, потому что ошибка возникает не в коде, написанном пользователем, а в сгенерированном коде, который существует только во внутреннем представлении компилятора, и, вообще говоря, не обязан иметь ОБРАТНОЕ отображение в пользовательский код.
← →
_oxffff (2010-11-24 11:10) [290]
> euru © (24.11.10 10:42) [287]
А разве строки и массивы в Pascal не имеют оператора New?
Имеют,но по другому называется и вызывается неявно Но смысл тот же.
Речь о том, как Вы собираетесь создать объект(аллокировать и инициализировать) и допустим детерминированно финализировать
без new, dispose?
Можно синтаксис и семантику?
← →
DiamondShark © (2010-11-24 11:36) [291]
> А разве строки и массивы в Pascal не имеют оператора New?
Строки и массивы в Pascal не имеют оператора New. Это value-типы.
> Можно синтаксис и семантику?
Легко.
Все типы языка -- value-типы. Есть специальный тип reference.
Экземпляр value-типа жив пока жива хоть одна reference на него.
Пример.
type
MyRecord = record
a,b,c : integer;
end;
procedure Foo() : reference to MyRecord;
var
r: MyRecord;
begin
r.a := 1;
r.b := 2;
r.c := 3;
return @r;
end;
procedure Bar() : MyRecord;
var
r: MyRecord;
begin
r.a := 1;
r.b := 2;
r.c := 3;
return r;
end;
procedure Main;
var
r: MyRecord;
rr: reference to MyRecord;
begin
rr := Foo(); // динамический экземпляр
r := Bar(); // копирование
rr := nil; // удаление
end;
Никаких new|dispose
← →
euru © (2010-11-24 11:48) [292]
> DiamondShark © (24.11.10 11:08) [289]
> Компилятор не должен угадывать, что имел в виду пользователь.
Пользователь имел в виду возможность преобразования типа T в тип U.
Компилятору оба типа известны. Если U - базовый тип для T, то используется преобразование (T is U). Если T и U - независимые типы, то проверяется наличие описания преобразования (ImplicitCast(T):U). Если такое преобразование есть, то оно выполняется, если нет - выдаётся сообщение об ошибке. Одновременное выполнение этих условий невозможно, потому что неявное преобразование в базовый класс/из базового класса запрещено (по крайней мере, в C#).
В каких тогда случаях может возникнуть неоднозначность?
> Эти перегрузки могут быть описаны в разных библиотеках.Эти
> перегрузки могут быть вообще не известны на момент компиляции
> определения генерика.Генерики должны обеспечивать возможность
> независимой компиляции, что становится невозможным, если
> семантический анализ откладывается до момента инстанцирования.
Если в библиотеках будет хранится информация не только о типах, но и об ограничениях, накладываемых на эти типы, то почему тогда невозможна независимая компиляция?
← →
euru © (2010-11-24 11:59) [293]
> _oxffff (24.11.10 11:10) [290]
> Можно синтаксис и семантику?
Ну, собственно в [291] приведён пример.
Только теперь мне не совсем понятно, в чём разница междуprocedure Foo() : reference to MyRecord;
иprocedure Bar() : MyRecord;
. И для каких целей она нужна. :)
← →
DiamondShark © (2010-11-24 12:38) [294]
> Пользователь имел в виду возможность преобразования типа
> T в тип U.
Это преобразование бывает двух типов: с изменением представления и без изменения представления. Это семантически разные операции.
> Если в библиотеках будет хранится информация не только о
> типах, но и об ограничениях, накладываемых на эти типы,
> то почему тогда невозможна независимая компиляция?
Потому что "a+b" может означать следующее:
- встроенная операция
- перекрытый оператор, определённый как функция верхнего уровня
- перекрытый оператор, определённый типом a
- перекрытый оператор, определённый типом b
- неявное преобразование из a во что-нибудь, что позволит применить что-нибудь из вышеперечисленного
- неявное преобразование из b во что-нибудь, что позволит применить что-нибудь из вышеперечисленного
Всё это помножить на ограничения на тип результата.
Эту всю байду надо записать в метаданные библиотеки. Для этого надо всё это реализовать в компиляторе, задокументировать и протестировать. Получится долго, дорого, тормозно и глючно.
А главное -- нафиг не нужно.
Не нужно, потому что программы пишутся не для того, чтобы запутать израильскую разведку, типа: "я напишу a+b и хрен кто догадается, что это означает". Фигтам. Программы пишут для того, чтобы их понимать и сопровождать. А для этого семантика кода должна быть ясна из самого кода (а не из инклуда на 5 мегов 80 уровня вложенности).
Когда [психически здоровым] программистом пишется "a+b" это подразумевает некую семантику операции (или семантический класс операций), известную в МОМЕНТ НАПИСАНИЯ этого факинг фрагмента кода.
Отсюда следует, что ограничния на типы операндов УЖЕ ИЗВЕСТНЫ этому долбанному уроду, который пишет этот булшит.
Поэтому самым разумным вариантом будет
- викинуть из компиляции генериков анализ перегрузок
- потребовать явного определения контракта взаимодействия параметров.
← →
DiamondShark © (2010-11-24 12:48) [295]
> И для каких целей она нужна. :)
иллюстрация создания динамических структур без явных операторов new|dispose.
Правда, пользователь такого языка первым делом напишет процедуру
procedure New<TRecord> : reference to TRecord;
var
r: TRecord;
begin
ZerroMemory(r, sizeof(TRecord));
return @r;
end;
(а в случае отсутствия генериков -- копию для каждого типа, который предполагается использовать в динамических структурах)
и будет долго материть разработчиков за то, что не предоставили синтаксический сахар в виде оператора new
%)
← →
_oxffff (2010-11-24 13:06) [296]
> euru © (24.11.10 11:06) [288]
>
> > _oxffff (24.11.10 08:36) [286]
> > 1. Ничего страшного. Не все generics можно инстанцировать.
>
> > Будет выведено сообщение о неоднозначности выбора при
> выборе
> > оператора.2. Современные языки отслеживают конфликты перегруженных
>
> > операторов.Поэтому сообщение об ошибке определения U и
> Z
> > могут появиться еще до использования generics.
>
> Допустим, есть два класса:
>
> class U
> {
> int operator *(U value1, Z value2)
> {
> return 1;
> }
> }
>
> class Z
> {
> int operator *(U value1, Z value2)
> {
> return 2;
> }
> }
>
> Далее определим ещё один класс:
>
> class A<T>
> {
> U field1 = new U();
> T field2;
> int field3;
>
> A(T field)
> {
> field2 = field;
> field3 = field1 * field2;
> }
> }
>
> И где-то дальше в коде определим переменную:
> A<Z> a = new A<Z>(new Z());
>
> Какое сообщение должен выдать компилятор, чтобы разработчику
> было понятно, почему его код не компилируется?
1. При определении U и Z компилятор проверяет набор перегруженных операторов. И сообщает об ошибке неоднозначности определения U и Z.
2. При интанцировании обобщенного типа компилятор проверяет автоматически выведенные constraints на существование и единственность оператора *. Единственность можно ослабить в рамках различных классов эквивалентности, добавив например приоритет методам-операторам *(хотя при условии 1 это ненужно).
← →
DiamondShark © (2010-11-24 14:29) [297]Мы вот тут спорим, спорим. А на основной вопрос системотехники(*) так и не ответили.
Вот скажите, кому нафиг нужен шаблон типа
U Foo<U,V,W>(V x, W y)
{
return x + y;
}
Что в переводе на человеческий означает эта функция?
"Сделай над операндами x и y нечто, непоймичего, что неизвестно где обозначено символом +; результат неизвестно каким образом преобразуй в тип U".
В чём радость иметь такой, простихоспидя, "обобщённый алкогоритм"?
-------------------
*основной вопрос системотехники: "А нафига?"
← →
euru © (2010-11-24 14:57) [298]
> DiamondShark © (24.11.10 12:38) [294]
> Это преобразование бывает двух типов: с изменением представления
> и без изменения представления. Это семантически разные операции
Но ведь это проблемы компилятора, какой вариант и каким образом выбирать в каждом конкретном случае. При чём этот выбор, по-моему, строго детерминирован, и никаких неопределённостей возникнуть не должно. Может, можно увидеть такой пример?
> Потому что "a+b" может означать следующее:
- встроенная операция
Только для встроенных типов. Соответственно, вся необходимая информация компилятору известна.
- перекрытый оператор, определённый как функция верхнего уровня
Такая возможность не должна поддерживаться компилятором, иначе неопределённости возникали бы и без дженериков.
- перекрытый оператор, определённый типом a
- перекрытый оператор, определённый типом b
- неявное преобразование из a во что-нибудь, что позволит применить что-нибудь из вышеперечисленного
- неявное преобразование из b во что-нибудь, что позволит применить что-нибудь из вышеперечисленного
Если такая возможность поддерживается для обычных типов, то почему этоже не может распространиться и на дженерики?
> Эту всю байду надо записать в метаданные библиотеки. Для
> этого надо всё это реализовать в компиляторе, задокументировать
> и протестировать. Получится долго, дорого, тормозно и глючно.
> А главное -- нафиг не нужно.
Такая же аргументация в конце прошлого века была и по отношению к объектно-ориентированным языкам. Однако они всё-таки почему-то появились.
> Не нужно, потому что программы пишутся не для того, и т.д.
Если вызывается виртуальная функция либо функция интерфейса, то, я так понимаю, израильская разведка догадается, что может сделать эта функция, и ей не придётся изучать те же 5 мегов.
← →
euru © (2010-11-24 15:15) [299]
> _oxffff (24.11.10 13:06) [296]
> 1. При определении U и Z компилятор проверяет набор перегруженных
> операторов. И сообщает об ошибке неоднозначности определения
> U и Z.
Классы U, Z и A<T> определены в библиотеке. Класс U вообще может оказаться приватным.
И что тогда должно разъяснить это сообщение, если программисту вообще неизвестно о существовании такого типа U?
← →
euru © (2010-11-24 15:29) [300]
> DiamondShark © (24.11.10 14:29) [297]
> Вот скажите, кому нафиг нужен шаблон типа
Во-первых, такие же вопросы можно задавать и про сборщик мусора, и про ООП.
Во-вторых, могу предложить другой шаблон:
class Vector<T>
{
Vector<T> operator +(Vector<T> a, Vector<T> b)
{
// Создание нового вектора, элементы которого равны
// сумме соответствующих элементов векторов a и b
}
}
← →
euru © (2010-11-24 15:57) [301]
> DiamondShark © (24.11.10 12:48) [295]
> иллюстрация создания динамических структур без явных операторов
> new|dispose.
Не понимаю необходимость таких структур.
procedure New<TRecord> : TRecord;
var r: TRecord;
begin
return r;
end;
По-моему, этого вполне достаточно, чтобы вернуть из функции инстанцированный объект типа TRecord.
← →
DiamondShark © (2010-11-24 16:28) [302]
> euru © (24.11.10 15:57) [301]
> Не понимаю необходимость таких структур.
facepalm.jpg
"
-- Приведите пример функции
-- int Foo() {return 17;}
-- Не понимаю необходимость таких функций
"
Надеюсь, необходимость структур, вроде
TListNode = record
data: string;
next: ^TListNode;
end
вы понимаете?
> По-моему, этого вполне достаточно, чтобы вернуть из функции
> инстанцированный объект типа TRecord.
По-моему, это вернёт копию.
> euru © (24.11.10 15:29) [300]
> Во-первых, такие же вопросы можно задавать и про сборщик
> мусора, и про ООП.
ИЧСХ, на них был даден убедительный ответ.
Ответа на вопрос: "Нафига нужна возможность МЕТОД обозначать символом плюсика" нет. Более того, ничего более убедительного, чем: "А шоб было, по-приколу же!" -- и быть не может.
> Во-вторых, могу предложить другой шаблон:
class Vector<T>
{
Vector<T> Add(Vector<T> a, Vector<T> b)
{
// Создание нового вектора, элементы которого равны
// сумме соответствующих элементов векторов a и b
}
}
Нафига там плюсик? Ага, знаю. Чтоб можно было написать вот так:
template<T> T PlusAny(T x, T y){ return x + y;}
и назвать это "обобщённым алгоритмом".
Сюда влезет и сложение целых цисел, и векторная сумма и конкатенация строк.
А нафига нужно такое обобщение?
← →
Mystic © (2010-11-24 16:50) [303]
> Нафига там плюсик? Ага, знаю. Чтоб можно было написать вот
> так:
> template<T> T PlusAny(T x, T y){ return x + y;}
> и назвать это "обобщённым алгоритмом"
Это не обобщенный алгоритм, это просто другой способ записи. Перегрузка операторов эквивалентна вызовам функций. Просто иногда бывает более удобна, напримерY := Add(Multiply(A, X), B);
выглядит малочитаемо :)
Вот выражение U.ABC(U,T) уже интереснее, ибо U.ABC может быть вызовом функции, а может быть именем типа. Но, как раз, C++ такое не разруливает на автомате, обязывая писать typename.
← →
DiamondShark © (2010-11-24 17:12) [304]
> Перегрузка операторов эквивалентна вызовам функций.
Замечательно.
Можно ли написать такой шаблон:
template<T> T FooBarAny(T x, T y){ return T.FooBar(x, y);}
?
НетЪ.
Почему?
← →
Mystic © (2010-11-24 17:40) [305]
> НетЪ.
> Почему?
Почему нельзя?
1 class A
2 {
3 public:
4 static A FooBar(A x, A y) { return A(); }
5 };
6
7 template<typename T>
8 T FooBarAny(T x, T y)
9 {
10 return T::FooBar(x, y);
11 }
12
13 int main()
14 {
15 A x, y;
16 FooBarAny(x, y);
17 return 0;
18 }
← →
DiamondShark © (2010-11-24 18:19) [306]
> Mystic © (24.11.10 17:40) [305]
Жэсть. Лишнее подтверждение тому, что плюсные шаблоны -- это лексические макросы.
← →
Mystic © (2010-11-24 18:36) [307]
> Лишнее подтверждение тому, что плюсные шаблоны -- это лексические
> макросы.
Не совсем, хотя как смотреть...
1 class A
2 {
3 public:
4 static A FooBar(A x, A y) { return A(); }
5 };
6
7 class B
8 {
9 public:
10 class FooBar
11 {
12 public:
13 FooBar(B x, B y) {}
14 operator B() { return B(); }
15 };
16 };
17
18 template<typename T>
19 T FooBarAny(T x, T y)
20 {
21 return T::FooBar(x, y);
22 }
23
24 template<typename T>
25 T FooBarAny2(T x, T y)
26 {
27 return typename T::FooBar(x, y);
28 }
29
30 int main()
31 {
32 A x, y;
33 B xx, yy;
34 FooBarAny(x, y);
35 // FooBarAny(xx, yy); // error: error: dependent-name "T::FooBar" is parsed as a non-type, but instantiation yields a type
36 FooBarAny2(xx, yy);
37 // FooBarAny2(x, y); // error: error: no type named "FooBar" in "class A"
38 return 0;
39 }
← →
euru © (2010-11-25 10:06) [308]
> DiamondShark © (24.11.10 16:28) [302]
> Надеюсь, необходимость структур, вроде
> TListNode = record
> data: string;
> next: ^TListNode;
> end
> вы понимаете?
Необходимость таких структур понимаю. Только с точки зрения описания структуры символ "^" в ней лишний. Замените слово "record" на слово "class", и он станет ненужным, хотя смысл структуры не изменился.
Я уточню. Мне непонятно, зачем в языке поддерживать явное создание динамических структур.
> По-моему, это вернёт копию.
Возьмём пример из Дельфиconst S: String = "очень длинная строка...";
function New(): String;
begin
Result := S;
end;
Что вернёт функция New? Копию строки или ссылкку на неё?
> ИЧСХ, на них был даден убедительный ответ.
Убедительный - это когда другие варианты ответов будут неверными? Однако существует, например, язык Дельфи, в котором нет сборщика мусора. Существует Прогог, которые не объектно-ориентированный. И с точки зрения этих языков такой ответ ни разу не убедительный.
> Нафига там плюсик? Ага, знаю. Чтоб можно было написать вот
> так:template<T> T PlusAny(T x, T y){ return x + y;}и назвать
> это "обобщённым алгоритмом".Сюда влезет и сложение целых
> цисел, и векторная сумма и конкатенация строк.А нафига нужно
> такое обобщение?
Сошлюсь-ка я на пару постов одно и того же автора из этой же темы: [43] и [119]. Уточнение: селёдка - это С++, паровая машина - это обобщение.
← →
DiamondShark © (2010-11-25 12:02) [309]
> Необходимость таких структур понимаю. Только с точки зрения
> описания структуры символ "^" в ней лишний. Замените слово
> "record" на слово "class", и он станет ненужным, хотя смысл
> структуры не изменился.
TRectangle = record
Origin: TPoint;
Size: Tsize;
end;
Здесь смысл изменится.
Либо вы имеете структуры и ссылки, либо имеете сущности "record" и "class".
Те же фаберже в разных ракурсах.
> Я уточню. Мне непонятно, зачем в языке поддерживать явное
> создание динамических структур.
А какое ещё? Телепатическое?
Вот есть код:
var
node: TListNode;
begin
// тут чего-то дофига происходит
node.next.data := "blablabla"; // вот тут чего должно произойти, если node.next = nil ?
Выделение нового узла или NullReferenceException?
Всё вам компилятор с телепатором подай...
Опять же, как различать копирование структур и копирование ссылок?
> Что вернёт функция New? Копию строки или ссылкку на неё?
В Дельфи это зависит от настроек компилятора.
Если String -- это ansi string, то вернётся ссылка;
Если String -- это pascal string, то вернётся копия.
> Убедительный - это когда другие варианты ответов будут неверными?
с абстрактным мышлением туго. Придётся на пальцах.
-- Курение вызывает зависимость и повышает риск заболеваний.
-- Курение нынче не в моде.
Первое утверждение убедительно, но это не значит, что второе неверное.
> Сошлюсь-ка я на пару постов
И всё-таки, зачем нужно обобщение сложения чисел и конкатенации строк?
← →
Mystic © (2010-11-25 12:16) [310]
> Я уточню. Мне непонятно, зачем в языке поддерживать явное
> создание динамических структур.
Классы иногда лишний оверхид по производительности. Плюс работа с низкоуровневыми библиотеками/API.
← →
DiamondShark © (2010-11-25 12:34) [311]
> Mystic © (25.11.10 12:16) [310]
В данном случае это не принципиально.
← →
Mystic © (2010-11-25 12:42) [312]
> В данном случае это не принципиально.
Основная идея поста, имхо, была в том, что если нужен указатель на запись, то проще ее сделать классом?
← →
DiamondShark © (2010-11-25 12:54) [313]
> Mystic © (25.11.10 12:42) [312]
Не-а. Мы пытаемся изобрести синтаксис и семантику языка, где бы вообще не было явного управления памятью.
← →
Mystic © (2010-11-25 13:19) [314]
> Не-а. Мы пытаемся изобрести синтаксис и семантику языка,
> где бы вообще не было явного управления памятью.
А чем не устраивают JavaScript, Lisp, Smalltalk?
← →
_oxffff (2010-11-25 14:29) [315]
> DiamondShark © (24.11.10 11:08) [289]
>
> > Почему невозможно? Это же взаимоисключающие условия: либо
>
> > T - подтип U, либо T - не подтип U, но поддерживает операцию
>
> > неявного привидения типа T к типу U.
>
>
> Потому что есть три возможности сгенерировать констрейнт
> - (T is U)
> - (ImplicitCast(T):U)
> - (T is U) or (ImplicitCast(T):U)
>
> Компилятор не должен угадывать, что имел в виду пользователь.
>
>
Если не думать в рамках текущей модели generics, а например ввести более общий T:=U(U assignable to T)?
>
> > 2. Современные языки отслеживают конфликты перегруженных
>
> > операторов.
>
> Эти перегрузки могут быть описаны в разных библиотеках.
> Эти перегрузки могут быть вообще не известны на момент компиляции
> определения генерика.
>
Будет выведено сообщение об ошибки о неоднозначности использования оператора * для U и T
← →
euru © (2010-11-25 14:29) [316]
> DiamondShark © (25.11.10 12:02) [309]
> Либо вы имеете структуры и ссылки, либо имеете сущности
> "record" и "class".
Кроме структур и ссылок возможны и другие варианты. Например, в Паскале есть тип file. Это структура или ссылка?
В чём разница между сущностями record и class, кроме того что одна из них value type, а другая - reference type. А могут быть и другие сущности. Например, в Дельфи имеется ещё одна сущность - object. Чем она отличается от первых двух сущностей?
> Вот есть код:
> var node: TListNode;
> begin
> // тут чего-то дофига происходит
> node.next.data := "blablabla"; // вот тут чего
> должно произойти, если node.next = nil ?Выделение нового
> узла или NullReferenceException?
Из [291] имеем: "Все типы языка -- value-типы. Есть специальный тип reference." Вопрос: зачем нужен reference?
Из [295] получаем ответ: "иллюстрация создания динамических структур без явных операторов new|dispose." Вопрос: зачем нужны динамические структуры?
Из [302] получаем ответ (если, конечно, я его правильно понял): например, для создания динамических списков.
Вопрос: неужели их нельзя создать без использования в языке понятия "ссылки"?
В приведённом примере (при условии, что используется некий язык, в котором все типы - это value type) поле TListNode.next - это тоже value type. Поэтому node.next.data := "blablabla"; отработает корректно и не приведёт ни к каким исключениям.
> Опять же, как различать копирование структур и копирование
> ссылок?
А их не нужно различать при отсутствии понятия "ссылка".
> В Дельфи это зависит от настроек компилятора.
> Если String -- это ansi string, то вернётся ссылка;
> Если String -- это pascal string, то вернётся копия.
Допустим, в настройках указано, что это ansi string. Тогда как будет работать следующий код:var s1: string;
s1 := New(); // возвращается ссылка на S
s1 := "!!!"; // что произойдёт со строкой S
s1 := New(); // опять возвращается ссылка на S
S := "+++"; // значение s1 тоже изменится?
> И всё-таки, зачем нужно обобщение сложения чисел и конкатенации
> строк?
Про селёдку: Если в Паскале или С-подобных языках "+" используется для конкатенации строк, то это проблемы этих языков. Например, в РНР используется точка, в АВАР строки вообще с помощью команды concatenate объединяются.
← →
_oxffff (2010-11-25 14:37) [317]
> DiamondShark © (24.11.10 11:36) [291]
>
> > А разве строки и массивы в Pascal не имеют оператора New?
>
>
> Строки и массивы в Pascal не имеют оператора New. Это value-
> типы.
То есть хотите сказать, что строки строго определенной длины и размещаются на стеке?
>
>
> > Можно синтаксис и семантику?
>
> Легко.
>
> Все типы языка -- value-типы. Есть специальный тип reference.
>
> Экземпляр value-типа жив пока жива хоть одна reference на
> него.
>
> Пример.
>
> type
> MyRecord = record
> a,b,c : integer;
> end;
>
> procedure Foo() : reference to MyRecord;
> var
> r: MyRecord;
> begin
> r.a := 1;
> r.b := 2;
> r.c := 3;
> return @r;
> end;
>
> procedure Bar() : MyRecord;
> var
> r: MyRecord;
> begin
> r.a := 1;
> r.b := 2;
> r.c := 3;
> return r;
> end;
>
> procedure Main;
> var
> r: MyRecord;
> rr: reference to MyRecord;
> begin
> rr := Foo(); // динамический экземпляр
> r := Bar(); // копирование
> rr := nil; // удаление
> end;
>
> Никаких new|dispose
Ну, ну. Прямо таки никаких new. Строго говоря написана обертка для оператора new для myrecord. Базируется на подобии замыканий(захват и продление жизни). И чем это собственно отличается от оператора new?
Для каждого типа своя обертка. А new - полиморфен.
Причем не следуют забывать о том, что new не только аллокирует, но еще и инициализирует сущность. Интересно какой будет введен еще абстрактный механизм для duck typing для конструкторов в вашем языке. Чтобы в итоге получится недовелосипед new?
← →
euru © (2010-11-25 14:39) [318]
> Mystic © (25.11.10 12:42) [312]
> Основная идея поста, имхо, была в том, что если нужен указатель
> на запись, то проще ее сделать классом?
Нет. Основная идея в том, что если нужен указатель на запись, то там действительно нужен указатель на запись?
← →
_oxffff (2010-11-25 14:42) [319]
> DiamondShark © (24.11.10 12:48) [295]
>
> > И для каких целей она нужна. :)
>
> иллюстрация создания динамических структур без явных операторов
> new|dispose.
>
> Правда, пользователь такого языка первым делом напишет процедуру
>
> procedure New<TRecord> : reference to TRecord;
> var
> r: TRecord;
> begin
> ZerroMemory(r, sizeof(TRecord));
> return @r;
> end;
>
> (а в случае отсутствия генериков -- копию для каждого типа,
> который предполагается использовать в динамических структурах)
> и будет долго материть разработчиков за то, что не предоставили
> синтаксический сахар в виде оператора new
>
> %)
Вместо одного new. Вводятся смысл замыкания и еще где опять инициализация типа? Как передать различные параметры? Как проверять?
← →
euru © (2010-11-25 14:42) [320]
> Mystic © (25.11.10 13:19) [314]
> А чем не устраивают JavaScript, Lisp, Smalltalk?
Тем, что они уже есть. :)
← →
_oxffff (2010-11-25 14:45) [321]
> euru © (24.11.10 15:15) [299]
>
> > _oxffff (24.11.10 13:06) [296]
>
> > 1. При определении U и Z компилятор проверяет набор перегруженных
>
> > операторов. И сообщает об ошибке неоднозначности определения
>
> > U и Z.
>
> Классы U, Z и A<T> определены в библиотеке. Класс U вообще
> может оказаться приватным.
> И что тогда должно разъяснить это сообщение, если программисту
> вообще неизвестно о существовании такого типа U?
Ответит честно, внутренний тип(без раскрытия имени) не поддерживают операцию * для типа Z
← →
_oxffff (2010-11-25 14:48) [322]Вроде на все вопросы ко мне ответил. Начал писать ответы вчера, а запостил сегодня. Сижу на больничном с сыном. Вчера проснулся во время ответов. Сейчас спит. Так что я ответил за все.
← →
euru © (2010-11-25 15:06) [323]
> _oxffff (25.11.10 14:45) [321]
> Ответит честно, внутренний тип(без раскрытия имени) не поддерживают
> операцию * для типа Z
Ну, наверно, да. Что-то в таком роде.
Хотя точнее, наверно, так будет: Конфликт между реализацией класса A<Z> и операцией Z.*(U, Z).
Потому что это необязательно может быть из-за внутреннего типа и в Z может быть несколько перезагрузок оператора *.
← →
Mystic © (2010-11-25 17:37) [324]> Например, в Паскале есть тип file. Это структура или ссылка?
Это приватный тип :)
> Основная идея в том, что если нужен указатель на запись,
> то там действительно нужен указатель на запись?
Если в API в записи есть указатель на другую запись, то как без него жить?
> Ответит честно, внутренний тип(без раскрытия имени) не поддерживают
> операцию * для типа Z
В общем ошибка может быть такой: нет перегруженой операции * для типов _____private2345762 и _____private124712345. Имеются следующие кандидаты: <внушительный список>. Вопрос в том, как это поможет программисту без доступа к коду шаблона узнать, как исправить эту ошибку и какой операции не хватает?
← →
_oxffff (2010-11-25 17:47) [325]
> . Вопрос в том, как это поможет программисту без доступа
> к коду шаблона узнать, как исправить эту ошибку и какой
> операции не хватает?
Можно вывести список автовыведенных constraints для данного шаблона с указанием множества допустимых типов(сигнатур) для данной операции с внутреннем типом.
← →
Mystic © (2010-11-25 17:56) [326]
> Можно вывести список автовыведенных constraints для данного
> шаблона с указанием множества допустимых типов(сигнатур)
> для данной операции с внутреннем типом.
С учетом всевозможных приведений типов получим экспоненциальный рост возможных вариантов, что может повесить компилятор и не помочь никак программисту.
← →
_oxffff (2010-11-25 18:21) [327]
> Mystic © (25.11.10 17:56) [326]
>
> > Можно вывести список автовыведенных constraints для данного
>
> > шаблона с указанием множества допустимых типов(сигнатур)
>
> > для данной операции с внутреннем типом.
>
>
> С учетом всевозможных приведений типов получим экспоненциальный
> рост возможных вариантов, что может повесить компилятор
> и не помочь никак программисту.
Да здесь могут быть сложности, если намеренно поставить такую задачу.
Однако глубина операций обычно <5, что никак не отразится на скорости.
← →
euru © (2010-11-25 18:31) [328]
> Mystic © (25.11.10 17:37) [324]
> Это приватный тип :)
Однако это нисколько не мешает работать с ним как с обычным типом.
String в Дельфи тоже, кстати, своего рода приватный тип.
> Если в API в записи есть указатель на другую запись, то
> как без него жить?
Вообще-то имелся в виду вопрос другого рода. Если в языке не поддерживается такое понятие как указатель или ссылка, то можно ли описывать в нём структуры типа связного списка и если можно, то как?
← →
Mystic © (2010-11-25 19:24) [329]
> Да здесь могут быть сложности, если намеренно поставить
> такую задачу.
> Однако глубина операций обычно <5, что никак не отразится
> на скорости.
Лично меня в C++ уже ужасно напрягает смотреть, почему шаблон не может быть инстанцирован. Даже сейчас мечтаю о том, чтобы можно было, как в Ada, ручками указывать ограничения. А ты предлагаешь что-то еще более сложное. Тогда точно надо будет повеситься :)
В крайнем случае для ленивых можно придумать внешнюю тулзу, которая эти ограничения будет генерировать на автомате и вписывать их в исходник.
В целом работы составителям компилятора очень дофига, а реальной пользы я не вижу.
← →
Mystic © (2010-11-25 19:26) [330]
> Если в языке не поддерживается такое понятие как указатель
> или ссылка, то можно ли описывать в нём структуры типа связного
> списка и если можно, то как?
Элементарно, смотри Хаскель. Там что-то вроде этого:data Tree a = Leaf a | Branch (Tree a) (Tree a)
← →
euru © (2010-11-26 10:22) [331]
> Mystic © (25.11.10 19:26) [330]
> Элементарно, смотри Хаскель.
С таким же успехом можно было посоветовать и Лисп. Только вот на вопрос "как это сделать?" такой ответ никак не отвечает.
← →
_oxffff (2010-11-26 10:43) [332]В функциональных языках для представления рекурсивных функций и типов используется комбинатор неподвижной точки.
http://www.wikiznanie.ru/ru-wz/index.php/%D0%9A%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80_%D0%BD%D0%B5%D0%BF%D0%BE%D0%B4%D0%B2%D0%B8%D0%B6%D0%BD%D0%BE%D0%B9_%D1%82%D0%BE%D1%87%D0%BA%D0%B8
Комбинаторы неподвижной точки позволяют определять анонимные рекурсивные функции. Немного удивительным является то, что такие комбинаторы сами могут быть определены при помощи нерекурсивных λ-абстракций.
Один из самых известных (и, вероятно, из самых простых) комбинаторов неподвижной точки в нетипизированном λ-исчислении называется комбинатором Y. Он был разработан Хаскеллом Карри и определяется следующим образом:
Y = λf.(λx.f(xx))(λx.f(xx))
Необходимо отметить, что комбинатор Y предназначен для использования совместно с вычислительной стратегией «вызов по имени», поскольку выражение (Y g) зацикливается для произвольного g в стратегии «вызов по значению».
← →
jack128_ (2010-11-26 11:10) [333]
> С таким же успехом можно было посоветовать и Лисп. Только
> вот на вопрос "как это сделать?" такой ответ никак не отвечает.
>
тебе привели пример как на хаскеле (в котором нет указателей) описать дерево. Это не ответ??
← →
euru © (2010-11-26 13:53) [334]
> jack128_ (26.11.10 11:10) [333]
> тебе привели пример как на хаскеле (в котором нет указателей)
> описать дерево. Это не ответ??
Ответ. Но не совсем тот, который я ожидал.
Допускаю, что некорректно сформулировал вопрос. Попробую его уточнить.
1. Есть некий язык программирования. По контексту обсуждения - это императивный язык.
2. Чтобы не возникал вопрос о нужности/ненужности ручного сбора мусора было предложено не вводить в язык оператор new [284] (нет возможности выделять память, соответственно не нужно её освобождать).
3. Чтобы не возникал вопрос о нужности/ненужности оператора new, было предложено все типы в языке представлять как value type [291].
4. Тогда возникают вопросы:
[302] Как реализовать (а не описать) в компиляторе обработку структур видаTListNode = record
data: string;
next: TListNode;
end;
[309] Как для таких структур компилятор должен обрабатывать выраженияnode.next.data := "blablabla"; // вот тут чего должно произойти, если node.next = nil ?
Выделение нового узла или NullReferenceException?
Вот, собственно говоря, и всё.
Соответственно ответ про Хаскель [330] не отвечает на эти вопросы.
← →
jack128_ (2010-11-26 14:29) [335]
> [302] Как реализовать (а не описать) в компиляторе обработку
> структур вида
> TListNode = record
> data: string;
> next: TListNode;
> end;
>
> [309] Как для таких структур компилятор должен обрабатывать
> выражения
> node.next.data := "blablabla"; // вот тут чего должно произойти,
> если node.next = nil ?
> Выделение нового узла или NullReferenceException?
какой такой nil - если у нас только value типы ?
← →
jack128_ (2010-11-26 14:31) [336]вообще в императивном(читай энергичном) языке иметь только value-типы -это бред. То есть лет 40 назад возможно прокатило бы, а сейчас - не взлетит..
← →
Mystic © (2010-11-26 14:50) [337]> euru © (26.11.10 13:53) [334]
Что-то тут не так. Имеет место быть попытка разработать язык программирования вообще без кучи в каком бы то ни было виде (явной или неявной)? Но как в этом контексте понимать
> Выделение нового узла или NullReferenceException?
Как компилятор может выделять место в куче, если ее нет?
Если куча присутствует неявно (со своим GC), то
> [309] Как для таких структур компилятор должен обрабатывать
> выражения> node.next.data := "blablabla"; // вот тут чего должно произойти, если node.next = nil ?
Тут NullReference.
В данном примере достаточно одного конструктораconstructor TList(ArgData: string);
begin
Data := ArgData;
Next := nil;
end;
и потом
Node.Next := TList("blablabla");
В Хаскеле проще, потому что язык функциональный, и изменять переменные нельзя. Почему просто конструируется новый список.Haskell data List a = Cons a (List a) | Nil
И строим дальше по своему желанию:
x = Cons "blablabla" Nil;
y = Cons "test" x;
z = Cons "3" (Cons "2" (Cons "1" Nil));
И т. д. и т. п.
← →
euru © (2010-11-26 15:59) [338]
> jack128_ (26.11.10 14:29) [335]
> какой такой nil - если у нас только value типы ?
Это такая константа, означающая неопределённое значение любого value-типа.
← →
euru © (2010-11-26 16:15) [339]
> jack128_ (26.11.10 14:31) [336]
> вообще в императивном(читай энергичном) языке иметь только
> value-типы -это бред. То есть лет 40 назад возможно прокатило
> бы, а сейчас - не взлетит..
Возможно. Не спорю.
Но, по-моему, данная тема более соответствует тематике этого форума, нежели некоторые другие. Почему бы и не пообсуждать?
И вообще: а вдруг взлетит?
← →
euru © (2010-11-26 16:43) [340]
> Mystic © (26.11.10 14:50) [337]
> Что-то тут не так. Имеет место быть попытка разработать
> язык программирования вообще без кучи в каком бы то ни было
> виде (явной или неявной)? Но как в этом контексте понимать
>
> > Выделение нового узла или NullReferenceException?
>
> Как компилятор может выделять место в куче, если ее нет?
Понятия кучи нет в языке программирования. Но ничто не мешает компилятору работать с кучей. Данные-то ему нужно же где-то хранить.
> Тут NullReference.
> В данном примере достаточно одного конструктора
А зачем? Формально ведьnode.next
уже содержит значение, равноеnil
(см. [338]). так что можно смело делать присвоениеnode.next.data := "blablabla";
, не опасаясь никаких исключений.
← →
Mystic © (2010-11-26 17:10) [341]
> Данные-то ему нужно же где-то хранить.
Обычно данные в стеке либо в сегменте данных. Куча уже рождает GC.
> так что можно смело делать присвоение node.next.data :=
> "blablabla";, не опасаясь никаких исключений
Для этого надо знать, как создать объект.
← →
euru © (2010-11-26 17:53) [342]
> Mystic © (26.11.10 17:10) [341]
> Обычно данные в стеке либо в сегменте данных.
Не факт, что в исполняемой среде есть стек. Я уже давал ссылку на статью "Правда о значимых типах", но повторю ещё раз. Там более подробно описано, где могут храниться значимые типы.
http://blogs.msdn.com/b/ruericlippert/archive/2010/10/25/the-truth-about-value-types.aspx
> Куча уже рождает GC.
А его никто и не отменял. Но он будет скрыт от программиста. А структура языка даже повода не даст ему подумать о необходимости в ручном сборщике мусора.
> Для этого надо знать, как создать объект.
Зачем? При объявлении переменной компилятор уже знает какого она типа и как её создать. Конструктор нужен не для создания объекта, а для его инициализации. Сам объект создаётся при первом присваивании ему или хотя бы одному из его компонентов какого-либо значения.
← →
euru © (2010-11-29 10:30) [343]Продолжим?
← →
euru © (2010-11-30 11:25) [344]А что, данная тема стала неинтересна?
← →
Mystic © (2010-11-30 12:33) [345]А что тут еще можно сказать? Все уже давно изобретено. Вряд-ли есть какие-нить еще идеи...
← →
_oxffff (2010-11-30 17:24) [346]
> euru © (30.11.10 11:25) [344]
> А что, данная тема стала неинтересна?
Завтра выхожу на работу и продолжу пилить свой язык YAR.
santonov.blogspot.com
← →
_oxffff (2010-11-30 17:30) [347]
> Вряд-ли есть какие-нить еще идеи...
Не все приятные изобретения попадают в mainstream языки.
← →
euru © (2010-11-30 18:33) [348]
> Mystic © (30.11.10 12:33) [345]
> А что тут еще можно сказать? Все уже давно изобретено. Вряд-
> ли есть какие-нить еще идеи...
Однако же новые языки всё появляются и появляются.
Идеи есть. Например, как я уже предлагал выше, отказаться от ссылочных типов и указателей и оставить только значимые типы. Ещё, например, идея отказаться от var-параметров в подпрограммах.
Собственно, хотелось бы пообсуждать, почему и чем те или иные идеи полезны/бесполезны/бестолковы и т.д.
← →
DiamondShark © (2010-11-30 20:17) [349]
> отказаться от ссылочных типов и указателей и оставить только
> значимые типы.
Это лютый ахтунг при наличии mutable значений.
Но такой подход уже ровесник Октябрьской Революции в кошерных функциональных языках без побочных эффектов.
← →
_oxffff (2010-11-30 22:04) [350]Тогда сюда
http://fprog.ru/2010/issue6/
← →
_oxffff (2010-11-30 22:25) [351]Дальше сюда
http://metacomputation-ru.blogspot.com/
И далее приятного мозголомства ....
← →
Mystic © (2010-12-01 12:05) [352]
> Однако же новые языки всё появляются и появляются.
А что в них принципиально нового? Помнится только Nemerle с его системой макросов. Но по сути похожее было в TeX.
> Идеи есть. Например, как я уже предлагал выше, отказаться
> от ссылочных типов и указателей и оставить только значимые
> типы. Ещё, например, идея отказаться от var-параметров в
> подпрограммах.
Это трудно назвать "новой идеей", потому что до того, как фича была придумана, ее не было. Ну так можно взять любой язык и отказаться в нем от много-чего. Только что это даст? В конце-концов, никто не мешает не пользоваться var-параметрами и указателями :)
> Собственно, хотелось бы пообсуждать, почему и чем те или
> иные идеи полезны/бесполезны/бестолковы и т.д.
Проще по одной идее на тему. Из того, что пришло в голову, список примерно такой:
Синтаксический сахар полезен, потому что уменьшает писанину. Но если его много, надо много держать в голове.
Отсутствие изменяемых переменных делает возможным распараллеливание на уровне исполняющей среды, но требует придерживаться опреденного стиля написания, что есть гемор. Плюс требуется сборка мусора и не всегда компилятор умен, чтобы избегать дополнительных расходов.
Сборщик мусора полезен тем, что избавляет от необходимости следить за памятью. Но все-таки для некоторых объектов надо контролировать жизнь объектов плюс в некоторых задачах надо более эффективно руками управлять памятью.
← →
oxffff © (2010-12-01 15:18) [353]
> euru © (30.11.10 18:33) [348]
>
> > Mystic © (30.11.10 12:33) [345]
>
> > А что тут еще можно сказать? Все уже давно изобретено.
> Вряд-
> > ли есть какие-нить еще идеи...
>
> Однако же новые языки всё появляются и появляются.
>
> Идеи есть. Например, как я уже предлагал выше, отказаться
> от ссылочных типов и указателей и оставить только значимые
> типы. Ещё, например, идея отказаться от var-параметров в
> подпрограммах.
>
> Собственно, хотелось бы пообсуждать, почему и чем те или
> иные идеи полезны/бесполезны/бестолковы и т.д.
Собственно я за обсуждение. Только обсуждение должно быть предметным.
Например описать операционную семантику данного языка.
Были попытки о DiamondShark, но не полные.
Более того вполне возможно если такая семантика будет представлена и более менее доказана и обсуждена нами, то мы бы могли попробовать совместными усилиями реализовать ее в виде языка. Почему нет? :)
← →
Wogn (2010-12-01 16:44) [354]О, Господи, они собираются убирать ссылочные типы из языка, когда давно уже для защиты от null pointer exception существует Maybe паттерн.
Сборка мусора им не нравится? Правильно, долой сборку мусора, а вместо кучи будем базу данных использовать, SQL же вообще прекрасны образчик языка без явного управления памятью.
А YAR, ну это надо же взять синтаксис Паскаля за основу. Это покрытое пылью и плесенью наследие веков. Это надо "Паскаль с плюшечками" назвать.
Весело, черт побери.
← →
euru © (2010-12-02 01:48) [355]
> Mystic © (01.12.10 12:05) [352]
> Сборщик мусора полезен... Но ... в некоторых задачах надо
> более эффективно руками управлять памятью.
А если создать соответствующий класс? В нём выделять необходимое количество памяти и эффективно управлять ею с помощью методов, наиболее соответствующих требованиям задачи.
← →
euru © (2010-12-02 02:15) [356]
> oxffff © (01.12.10 15:18) [353]
> Собственно я за обсуждение. Только обсуждение должно быть
> предметным. Например описать операционную семантику данного
> языка. Были попытки о DiamondShark, но не полные.Более того
> вполне возможно если такая семантика будет представлена
> и более менее доказана и обсуждена нами, то мы бы могли
> попробовать совместными усилиями реализовать ее в виде языка.
> Почему нет? :)
Скорее всего, такой подход ни к чему хорошему не приведёт. Потому что желающих заниматься разработкой языка и тем более его реализацией окажется слишком мало. А среди тех, кто всё-таки решится на это, наверняка будут разные взгляды, как должен выглядеть этот язык.
По-моему, лучше как раз обсуждать некоторые идеи. Попытаться понять, можно ли эти идеи реализовать. И если невозможно, то почему.
Мне вот, например, до сих пор непонятно, почему нельзя в нефункциональном языке остановиться только на значимых типах, не воодя ссылок и указателей.
← →
euru © (2010-12-02 02:17) [357]
> Wogn (01.12.10 16:44) [354]
> О, Господи, они собираются убирать ссылочные типы из языка,
> когда давно уже для защиты от null pointer exception существует
> Maybe паттерн.
А зачем вводить паттерн для защиты от null, если можно в принципе отказаться от такой ситуации?
← →
oxffff © (2010-12-02 09:23) [358]
> euru © (02.12.10 02:15) [356]
>
> > oxffff © (01.12.10 15:18) [353]
>
> > Собственно я за обсуждение. Только обсуждение должно быть
>
> > предметным. Например описать операционную семантику данного
>
> > языка. Были попытки о DiamondShark, но не полные.Более
> того
> > вполне возможно если такая семантика будет представлена
>
> > и более менее доказана и обсуждена нами, то мы бы могли
>
> > попробовать совместными усилиями реализовать ее в виде
> языка.
> > Почему нет? :)
>
> Скорее всего, такой подход ни к чему хорошему не приведёт.
> Потому что желающих заниматься разработкой языка и тем
> более его реализацией окажется слишком мало. А среди тех,
> кто всё-таки решится на это, наверняка будут разные взгляды,
> как должен выглядеть этот язык.
>
> По-моему, лучше как раз обсуждать некоторые идеи. Попытаться
> понять, можно ли эти идеи реализовать. И если невозможно,
> то почему.
>
> Мне вот, например, до сих пор непонятно, почему нельзя в
> нефункциональном языке остановиться только на значимых типах,
> не воодя ссылок и указателей
Рассуждать о сферическом коне в вакууме сложно.
Это действительно сложно. "нестыковки" могут быть выявлены только на практике.
← →
Wogn (2010-12-02 09:38) [359]>euru © (02.12.10 02:17) [357]
>А зачем вводить паттерн для защиты от null, если можно в принципе отказаться от такой ситуации?
В противном случае, вы получите еще один SQL. Ну или Haskell, если постараетесь. Просто потому, что операции работы с памятью естественны для императивного подхода. Убрав их, вы сделаете императивный язык противоестественным.
А что до ссылок, то паттерн Maybe может быть просто встроенным в язык. Все ссылки - это ссылки Maybe, и программист просто будет вынужден всегда их обрабатывать.
← →
euru © (2010-12-02 11:38) [360]
> oxffff © (02.12.10 09:23) [358]
> Рассуждать о сферическом коне в вакууме сложно. Это действительно
> сложно. "нестыковки" могут быть выявлены только на практике.
Хорошо. Попробуем пойти этим путём. Жду описания операционной семантики языка.
← →
oxffff © (2010-12-02 11:43) [361]
> euru © (02.12.10 11:38) [360]
>
> > oxffff © (02.12.10 09:23) [358]
>
> > Рассуждать о сферическом коне в вакууме сложно. Это действительно
>
> > сложно. "нестыковки" могут быть выявлены только на практике.
>
>
> Хорошо. Попробуем пойти этим путём. Жду описания операционной
> семантики языка.
Каком языке идет речь?
Это я и другие участники ждем, когда будет написано подробно что и как работает и какие используеются механизмы в языке в котором присутствуют только value типы. Чтобы попробовать поразмышлять над семантикой языка по его правилам в общем виде и попробовать найти нестыковки есть они есть.
Разве подругому?
← →
euru © (2010-12-02 11:46) [362]
> Wogn (02.12.10 09:38) [359]
> В противном случае, вы получите еще один SQL. Ну или Haskell,
> если постараетесь.
Есть большая разница, что получить: ещё один SQL, Haskell или ещё один императивный язык?
> Убрав их, вы сделаете императивный язык противоестественным.
А, может быть, это и есть "новая идея"? :)
> А что до ссылок, то паттерн Maybe может быть просто встроенным
> в язык. Все ссылки - это ссылки Maybe, и программист просто
> будет вынужден всегда их обрабатывать.
Лучше было бы вынудить компилятор это обрабатывать, сняв эту заботу с программиста. Я думаю, программисту найдётся, чем заняться в освободившееся от вынужденной обработки ссылок время.
← →
Wogn (2010-12-02 12:08) [363]euru © (02.12.10 11:46) [362]
>Есть большая разница, что получить: ещё один SQL, Haskell или ещё один императивный язык?
Если вы программировали на Haskell или Clojure, то наверняка знаете какие нетривиальные мыслительные извороты приходится выполнять, чтобы остаться в рамках "immutable data structures". У вас есть только возможность конструирования и связывания, практически все то, что вы хотите оставить в своем гипотетическом императивном языке без явного управления памятью. Но я слабо понимаю, как вы себе представляете императивный язык, в котором есть только эти операции? В SQL, Haskell или Clojure, как вы понимаете, это возможно потому, что время жизни большинства переменных определяется исключительно лексическим контекстом (в Clojure можно использовать динамический контекст, для хранения данных которого используется TLS). Как такое провернуть в императивном языке?
>Лучше было бы вынудить компилятор это обрабатывать, сняв эту заботу с программиста. Я думаю, программисту найдётся, чем заняться в освободившееся от вынужденной обработки ссылок время.
А потом будете вопить: "Святая Дева, мне опять приходится создавать экземпляр объекта со значением "zzByk@nstwernnkt", чтобы выделять неинициализрованные значения. О Господи, он не эквивалентен экземпляру объекта с таким же именем, созданном в стороннем модуле, и моя логика из-за этого не работает!", "Эти чертовы разработчики языков отнимают у нас свободу! Вчера они отняли у нас возможность управлять памятью, а теперь лишили нас null! В топку эти их языки, создадим же свой новый язык с null и управлением памятью!"
Вы не цените свободу выбора, пока она у вас есть.
← →
oxffff © (2010-12-02 12:20) [364]
> Wogn (01.12.10 16:44) [354]
> А YAR, ну это надо же взять синтаксис Паскаля за основу.
> Это покрытое пылью и плесенью наследие веков. Это надо
> "Паскаль с плюшечками" назвать.
> Весело, черт побери.
Кто то любит быть многословным, кто то кратким. Но главное в понимании.
Вопрос синтаксиса имеет большое отношение к семантике языка?
← →
oxffff © (2010-12-02 12:25) [365]
> Wogn (02.12.10 12:08) [363]
> euru © (02.12.10 11:46) [362]
>
> >Есть большая разница, что получить: ещё один SQL, Haskell
> или ещё один императивный язык?
>
> Если вы программировали на Haskell или Clojure, то наверняка
> знаете какие нетривиальные мыслительные извороты приходится
> выполнять, чтобы остаться в рамках "immutable data structures".
> У вас есть только возможность конструирования и связывания,
> практически все то, что вы хотите оставить в своем гипотетическом
> императивном языке без явного управления памятью. Но я слабо
> понимаю, как вы себе представляете императивный язык, в
> котором есть только эти операции? В SQL, Haskell или Clojure,
> как вы понимаете, это возможно потому, что время жизни
> большинства переменных определяется исключительно лексическим
> контекстом (в Clojure можно использовать динамический контекст,
> для хранения данных которого используется TLS). Как такое
> провернуть в императивном языке?
Слабо представлять не нужно, нужно просто обратить внимание на присутствие замыканий в императивным языках.
← →
Wogn (2010-12-02 13:11) [366]oxffff © (02.12.10 12:25) [365]
Замыкания хорошо работают, когда функция - это объект первого класса. То есть, замыкание захватывает лексический экстент в котором оно находится и его можно возвратить из него, и строить на нем ленивую логику и т.п. Насколько я знаю, Delphi не позволяет этого делать, и замыкания в нем, это просто сорт сахара. А если в языке наличествуют замыкания и функции как объекты первого класса, то это уже, как минимум, гибридный язык.
А вот как вы, кстати, собираетесь делать замыкания и захват лексического экстента без кучи?
← →
jack128_ (2010-12-02 13:21) [367]
> п. Насколько я знаю, Delphi не позволяет этого делать, и
> замыкания в нем, это просто сорт сахара
начиная с 2009ой - есть.
← →
jack128_ (2010-12-02 13:21) [368]в смысле - позволяет -)
← →
RWolf © (2010-12-02 13:54) [369]кстати, не объяснит ли кто-нибудь, что есть замыкание с точки зрения компилятора? т.е. под какие сущности выделяется память, стековые фреймы и т.п.
← →
Wogn (2010-12-02 14:07) [370]jack128_ (02.12.10 13:21) [367]
Нашел только анонимные процедуры. А метод Free у них наверняка тоже есть?
RWolf © (02.12.10 13:54) [369]
Если речь идет о функциональных замыканиях, то стек просто не задействуется. Если компилятор определяет, что эта функция будет возвращена как замыкание, то он помещает структуру данных, содержащую указатель на нее и память для переменных из захваченного ею окружения в кучу.
← →
oxffff © (2010-12-02 14:10) [371]
> Wogn (02.12.10 13:11) [366]
> oxffff © (02.12.10 12:25) [365]
>
> Замыкания хорошо работают, когда функция - это объект первого
> класса. То есть, замыкание захватывает лексический экстент
> в котором оно находится и его можно возвратить из него,
> и строить на нем ленивую логику и т.п. Насколько я знаю,
> Delphi не позволяет этого делать, и замыкания в нем, это
> просто сорт сахара. А если в языке наличествуют замыкания
> и функции как объекты первого класса, то это уже, как минимум,
> гибридный язык.
> А вот как вы, кстати, собираетесь делать замыкания и захват
> лексического экстента без кучи?
Видимо речь идет о первом порядке, а не о первом классе?
Я честно говоря не понял почему именно для функций первого порядка хорошо работают замыкания. Какие есть сложности для функций высших порядков?
← →
Wogn (2010-12-02 14:19) [372]oxffff © (02.12.10 14:10) [371]
Имеется в виду function as a first-class object. Это просто означает, что функция может быть взята и присвоена переменной в качестве значения (при этом время ее жизни не зависит от контекста в котором она находится).
Насколько я знаком с замыканиями в Delphi - это просто локальные функции, которые могут использовать переменные из контекста в котором они находятся, но допустимость их использования, даже если указатели на них можно было бы получить, определяется временем существования контекста в котором они определены. Для функций как объектов первого класса такого ограничения нет.
Я могу ошибаться конечно, может быть в современных версиях Дельфи возможны функциональные замыкания, но как тогда производится управление памятью?
← →
oxffff © (2010-12-02 14:19) [373]
> Wogn (02.12.10 14:07) [370]
> jack128_ (02.12.10 13:21) [367]
>
> Нашел только анонимные процедуры. А метод Free у них наверняка
> тоже есть?
>
> RWolf © (02.12.10 13:54) [369]
>
> Если речь идет о функциональных замыканиях, то стек просто
> не задействуется. Если компилятор определяет, что эта функция
> будет возвращена как замыкание, то он помещает структуру
> данных, содержащую указатель на нее и память для переменных
> из захваченного ею окружения в кучу.
Анонимные методы - это еще одно название замыканий.
Явного метода Free у Delphi сlosures нет. Однако есть семантика подсчета ссылок(однако при определенной сноровке может вызвать зацикливание).
Захват в замыканиих Delphi происходит по локации, а не значении.
Отсюда и известные проблемы например в цилках for. Но эта же проблема есть и у C#.
for i:=0 to 100 do
begin
a:=procedure abc;
begin
showmessage(inttostr(i));
end;
end;
Реализация также как и у всех: размещение вне в записи активации метода(например куча, или если активация методов не стековая(то есть при покидании метода, можно сохранить его состояние, то в его активации, а сама активация в куче)).
← →
oxffff © (2010-12-02 14:24) [374]
> Wogn (02.12.10 14:19) [372]
> oxffff © (02.12.10 14:10) [371]
>
> Имеется в виду function as a first-class object. Это просто
> означает, что функция может быть взята и присвоена переменной
> в качестве значения (при этом время ее жизни не зависит
> от контекста в котором она находится).
> Насколько я знаком с замыканиями в Delphi - это просто локальные
> функции, которые могут использовать переменные из контекста
> в котором они находятся, но допустимость их использования,
> даже если указатели на них можно было бы получить, определяется
> временем существования контекста в котором они определены.
> Для функций как объектов первого класса такого ограничения
> нет.
> Я могу ошибаться конечно, может быть в современных версиях
> Дельфи возможны функциональные замыкания, но как тогда производится
> управление памятью?
Есть функциональные замыкания.
Захваченные переменные будут размещены в куче.
← →
Wogn (2010-12-02 14:25) [375]oxffff © (02.12.10 14:19) [373]
>Анонимные методы - это еще одно название замыканий.
Это конечно буквоедство, но замыканием называется именно захват окружения. А анонимные методы, это анонимные методы.
А на счет анонимных методов в Дельфи стоит еще покопать, это интересно. Вижу, постепенно язык тоже обзаводится хромыми костылями.
← →
euru © (2010-12-02 14:30) [376]
> oxffff © (02.12.10 11:43) [361]
> Каком языке идет речь?
Прошу прощения. Возникло небольшое недопонимание. :)
Целостного описания семантики языка у меня нет, есть только идеи. Одна из них: представлять все типы в языке с точки знения программиста как значимые. Что это даёт? Например:
- упрощение языка в связи с отсутствием понятия ссылок и указателей;
- отсутствие проблемы утечки памяти.
Собственно, по ходу обсуждения я обо всём этом уже говорил. Если что-то непонятно, задавайте вопросы.
← →
oxffff © (2010-12-02 14:34) [377]
> euru © (02.12.10 14:30) [376]
>
> > oxffff © (02.12.10 11:43) [361]
>
> > Каком языке идет речь?
>
> Прошу прощения. Возникло небольшое недопонимание. :)
>
> Целостного описания семантики языка у меня нет, есть только
> идеи. Одна из них: представлять все типы в языке с точки
> знения программиста как значимые. Что это даёт? Например:
>
> - упрощение языка в связи с отсутствием понятия ссылок и
> указателей;
> - отсутствие проблемы утечки памяти.
> Собственно, по ходу обсуждения я обо всём этом уже говорил.
> Если что-то непонятно, задавайте вопросы.
Тогда если нет ссылок и указателей, как создать например двунаправленный связный список?
Или все таки все типы значимые, но cкрыто(неявно) ссылочные?
← →
oxffff © (2010-12-02 14:36) [378]
> Wogn (02.12.10 14:25) [375]
> oxffff © (02.12.10 14:19) [373]
>
> >Анонимные методы - это еще одно название замыканий.
>
> Это конечно буквоедство, но замыканием называется именно
> захват окружения. А анонимные методы, это анонимные методы.
>
Это конечно буквоедство, однако
http://en.wikipedia.org/wiki/Closure_(computer_science)
In computer science, a closure is a first-class function with free variables that are bound in the lexical environment.
← →
euru © (2010-12-02 14:48) [379]
> oxffff © (02.12.10 14:34) [377]
> Или все таки все типы значимые, но cкрыто(неявно) ссылочные?
Именно.
← →
Wogn (2010-12-02 14:55) [380]oxffff © (02.12.10 14:36) [378]
Где там написано про анонимность? Вас это беспокоит, вы хотите поговорить об этом? Вот, например:
(defun fun1 (arg1 arg2)
(* arg1 arg1 arg2))
(defun fun1-bind (arg1)
(curry fun1 arg1))
Где же здесь анонимные функции и иже с ними?
← →
Wogn (2010-12-02 15:15) [381]euru © (02.12.10 14:48) [379]
Помнится кое-кто из майкрософта пытался такое сделать. И что в результате получилось? Автобоксинг с кучей подводных камней? Явная реализация методов интерфейсов, способная существовать совместно с одноименными методами классов? Nullable объекты? Вы хотите эффективности при этом? У вас уже есть решения этих проблем?
← →
oxffff © (2010-12-02 15:16) [382]
> Wogn (02.12.10 14:55) [380]
Про буквоедство не я начал. Ответил Вам в Вашем стиле.
Обижаетесь?
Тогда начните плакать
anonymous method
As the name suggests, an anonymous method is a procedure or function that does not have a name associated with it. An anonymous method treats a block of code as an entity that can be assigned to a variable or used as a parameter to a method. In addition, an anonymous method can refer to variables and bind values to the variables in the context in which the method is defined. Anonymous methods can be defined and used with simple syntax.
They are similar to the construct of closures defined in other languages.
← →
Wogn (2010-12-02 15:25) [383]oxffff © (02.12.10 15:16) [382]
Ну здесь остается только сказать, что анонимный метод может не быть замыканием. (map #"(lambda (x) (+1 x)) "(1 2 3)). Где здесь замыкание? Я надеюсь, после этого, все вопросы снимаются? Честно говоря, я не понимаю, откуда они это взяли. Вы сами-то в это верите?
← →
oxffff © (2010-12-02 15:25) [384]
> Wogn (02.12.10 15:15) [381]
> euru © (02.12.10 14:48) [379]
>
> Помнится кое-кто из майкрософта пытался такое сделать. И
> что в результате получилось? Автобоксинг с кучей подводных
> камней? Явная реализация методов интерфейсов, способная
> существовать совместно с одноименными методами классов?
> Nullable объекты? Вы хотите эффективности при этом? У вас
> уже есть решения этих проблем?
А можно о сложностях в деталях?
← →
oxffff © (2010-12-02 15:29) [385]
> Wogn (02.12.10 15:25) [383]
> oxffff © (02.12.10 15:16) [382]
>
> Ну здесь остается только сказать, что анонимный метод может
> не быть замыканием. (map #"(lambda (x) (+1 x)) "(1 2 3)).
> Где здесь замыкание? Я надеюсь, после этого, все вопросы
> снимаются? Честно говоря, я не понимаю, откуда они это взяли.
> Вы сами-то в это верите?
Я не владею надстройкой над лямбда исчислениям в виде функционального языка.
Мне более понятнее будет в нотации лямбда исчисления или своими словами. Это возможно?
← →
oxffff © (2010-12-02 15:45) [386]
> Wogn (02.12.10 15:25) [383]
> oxffff © (02.12.10 15:16) [382]
>
> Ну здесь остается только сказать, что анонимный метод может
> не быть замыканием. (map #"(lambda (x) (+1 x)) "(1 2 3)).
> Где здесь замыкание? Я надеюсь, после этого, все вопросы
> снимаются? Честно говоря, я не понимаю, откуда они это взяли.
> Вы сами-то в это верите?
Прочитал про map и космический синтаксис.
Какие вопросы снимаются? У кого вопросы?
Насколько я знаю есть возможность создания функции run-time c захватом свободных переменных. Такая функция называется замыканием.
В императивных языках существует схожая возможность называемая анонимным методом. Хотите захватывайте контекст, хотите нет.
← →
Wogn (2010-12-02 15:56) [387]oxffff © (02.12.10 15:25) [384]
Если вы хотите эффективности, то вы будете использовать стек для value-объектов и будете остерегаться передавать объекты по значению. Но если нет семантики ссылок, то как передавать по ссылке value объекты? Как использовать полиморфизм? Автобоксинг/анбоксинг приходит на помощь. Вы создаете объект ссылочного тип из value-типа в куче и пользуетесь всеми прелестями. Но при этом возникает еще и куча подводных камней. Если value тип реализует интерфейс, то объекты этого типа при вызове методов интерфейса должны бокситься/анбокситься, прощай производительность. Более того, вы можете даже не подозревать когда объект боксится, а когда не боксится, вызывая метод напрямую у объекта, или у ссылки на объект (у ссылки-то понятное дело, всегда боксится, а вот у объекта может и не бокситься, так как в C# есть возможность явного описания интерфейсов, и явно описанные методы будут работать, только тогда, когда вызываются по ссылке на интерфейс). И наконец, как вы будете присваивать null value типам? Вам придется создать специальную оберкту (Nullable тип), который будет хранить информацию о том, не null ли объект? Да прочтите CLR via С#, и еще не такое увидите. null не нужен? Каковы же альтернативы null-у? Знаете ли вы какие подводные камни скрываются в альтернативах?
oxffff © (02.12.10 15:45) [386]
Ну если заниматься буквоедством дальше, то:
1. Замыкание - это ни что иное как захват окружения и оно может не возвращать функцию как результат, например, следующий код использует замыкание, но не возвращает ничего, определяя именованную top-level функцию add-1, которая захватывает переменную a.
(let (a 1)
(defun add-1 (arg)
(+ arg a))
(values))
2. Под анонимными функциями подразумевается синтаксис для определения функций, но они могут не использовать замыкания (но так как являются функциями первого класса, могут и использовать).
← →
oxffff © (2010-12-02 16:18) [388]
> Wogn (02.12.10 15:56) [387]
> oxffff © (02.12.10 15:25) [384]
>
> Если вы хотите эффективности, то вы будете использовать
> стек для value-объектов и будете остерегаться передавать
> объекты по значению. Но если нет семантики ссылок, то как
> передавать по ссылке value объекты? Как использовать полиморфизм?
> Автобоксинг/анбоксинг приходит на помощь. Вы создаете объект
> ссылочного тип из value-типа в куче и пользуетесь всеми
> прелестями. Но при этом возникает еще и куча подводных камней.
> Если value тип реализует интерфейс, то объекты этого типа
> при вызове методов интерфейса должны бокситься/анбокситься,
> прощай производительность. Более того, вы можете даже не
> подозревать когда объект боксится, а когда не боксится,
> вызывая метод напрямую у объекта, или у ссылки на объект
> (у ссылки-то понятное дело, всегда боксится, а вот у объекта
> может и не бокситься, так как в C# есть возможность явного
> описания интерфейсов, и явно описанные методы будут работать,
> только тогда, когда вызываются по ссылке на интерфейс).
> И наконец, как вы будете присваивать null value типам?
> Вам придется создать специальную оберкту (Nullable тип),
> который будет хранить информацию о том, не null ли объект?
> Да прочтите CLR via С#, и еще не такое увидите. null не
> нужен? Каковы же альтернативы null-у? Знаете ли вы какие
> подводные камни скрываются в альтернативах?
>
А внимательно читали Рихтера сами?
Про вызов интерфейсных методов у value типов?
Насколько мне помнится при вызове интерфейсного метода объект не боксится С#(вообщем ILdasm в помощь), а используется некий трюк комиплятора использующий управляемый указатель на поле активации метода(ссылка на локальную переменную).
> oxffff © (02.12.10 15:45) [386]
>
> Ну если заниматься буквоедством дальше, то:
>
> 1. Замыкание - это ни что иное как захват окружения и оно
> может не возвращать функцию как результат, например, следующий
> код использует замыкание, но не возвращает ничего, определяя
> именованную top-level функцию add-1, которая захватывает
> переменную a.
>
> (let (a 1)
> (defun add-1 (arg)
> (+ arg a))
> (values))
>
> 2. Под анонимными функциями подразумевается синтаксис для
> определения функций, но они могут не использовать замыкания
> (но так как являются функциями первого класса, могут и использовать).
>
Я не даю свои определения, а использую общепризнанные.
← →
oxffff © (2010-12-02 16:18) [389]
> объект не боксится
value тип не боксится
← →
jack128_ (2010-12-02 16:25) [390]
> а используется некий трюк комиплятора использующий управляемый
> указатель на поле активации метода(ссылка на локальную переменную).
>
какой трюк то??
int i = 10;
....
MessageBox.Show(i.ToString());
i - struct, поэтому не может наследоваться, поэтому ToString нельзя переопределить, поэтому компилятор просто вызывает конкретный метод Int32.ToString
← →
Wogn (2010-12-02 16:27) [391]oxffff © (02.12.10 16:18) [389]
Ну во всяком случае, в последнем издании С# via CLR, на странице 332 явно написано, что: "Value type instances are boxed when cast to an interface". Если приведете ссылку на опровержение, буду благодарен.
← →
oxffff © (2010-12-02 16:32) [392]
> jack128_ (02.12.10 16:25) [390]
>
> > а используется некий трюк комиплятора использующий управляемый
>
> > указатель на поле активации метода(ссылка на локальную
> переменную).
> >
>
> какой трюк то??
> int i = 10;
> ....
> MessageBox.Show(i.ToString());
>
> i - struct, поэтому не может наследоваться, поэтому ToString
> нельзя переопределить, поэтому компилятор просто вызывает
> конкретный метод Int32.ToString
Конечно это не трюк, а просто правильный анализ.
← →
jack128_ (2010-12-02 16:32) [393]
> "Value type instances are boxed when cast to an interface"
кастятся они, куда им деваться то??
← →
oxffff © (2010-12-02 16:36) [394]
> Wogn (02.12.10 16:27) [391]
> oxffff © (02.12.10 16:18) [389]
>
> Ну во всяком случае, в последнем издании С# via CLR, на
> странице 332 явно написано, что: "Value type instances are
> boxed when cast to an interface". Если приведете ссылку
> на опровержение, буду благодарен.
Постойте.
Речь идет о вызове интерфесного метода у value типа. А не о casting.
Для casting - box необходим, для гарантии того что ссылка на значение будет действительна, если интерфейс "переживет" вызов метода.
← →
oxffff © (2010-12-02 16:41) [395]
> jack128_ (02.12.10 16:25) [390]
>
> > а используется некий трюк комиплятора использующий управляемый
>
> > указатель на поле активации метода(ссылка на локальную
> переменную).
> >
>
> какой трюк то??
> int i = 10;
> ....
> MessageBox.Show(i.ToString());
>
> i - struct, поэтому не может наследоваться, поэтому ToString
> нельзя переопределить, поэтому компилятор просто вызывает
> конкретный метод Int32.ToString
Не совсем так, то что ты описал используется при вызове call или callvirt.
Поскольку значение будет жить в момент вызова его можно вызвать напрямую минуя box обертку.
← →
jack128_ (2010-12-02 16:45) [396]
>
> Не совсем так, то что ты описал используется при вызове
> call или callvirt.
а что ты имел в виду? пример кода мона?
← →
oxffff © (2010-12-02 16:55) [397]
> jack128_ (02.12.10 16:45) [396]
>
> >
> > Не совсем так, то что ты описал используется при вызове
>
> > call или callvirt.
>
> а что ты имел в виду? пример кода мона?
Допустим есть объект TSomeA и он помечен как final. Есть переменная
A:TSomeA;
при вызове А.VirtualMethod(), поскольку после A не содержит подтипов, то можно вызвать прямой вызов вместо виртуального, что положительно отразится на скорости. По идее можно вызывать и последний перекрытый родительский виртуальный метод, если он не перекрыт в TSomeA.
Вместо
.ldloc a
.callvirt .. TSomeA.VirtualMethod ..
Будет прямой вызов минуя VMT.
.ldloc a
.call .. TSomeA.VirtualMethod ..
Вроде этот мини финт пошел c JAVA.
← →
jack128_ (2010-12-02 16:58) [398]
> oxffff © (02.12.10 16:55) [397]
это то, что я описал. а в каком случае будет использоваться твой
некий трюк комиплятора использующий управляемый указатель на поле активации метода
?
← →
oxffff © (2010-12-03 08:53) [399]
> jack128_ (02.12.10 16:58) [398]
>
> > oxffff © (02.12.10 16:55) [397]
>
> это то, что я описал. а в каком случае будет использоваться
> твой
> некий трюк комиплятора использующий управляемый указатель
> на поле активации метода
> ?
Подумал. Посмотрел Рихтера(не нашел я этого в нем.
Однако в памяти осталось что именно упаковка не происходит в ассоциации методов интерфейса). Опять подумал.
Доводы против
В интерфейс в качестве неявного параметра передается контекст(насколько помню по беглым исследованиям нативного кода - это также указатель на управляемый объект, и по косвенным признакам вызовы методов object).
Boxed value type cостоит из
--> служебное поле
поля Boxed value type
Managed pointer to value type
--> поля Boxed value type
Соответственно если в теле метода интерфейса трактовать context как managed pointer to value type, то все будет OK, с одной сложностью, что в вызове через интерфейс через boxed value type, в него передаваться будет уже boxed value type с его содержимым, поскольку помимо методов интерфейса можно дергать и методы object например ToString, который виртуален и вызывается соответственно,и который физически(boxed value type) отличен от содержимого по Managed pointer to value type.
Возникает не соответствие.
Доводы за
Однако это препятствие можно было бы преодолеть по моему мнению, если использовать небольшие трюки
1. Есть две копии методов для интерфейса для value type
(очень маловероятно)
2. При вызове через интерфейс boxed value type преобразуется через stub в managed pointer to value type. Должно поддерживаться не на уровне языка, а на уровне .NET.
А тело метода интерфейса для value type использует в качестве контекста managed pointer to value type.
← →
DiamondShark © (2010-12-03 18:02) [400]
> oxffff © (03.12.10 08:53) [399]
ILdasm откроет истину.
← →
_oxffff (2010-12-04 00:31) [401]
> DiamondShark © (03.12.10 18:02) [400]
>
> > oxffff © (03.12.10 08:53) [399]
>
> ILdasm откроет истину
Ildasm не откроет истину.
А только отладчик нативного кода поможет.
Действительно при вызове через boxed объект внутри происходит подстройка смещения на начало содержимого(это хорошо видно на присвоении a = 5). Появляется префикс constrained в MSIL для tostring и каждый такой вызов создает еще по экземпляру, но кто об этом знает. Результат ожидаем поскольку
When callvirt method instruction has been prefixed by constrained thisType the instruction is executed as follows.
If thisType is a reference type (as opposed to a value type) then
ptr is dereferenced and passed as the ‘this’ pointer to the callvirt of method
If thisType is a value type and thisType implements method then
ptr is passed unmodified as the ‘this’ pointer to a call of method implemented by thisType
If thisType is a value type and thisType does not implement method then
ptr is dereferenced, boxed, and passed as the ‘this’ pointer to the callvirt of methodThis last case can only occur when method was defined on System.Object, System.ValueType, or System.Enum and not overridden by thisType. In this last case, the boxing causes a copy of the original object to be made, however since all methods on System.Object, System.ValueType, and System.Enum do not modify the state of the object, this fact can not be detected.
Очень рекомендую к просмотру под отладчиком VS в go to Disassembly режиме, а также посмотреть на состояние управляемой кучи. Новые объекты создаются рядом друг за другом. Интересно.
class Program
{
interface IMyInt
{
int func(object obj);
};
interface IMyInt2
{
int func2(object obj);
};
public struct MyValueType : IMyInt
{
public Int32 a;
public int func(object obj)
{
a = 5;
this.func2(null);
ToString();
return 5;
}
public int func2(object obj)
{
return 5;
}
}
static void Main(string[] args)
{
MyValueType a;
IMyInt b;
a.a = 3;
a.func(null);
b = a;
b.func(null);
}
}
← →
euru © (2010-12-06 12:24) [402]Если в языке используются только значимые типы, то для чего нужны операции boxing/unboxing?
← →
oxffff © (2010-12-07 09:43) [403]
> euru © (06.12.10 12:24) [402]
> Если в языке используются только значимые типы, то для чего
> нужны операции boxing/unboxing?
Это кому вопрос? :)
← →
oxffff © (2010-12-07 09:49) [404]Сейчас в YAR есть только значимые типы.
Возможности по динамической аллокации отсутствуют.
Однако в языке есть конструктор типа - типизированный указатель и операторы @ и ^.
Поэтому если будут интересные выкладки по value type, захвату, и общей семантике, то можно будет реализовать их в одном из ответвлений YAR. И потестить usability. :)
← →
euru © (2010-12-07 12:04) [405]
> oxffff © (07.12.10 09:43) [403]
> Это кому вопрос? :)
Всем, кто сможет объяснить необходимость этой операции. :)
← →
oxffff © (2010-12-07 12:31) [406]
> euru © (07.12.10 12:04) [405]
>
> > oxffff © (07.12.10 09:43) [403]
>
> > Это кому вопрос? :)
>
> Всем, кто сможет объяснить необходимость этой операции.
> :)
Boxed type - имеет схожесть с вариантным типом.
← →
Mystic © (2010-12-07 13:03) [407]
> Всем, кто сможет объяснить необходимость этой операции.
> :)
В C# она часто скрыта. А так можешь рассматривать как приведение типа.
← →
euru © (2010-12-07 14:15) [408]
> oxffff © (07.12.10 09:49) [404]
> Однако в языке есть конструктор типа - типизированный указатель
> и операторы @ и ^.
С какой целью они введены в язык?
> Поэтому если будут интересные выкладки по value type, захвату,
> и общей семантике, то можно будет реализовать их в одном
> из ответвлений YAR. И потестить usability. :)
Моих знаний, скорее всего, будет недостаточно, чтобы сделать полное формальное описание. В общих же чертах идея выглядит следующим образом.
В языке используются переменные только значимых типов. Понятие указателей и ссылок полностью отсутствует. Однако компилятор на основе анализа исходного кода сам решает, как лучше представить переменную (в виде значения либо ссылки на некий объект) и где лучше её хранить (в стеке, куче либо где-то ещё).
Все типы, скорее всего, должны обладать некими атрибутами, позволяющими компилятору управлять этими типами (например, для того чтобы можно было применять арифметические операции, у типа дложен быть атрибут, означающий что он числовой тип).
Пока придерживаюсь варианта, что должна быть явная инициализация переменных. В случае отсутствия инициализации компилятор выдаёт предупреждение. Хотя не уверен, что это возможно.
Вот как-то так. Хотелось бы критики, чтобы уточнить эту идею либо согласиться в её невозможности.
← →
oxffff © (2010-12-07 14:26) [409]
> euru © (07.12.10 14:15) [408]
> > oxffff © (07.12.10 09:49) [404]
>
> > Однако в языке есть конструктор типа - типизированный
> указатель
> > и операторы @ и ^.
>
> С какой целью они введены в язык?
Планирую создавать динамические структруры данных по старинке.
> Однако компилятор на основе анализа исходного кода сам решает,
> как лучше представить переменную (в виде значения либо
> ссылки на некий объект) и где лучше её хранить (в стеке,
> куче либо где-то ещё).
Было бы здорово увидить конкретный пример с неформальным описанием в каком случае компилятор решает что переменная должна быть на стеке, а в каком в куче.
← →
euru © (2010-12-07 15:17) [410]
> oxffff © (07.12.10 12:31) [406]
> Mystic © (07.12.10 13:03) [407]
Правильно ли я понимаю, что если бы дженерики были изначально, то боксинг бы не понадобился?
← →
euru © (2010-12-07 15:52) [411]
> oxffff © (07.12.10 14:26) [409]
> Планирую создавать динамические структруры данных по старинке.
А точно для этих целей нужны эти операторы? Разве по контексту компилятор не сможет понять, когда данные необходимо создавать динамически?
> Было бы здорово увидить конкретный пример с неформальным
> описанием в каком случае компилятор решает что переменная
> должна быть на стеке, а в каком в куче.
Например, если компилятор определит, что время жизни переменной меньше времени жизни кода, в которой она используется, то можно выделять в стеке (к примеру, локальная переменная в подпрограмме).
Другой пример. Если компилятор видит, что возвращаемое из подпрограммы значение присваивается локальной переменной в вызывающем коде, то для этого возвращаемого значения можно зарезервировать память в стеке вызывающего кода.
← →
oxffff © (2010-12-07 15:52) [412]
> euru © (07.12.10 15:17) [410]
>
> > oxffff © (07.12.10 12:31) [406]
> > Mystic © (07.12.10 13:03) [407]
>
> Правильно ли я понимаю, что если бы дженерики были изначально,
> то боксинг бы не понадобился?
В большинстве да. IMHO.
Особенно с учетом введения DLR.
Очень интересный пример
http://www.gamedev.ru/flame/forum/?id=127498
← →
oxffff © (2010-12-07 16:19) [413]
> euru © (07.12.10 15:52) [411]
>
> > oxffff © (07.12.10 14:26) [409]
>
> > Планирую создавать динамические структруры данных по старинке.
>
>
> А точно для этих целей нужны эти операторы? Разве по контексту
> компилятор не сможет понять, когда данные необходимо создавать
> динамически?
В YAR я сделаю так, как это делается например в Pascal.
> Например, если компилятор определит, что время жизни переменной
> меньше времени жизни кода, в которой она используется, то
> можно выделять в стеке (к примеру, локальная переменная
> в подпрограмме).
> Другой пример. Если компилятор видит, что возвращаемое из
> подпрограммы значение присваивается локальной переменной
> в вызывающем коде, то для этого возвращаемого значения можно
> зарезервировать память в стеке вызывающего кода.
Все же примеры на псевдоязыке были бы более нагляднее и понятнее.
Например
function abc:integer; <-значение результата динамически
a:integer; <-стек.
begin
result:=a+1;
end;
function ReturnFunction(): function ():integer <-значение результата динамически
a:integer; <-куча
begin
result:=function :integer
begin
result:=a;
end;
end;
Однако у меня нет опыта написания на функциональном языке.
Но чутье подсказывает функциональную природу подхода(свободные и связанные переменные) этих примеров. IMHO.
← →
euru © (2010-12-07 23:07) [414]
> oxffff © (07.12.10 16:19) [413]
> В YAR я сделаю так, как это делается например в Pascal.
В [360] я и предположил, что в [358] предлагается обсудить YAR. :)
Я не предлагаю из YAR убрать операторы @ и ^. Мне просто интересно, какие трудности могут возникнуть в случае их отсутствия в языке и можно ли их решить без ввода этих операторов.
> Все же примеры на псевдоязыке были бы более нагляднее и
> понятнее.
Ок. Рассмотрим предложенные примеры.
Для начала я введу такое понятие как "дескриптор" - это объект, предоставляющий компилятору необходимую информацию для правильной интерпретации элемента языка во время компиляции.function abc:integer;
Компилятор создаёт дескриптор функции abc, в котором сохраняет, пустой список входящих параметров и список, состоящий из одного элемента, исходящих параметров. Так как тип исходящего параметра функции -- Integer, то значение этого параметра может храниться в регистре, стеке или кучи, что и записывается в дескриптор исходящего параметра. Необходимый вариант будет определяться переменной, которой присваивается значение исходящего параметра.a:integer;
Компилятор создаёт дескриптор локальной переменной a, определяет её тип как Integer, а место хранения - регистр, стек, куча.begin
result:=a+1;
Здесь компилятор должен выдать сообщение об ошибке, так как переменная a ещё не инициализирована. Но пусть перед этой строкой имеется, например, строка a := rand().end;
Компилятор видит, переменная а используется только как промежуточное значение, используемое для вычисления исходящего параметра. Поэтому он выкидывает эту перенменную, а выражение rand()+1 присваивает непосредственно исходящему параметру. В принципе, компилятор может принять решение вообще определить эту функцию как inline.function ReturnFunction(): function ():integer
a:integer; <-куча
begin
result:=function :integer
begin
result:=a;
end;
end;
Здесь, в принципе, тоже ошибка с инициализацией локальной переменной а. И если, допустим, для её инициализации используется код типа a := rand();, то анализ покажет, что функция ReturnFunction() возвращает функцию rand(). Поэтому здесь также компилятор может отказаться от использования в функции переменной а, а в месте вызова функции ReturnFunction() вызывать непосредственно функцию rand().
← →
oxffff © (2010-12-08 00:14) [415]
> euru © (07.12.10 23:07) [414]
Здесь похоже больше на оптимизирующий компилятор, который отбрасывает промежуточные локации. Однако как только ветвь становится недетерминированной например появится if, то просто так отбросить промежуточные локации не получится.
Считаем что локация необходима(от нее нельзя избавиться) как установить где она должна быть размещена?
Мне все же бы хотелось больше конкретных примеров алгоритма(или его наброски) установления именно времени жизни локациии - стек, куча.
Опять же наши функции чистые? Есть ли ссылки?
> а в месте вызова функции ReturnFunction() вызывать непосредственно
> функцию rand().
Не получится поскольку ReturnFunction возравщает функцию, а не значение.
← →
Mystic © (2010-12-08 14:13) [416]
> Правильно ли я понимаю, что если бы дженерики были изначально,
> то боксинг бы не понадобился?
Тяжело все случаи закрывать generic-ами. Часто есть поля типа Data, Tag, где пользователь может хранить свои собственные данные. Если эти поля определить как Object, то как тогда в него занести int? А делать int полноценным Obejct дорого.
← →
euru © (2010-12-09 13:43) [417]
> oxffff © (08.12.10 00:14) [415]
> Мне все же бы хотелось больше конкретных примеров алгоритма(или
> его наброски) установления именно времени жизни локациии
> - стек, куча.
Если только в качестве наброска. Например, локальные переменные. Время их жизни ограничивается временем жизни подпрограммы. Изначально для всех локальных переменных подпрограммы определяется наиболее эффективный тип хранилища данных (например, для элементарных типов - регистры, для остальных - стек). Если переменная передаётся в качестве параметра в другую подпрограмму, то её тип хранилища определяется типом хранилища параметра. Если переменная присваивается другой переменной либо возвращается из подпрограммы, то её тип хранилища определяется типом хранилища переменной, принимающее это значение. Если для всех переменных элементарных типов не хватило регистров, то часть их перемещается в стек. Если же, например, по каким-либо причинам объём стека окажется меньше суммарного объёма всех претендующих на него переменных, то можно в стеке поместить максимально возможное количество переменных, а остальные переменные определить в куче. После этого можно генерировать код в соответствии с определёнными местами хранения переменных.
> Опять же наши функции чистые? Есть ли ссылки?
В [348] я вскользь коснулся этих вопросов.
Функции имеют только входящие и возвращаемые параметры. Например,(a, b) := func(b, c);
> > а в месте вызова функции ReturnFunction() вызывать непосредственно
> > функцию rand().
> Не получится поскольку ReturnFunction возравщает
> функцию, а не значение.
Некорректно выразился. "В месте присваивания результата функции ReturnFunction() присвоить непосредственно функцию rand()."
← →
euru © (2010-12-09 13:44) [418]
> Mystic © (08.12.10 14:13) [416]
> Часто есть поля типа Data, Tag, где пользователь может хранить
> свои собственные данные.
А разве эти поля нельзя сделать параметризованными?
← →
Mystic © (2010-12-09 13:54) [419]> А разве эти поля нельзя сделать параметризованными?
Можно, но для разработчиков либ это большой геморрой протаскивать все эти поля через generic. Поле Tag появляется в классе TComponent, и его придется тащить сквозь всю иерархию TControl, TWinControl, TCustomForm, TForm, ... При разработке своих компонентов мне также придется с ним мучаться. И все только ради призрачной цели, чтобы в 1% случаев, когда оно юзается, не делать лишнее приведение типа?
Не говоря о проблемах с DLL, в которой метод возвращает TForm.
Страницы: 1 2 3 4 5 6 7 8 9
10 11 вся ветка
Форум: "Прочее";
Текущий архив: 2011.03.20;
Скачать: [xml.tar.bz2];
Память: 2.04 MB
Время: 0.021 c