VladD2 wrote
> C>Как язык Дельфи не блещет особыми достижениями, в ней нет нормальных > C>средств для ручного управления памятью (умные указатели, автоматические > C>классы и т.п.), нет автоматического управления памятью, нет каких-лиюо > C>средств метапрограммирования, нет продвинутых средств типа лямбды и > C>замыканий. > Про управление памятью я уже говорил. Отсуствие ЖЦ — это конечно > недостаток, но управление памятью в Дельфи отнимало не бьльше чем при > пронраммировании на С++.
У кого как, я писал как-то на Дельфи визуальный генератор MSI-файлов (ну
заказали нам очередной велосипед...). В GUIшной части действительно все
было нормально — время жизни компонентов точно ограничено временем жизни
формы, поэтому проблем не было.
А вот когда я писал алгоритм сборки MSI-файла, то я там перематерился на
отсутствие умных указателей и нормальных контейнеров.
> Умные указатели и т.п. — это все костыли.
Нет, умные укзатели — это формализация политики владения (и
использования) объекта auto_ptr — эстафетное владение, scoped_ptr —
эксклюзивное владение, shared_ptr — разделяемое владение. Почти любую
программу можно описать в этих терминах, лишь в очень редких случаях
необходимо циклическое владение, которое не описывается нормально на С++.
Кстати, в Дельфи как раз реализована только политика эксклюзивного
владения для компонентов.
> Что касается метапрограммирования. Да его там нет. Но за то там есть > компоненты, компонентная модель
Слова "компонент" и "компонентная модель" (в понимании Дельфи) для меня
стали ругательными, если честно. Я не вижу особых преимуществ, которые
они дают по сравнению с хорошей "некомпонентной" объектной моделью.
> метаинформация оплностью отсутсвующая в плюсах.
В С++ есть метаинформация, только она доступна только на этапе компиляции.
> C>Поэтому как язык особо Дельфи никому и не нужна. > На дельфи писали, пишут и еще очень долго будут писать приложения. Во > всем мире популярность его конечно не так что у плюсов, но у нас > дельфи более чем поеулярен.
Потому что только им умеют пользоваться учителя в школах и универах, к
сожалению.
> C>А "компонентые технологии" обычно нигде кроме простого GUI и не > нужны.... > Так оно и есть... если добавить одну оговорку — лично тобой.
Могу пофлеймить на эту тему, если хочешь.
>>> В Делфьи научились обходить проблемы, но наличие ЖЦ дает >>> дополнительную свободу программисту и делает язык более высокоуровневым. > C>И при этом требует кардинального изменения в организации окружения. > Отнюдь.
Не "отнюдь", если GC — нормальный, а не консервативный.
> C>Чего-то сложнее формочек с несколькими таблицами на VB нормально не > C>пишется, так как метод "drag-and-drop контролов на форму" становится > C>неприменим, зато становится необходимой нормаль. > Опять же тобой. VB6 — с успехом использовался для создания компонентов > в трехзвенке, а об АСП я вообще молчу.
VB6 использовался (да и сейчас используется) для простых
GUI-интерфейсов. В бизнес-логике VB6 я чего-то не встречал.
Кстати, под "сложными интерфейсами" я имею в виду чего-нибудь уровня
интерфейса в MS Office.
> C>3. Отсутствие целевого рынка (VB.NET/C#+WinForms делают те же задачи, > C>что и Дельфи.NET). > Старный ты человек. На ранке могут, а вренее должны, соусуществовать > разные решения. Только одино решение приведет к застою и ушудшению > ситуации.
Да, но обычно более дешовое и качественное вытесняет со временем другие.
Чего у нас было до .NET?
1. VC6+VB6 = около $1500 (не помню уже точно).
2. Delphi в стандартной редакции = около $300.
При этом объективно Delphi проще VB+VC для многих приложений.
Соответственно, и популярность у Дельфи была немалой.
Сейчас имеем:
1. Eclipse для Java = $0
2. VS Express = $0
3. Delphi 2005, Professional = $1000
И при этом Delphi уже не имеет особых преимуществ перед той же VSE. Что
в этих условиях выберет покупатель?
Здравствуйте, Сергей Губанов, Вы писали:
VD>>Не. Делать тесты ради одного человека — это уже пребор.
СГ>Дык, а если тесты для оберонов попросить написать того человека, разьве-ж он откажется...
Если попросить его, то оберон несомненно победит.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Сергей Губанов, Вы писали:
СГ>2) Не замучаетесь на каждый чих писать все новые и новые аналоги классов ResGuard (лишние сущности)? Использование структурной конструкции finally избавляет от этой лишней писанины и структурирует программу.
Это зависит от того, на какую глубину ты способен структурироваться.
Обычное дело:
создать ресурс №1.
использовать ресурс №1.
проверить условие.
создать ресурс №2.
использовать ресурс №2.
проверить условие.
создать ресурс №3.
использовать ресурс №3.
проверить условие.
создать ресурс №4.
использовать ресурс №4.
проверить условие.
и т.д., порой получается большой итоговый №.
Со всякими scope-контоллерами подобные алгоритмы не представляют трудностей, записываются "как под диктовку". В случае try-finally мы должны либо городить новый уровень вложенности на каждый №, либо усложнять блок finally, проверяя, что мы успели создать, а что нет. Получаем скорее деструктуризацию, чем структуризацию.
. Я начал изучать его недавно, и он мне нра В "Дизайне и Эволюции С++" был такой пассажик: Бьерн сомневается, в правильном ли направлении он движется, и один из создателей языка С успокаивает его фразой "С++ — это то, чем бы мы сделали С, если бы могли". Так, вот, при ознакомлении с D у меня временами (далеко не всегда!) возникает впечатление, что D — это то, чем мог бы быть С++.
Так вот — сейчас сижу читаю мануал этого забавного языка. И возникло у меня желание делиться с окружающими интересными фактами. А раз возникло — то этим я в этой ветке и займусь. Цель этого мне видится не в ознакомлении всего РСДНа с новым языком — а в обсуждении новых или не очень концепций D и их реализации. В конце концов, если это никому не интересно — бомбочек навешаете и всех делов
Поехали!
Перегрузка операторов
Хорошая новость: она есть. Но выглядит несколько... вычурно, что ли?
В С++ мы имеем "естественный синтаксис:
class A
{
...
int operator+(int); //оператор сложения A+int
...
}
В принципе, такой синтаксис в некоторой степени самоописателен.
В D та же задача решается следующим способом:
class A
{
...
int opAdd(int); //оператор сложения A+int - функция со "специальным" именем opAdd
...
}
Результат, как бы, тот же. Но выглядит это слегка менее очевидно.
Зачем это сделано?
Во-первых, один из design goals языка D — упрощение (по сравнению с С++) лексического/синтаксического анализатора (поэтому D вообще больше склонен к словам, чем к "значками").
Во-вторых, при этом достигается довольно интересный эффект:
A a;
double d = 1/a; //как написать кастомный оператор для этого случая?
В С++ выходом из этой ситуации стали операторы — свободные функции:
class A
{
...
};
double operator/(int, A&);
А вот в D — "несимметричные операторные функции" ((с) термина мой):
class A
{
double opDiv_r(int, A&); //opDiv + _r (right)
};
Мне, откровенно говоря, такой подход нравится существенно меньше — уж очень это напоминает некоторые "неявные соглашения", которые способствуют упрощению компилятора, но не самодокументированию кода. Впрочем, думаю, привыкнуть можно
А вот — очень интересная фича операторов D: они в явном виде поддерживают "зависимые операторы":
//C++
A a, b;
if(a == b) ... //вызов A.operator==if(a != b) ... //вызов A.operator!=
//D
A a, b;
if(a == b) ... //вызов A.opEqualsif(a != b) ... //вызов !A.opEquals
то есть оператора != не существует по определению.
И даже более того: все четыре сравнения (>, <, >=, <=) выполняются одним оператором opCmp:
//C++
A a, b;
if(a > b) ... //вызов A.operator>if(a < b) ... //вызов A.operator<
//...и т.д.
//D
A a, b;
if(a < b) ... //вызов A.opCmp(b) < 0if(a > b) ... //вызов A.opCmp(b) > 0if(a <= b) ... //вызов A.opCmp(b) <= 0if(a >= b) ... //вызов A.opCmp(b) >= 0
...и вот эта фичка (несмотря на не совсем очевидное действие сравнения результата с нулем) мне кажется весьма достойной. Как и любые другие, позволяющие записывать всеобщие неявные соглашения (например: оператор != эквивалентен отрицанию оператора ==) в явном виде. Выигрыш имеем двойной: а) уверенность, что в чужом коде определены и корректно работают все операторы сравнение + б) отстутсвие необходимости повторять "руками" дурную работу.
Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.
К слову, эта идея (избавления от "ненужных операторов") не распространена на операторы вида op= (+=, -= и т.д.). Почему? То есть, конечно, логику в этом, видимо, можно найти... Но лень.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, c-smile, Вы писали:
CS>>Мон шер IT, у меня такое ощущение что ты в плену стереотипов .NET
IT>Хочешь со мной пообщаться в подобном стиле? Можно конечно было бы задвинуть что-нибудь типа "Вам бы, уважаемый, сначала калькулятором научиться пользоваться, а уже потом рассуждать о программировании..", но мне это уже давно не интересно. Да и бывает что в баню я за это отправляю, придётся потом самого себя банить. Так что давай оставим другим сарказм, сатиру и юмор, переходящие в неуклюжие упражнения в демагогии. Ok?
Это угроза или я чего-то не понял?
Игорь, если я обидел чем приношу свои извинения.
IT>А в плену я у здравого смысла. И подобный механизм у меня вызывает вполне законное недоверие. Если у тебя есть убедительные цифры и аргументы, то я с удовольствием их выслушаю. Точно такое же недоверие в своё время у меня вызывала производительность GC, по-этому я это дело тщательно проверял.
Игорь Ткачев:
При увеличении числа одновременно живущих объектов ещё на порядок ситуация стала ещё более печальной для GC. Теперь выигрыш заканчивается на 75 байтах, и далее GC начинает отставать, проигрывая в десятки раз, а при размере объектов в 5000 байт GC вообще впал в анабиоз часа на три, в то время как хипы уверенно справились с задачей за несколько минут.
Automatic vs. Explicit Memory Management:
Settling the Performance Debate
Matthew Hertz and Emery D. Berger
Dept. of Computer Science
University of Massachusetts
... we execute a range of unaltered
Java benchmarks using both garbage collection and explicit
memory management. Comparing runtime, space consumption,
and virtual memory footprints, we find that when space is plentiful,
the runtime performance of garbage collection can be competitive
with explicit memory management, and can even outperform
it by up to 4%. We find that copying garbage collection can
require six times the physical memory as the Lea or Kingsley allocators
to provide comparable performance. We also show that garbage
collection suffers orders-of-magnitude performance penalties
when paging occurs. This first-ever comparison of explicit memory
management and copying garbage collection shows where garbage
collectionmust improve in the future. While we expect the incorporation
of L3 caches to minimize the impact of garbage collection’s
poor L2 locality, the relative cost of disk latency continues to grow.
Improving the space efficiency and page-level locality of garbage
collection will thus become increasingly important.
Источник вот здесь.
CS>>Начать с того что выражение "выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти" вернО до тех пор пока ты говоришь только о выделении памяти. CS>>Но если рассматривать весь объем затрат на GC включая copying/generation management то тут имхо имеем паритет с C++. В С++ выделение памяти медленне но нет таких "менопауз".
IT>Ты на основании чего судишь? На основании собственных догадок или научных экспериментов? Я это утверждаю на основании проведённых тестов
Я руками сделал generational GC для своей VM. На самом деле для трех на сегодняшний момент.
Смею думать что и я тоже имею право судить о достоинсвах и недостатках GC и heap.
CS>>Вообще как ты понимаешь чудес нет в memory management. Мы как-то постоянно об этом забываем. CS>>Тут всегда trade-off: где-то теряем, где-то находим.
IT>Именно об этом я говорю. Чудес не бывает.
Вот. Можем же договариваться если непредвзято подходить?
CS>>Выжать максимум можно только если ты можешь варьировать обеими подходами в "тонких" местах. CS>>Что в D как раз и возможно.
IT>Мда... Хип и GC — это две принципиально разные вещи. Как можно скрестить бульдога с носорогом и получить в результате белого лебедя я совершенно не понимаю Объясни мне убогому.
Да все очень просто. Оставь GC функции именно garbage collector'а а не компактификатора
памяти и всего прочего.
Т.е. new аллоцирует объекты на хипе и регистрирует их в (глобальном) списке.
Т.е. ты можешь сделать delete конкретного объекта как обычно.
А можешь попросить все объекты в хипе просканировать себя (mark)
и выполнить затем опять же delete тех объектов которые не помечены (sweep)
Что тебе это дает?
Те же возможности работы с памятью что и в C/C++ плюс
устраняет потребность во всякого рода "умных" указателях
и жесткой потребности в explicit deletion.
И все! и не надо из GC вообще делать краеугольный камень.
Одна из многих фич которая решает отдельную задачу.
CS>>И еще. И в С++ и в D написание своего domain specific аллокатора делающего "выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти" это дело 15 минут. Переопределить new/delete и выбрать способ выделения буфера.
IT>Только не забудь упомянуть про цену такого решения
Я не понял про цену. цена чего?
На этом принципе (domain specific аллокатор) работают
такие штуки как Apache и Subversion. Там вообще все еще красивее устроено.
memory pools которыми можно независимо управлять.
There are four general-purpose pools always available in Apache:
the request pool, with the lifetime of an HTTP request.
the process pool, with the lifetime of an server process.
the connection pool, with the lifetime of a TCP connection.
the configuration pool.
CS>>Далее. "ложит сишный хип на лопатки на выделении большого количества маленьких объектов."
CS>>А зачем собственно выделять это самое большое количество маленьких объектов? CS>>Когда это можно сделать одним единственным выделением?
IT>А зачем мне одно единственное выделение, когда я могу выделять по мере необходимости? С GC результат будет тот же.
Ну вот снова... А удалять как?
А кто твою тучу объектов сканировать будет на предмет обнаружения ссылок.
Без фазы mark еще никто не обошелся.
А кто потом копировать оставшиеся объекты будет?
Ты ж вроде сам об этих проблемах написал?
CS>>В D и в C++ такой ерундой не занимаются. vector<int> там это один кусок памяти, а не массив указателей на int выделенных в managed memory space.
IT>Вот только не надо нам рассказывать про vector, более тупого варианта распределения памяти я не встречал. Без явного вызова reserve на больших объёмах данных можно легко "дать фору" любому GC.
Согласен обеими руками!
Ну дык думающий мозг ((С) McSeem2) он везде ж нужен.
И GC можно "посадить" и explicit memory allocators с не меньшим успехом.
CS>>Еще раз говорю истина как всегда посредине — между "только heap" и "только GC". CS>>И вот там, в этой золотой середине, и сидит D
IT>Не верю. (c)
Ну вот допишу свою Harmonia увидишь.
Честно, D — рулез.
Уже в общем и так видно.
Я думаю для людей серьезно программирующих на Java
и .NET и познавших "блеск и нищету куртизанок"
D представляет очень серьезный интерес. ИМХО, конечно.
Да, где-то местами своеобразный, но в общем и целом — кайф.
CS>>На самом деле я Вальтеру предложил ввести механизм memory pools — CS>>тогда вообще можно говорить CS>>new(myGenerationalMemoryPool) MyObject, CS>>new(myMarkAndSweepMemoryPool) MyObject, CS>>new(Heap) MyObject.
IT>И что это даст? Добавление в результате ещё одного менеджера менеджеров памяти?
Возможность оптимально выбирать в первую очередь.
На каких-то задачах один GC лучше на других — другой. На третьих — хип.
Возможность например "грохнуть" пул как одно целое и забыть
про все объекты там нааллоцированные. Например HTML страница со своим DOMом
при выгрузке оной может быть просто удалена как одно целое.
IT>А вообще, котята такие — мне не нравится, что вместо доказательств в защиту D ты всё время скатываешься на поиск недостатков в .NET. Странная манера. Мы же в этом топике не .NET обсуждаем, правда? Но если тебе хочется, давай исходить из того, что .NET плохой, даже очень плохой, можешь больше не пытаться мне это доказать. Лучше докажи, что D хороший. Если получится, то кто знает, может потом вместе доказывать будем
Да не скатываюсь я. Меня скатывают это да.
Ты прочти внимательно любую ветку от root и до конца.
Я никогда ничего про .NET на пустом месте и по своей инциативе
не говорю. У меня просто идиосинкразия на любые попытки меня "построить строем".
Все на .NET! А зачем, а почему и кому это выгодно?
Никто толком не показывает, не рассказывает и не демонстрирует.
Добавлю от себя: Не существует неинициализированных стековых переменных
byte[100] array; // будут инициализированны по умолчанию.
Все функции классов по умолчанию виртуальны
Оптимизацией с выкидыванием ненужной виртуальности занимается компилятор.
А учитывая, что методы могут быть перегруженными, то фактически получаются перегружаемые виртуальные функции...
Передача параметров в функции
По умолчанию все in. Для out & inout нужно указывать специально. Причем для out переменная инициализируется по умолчанию или вызывается соответствующий конструктор.
void foo(out int bar)
{
}
int bar = 3;
foo(bar);
// bar is now 0
Здравствуйте, Сергей Губанов, Вы писали:
СГ>А разьве это не всегда так? Разьве деструктор может позвать кто-то еще кроме GC? Если да, то зачем?
СГ>(Например, в Component Pascal, вызвать финализатор может только GC и никто другой, это потому что виртуальный пустой метод FINALIZE()- экспортируется "только для реализации", но не для вызова).
В D как и в C++ есть оператор delete.
Но в D есть еще и GC при этом.
Что есть (GC и delete вместе) *очень* разумно.
Выделил — убери за собой.
Не можешь убрать сейчас? Ладно, тогда оставь дворнику.
Но труд дворника надо уважать. У него "много вас ходють".
Оптимистичный подход в стиле "А вот программуля "Радость garbage collector'а""
уж очень смотрится... некузяво... это тебе любой
советский инженер (ТМ) скажет.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>>>А можно? Хочу Буду Влада пугать IT>>А ну ка попробуй чего-нибудь написать
ЗХ>ой, какая прелесть А можно это так и оставить?
Я тоже за, о великий и ужасный Зверёк.
ЗХ>ЗЫ: жаль, в Янусе все равно не видно
"Сказку о старике и рыбке" помнишь? Что там со старухой случилось?
Здравствуйте, c-smile, Вы писали:
CS>Это угроза или я чего-то не понял?
Боже упаси. Не имею такой дурной привычки. Это просто попытка направить разговор в конструктивное русло. Ведь всегда приятно пообщаться с умным человеком, но именно пообщаться, а не покидаться друг в друга какашками. Это даже звучит неестественно — "Всегда приятно покидаться друг в друга какашкам с умным человеком"
CS>Игорь Ткачев: CS>
CS>При увеличении числа одновременно живущих объектов ещё на порядок ситуация стала ещё более печальной для GC. Теперь выигрыш заканчивается на 75 байтах, и далее GC начинает отставать, проигрывая в десятки раз, а при размере объектов в 5000 байт GC вообще впал в анабиоз часа на три, в то время как хипы уверенно справились с задачей за несколько минут.
CS>Это ж ты сам написал как я понял?
Я. Но так же я написал, что это крайние случаи, которых в жизни практически не бывает. GC от майкрософт во многом основана на статистике. Она очень хорошо оптимизирована именно под наиболее частые случаи. Вариант, когда мы имеем в памяти 100к объектов размером по 5к, согласись, к таким не относится. Это всё же 5 гиг не просто выделенной, но и используемой в данный момент памяти. Меня в данном случае интересовали тенденции. Но, конечно же надо признать, что сишный, а точнее виндовый, хип с такой задачей вполне успешно справляется.
CS>Вот еще
CS>Automatic vs. Explicit Memory Management: CS>Settling the Performance Debate
Так никто же и не спорит. Мы же уже договорились — чудес не бывает, за всё надо платить. С другой стороны, возмём к примеру наш RSDN'овский сервер. .NET приложениям его памяти хватает без проблем, главный потребитель памяи у нас SQL сервер. Вот где-где, а в нём, думаю, работа с памятью вылизана до последнего байта. Тем не менее жрёт он как ни в себя. Оно и понятно, объём базы у нас не маленький. Но факт есть факт — объём используемой памяти зависит не столько от GC, сколько от решаемых задач.
CS>Я руками сделал generational GC для своей VM. На самом деле для трех на сегодняшний момент. CS>Смею думать что и я тоже имею право судить о достоинсвах и недостатках GC и heap.
Вот видишь как здорово! Тогда тем более тебе не составит труда объяснить мне как GC и хип могут вместе работать быстрее чем пораздельности. Я честно не понимаю как такое может быть.
IT>>Мда... Хип и GC — это две принципиально разные вещи. Как можно скрестить бульдога с носорогом и получить в результате белого лебедя я совершенно не понимаю Объясни мне убогому.
CS>Да все очень просто. Оставь GC функции именно garbage collector'а а не компактификатора памяти и всего прочего.
Т.е. попросту говоря, мы исключаем из GC функцию упаковки памяти? Вот этого я больше всего и опасался. Фактически, мы убираем то, за счёт чего GC может тягаться с хипами — её самую сильную в плане быстродействия часть, и оставляем самую медленную — поиск живых ссылок... Хотя возможно я и тут не прав. Вариант о котором ты говоришь занимается поиском живых или мёртвых ссылок? Это тоже принципиальный для быстродействия вопрос.
CS>Т.е. new аллоцирует объекты на хипе и регистрирует их в (глобальном) списке. Т.е. ты можешь сделать delete конкретного объекта как обычно. А можешь попросить все объекты в хипе просканировать себя (mark) и выполнить затем опять же delete тех объектов которые не помечены (sweep)
А как объект узнает что на него есть ссылка? Например, эта ссылка может находится в данный момент в стеке другого потока или вообще в регистрах процессора.
CS>И все! и не надо из GC вообще делать краеугольный камень. CS>Одна из многих фич которая решает отдельную задачу.
То о чём ты говоришь скорее напоминает не GC, а хелпер по удалению памяти. Впрочем, чтобы судить хорошо бы получить ответы на предыдущие вопросы.
CS>>>И еще. И в С++ и в D написание своего domain specific аллокатора делающего "выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти" это дело 15 минут. Переопределить new/delete и выбрать способ выделения буфера.
IT>>Только не забудь упомянуть про цену такого решения
CS>Я не понял про цену. цена чего?
Свой аллокатор должен либо заранее знать объём памяти, которая будет запрошена, либо предётся её перевыделять и то, что выделенный кусок окажется по тому же адресу маловероятно. Следовательно, либо надо будет корректировать все указатели либо использовать относительную относительно аллокатора адресацию.
CS>На этом принципе (domain specific аллокатор) работают такие штуки как Apache и Subversion. Там вообще все еще красивее устроено. memory pools которыми можно независимо управлять.
Согласен в Apache это может дать определённый эффект. В IIS такая же фигня. Причём малоизвестная и почему-то не очень рекомендуемая MS для интенсивного использования
IT>>А зачем мне одно единственное выделение, когда я могу выделять по мере необходимости? С GC результат будет тот же.
CS>Ну вот снова... А удалять как? CS>А кто твою тучу объектов сканировать будет на предмет обнаружения ссылок. CS>Без фазы mark еще никто не обошелся. CS>А кто потом копировать оставшиеся объекты будет? CS>Ты ж вроде сам об этих проблемах написал?
GC. Причём, если я не буду держать всё это барахло бесконечно долго в памяти, то маркать осебенно ничего не надо будет. Дотнетовский коллектор ищет только живые ссылки.
CS>Честно, D — рулез.
А что нужно чтобы на нём начать писать? Он в студию как-нибудь встраивается? А то я ленивый стал, изучать новые текстовые редакторы в лом.
IT>>И что это даст? Добавление в результате ещё одного менеджера менеджеров памяти?
CS>Возможность оптимально выбирать в первую очередь. CS>На каких-то задачах один GC лучше на других — другой. На третьих — хип.
Самое прикольное, что за долгие годы работы на плюсах, свой уникальный хип мне понадобился лишь раз и как раз на задаче, где интенсивно выделялась и освобождалась память маленькими кусочками, нарвался тогда на жуткую дефрагментацию. GC с этой проблемой справился бы легко. На шарпе я пока проблемой уникально пула за три года не озадачивался ни разу. Правда три года не столь большой срок, да и клепаю я сейчас в основном интерпрайзы, где GC самое то. Неправильное использование памяти видел. Например, берём файл, закачиваем в память, конвертируем, зипуем, шифруем, перекрашиваем в оранжевый цвет, отправляем по сети. Очень ресурсоёмко. Чем больше файл, тем больше проблем. Решилось всё путём перехода на стримы, т.е. решение в равной степени применимое и для GC и для хипа.
Более того. Я не хочу об этом думать вообще, ни о каких пулах и хипах. Я хочу видеть в своём прикладном коде только бизнес-логику. Любое смешивание бизнес-кода с пулами меня очень сильно огорчает и расстраивает. В каком-нибудь фреймворке это всё вполне возможно, но там другие требования к коду. Да и там, как я уже сказал выше, это большая редкость.
CS>У меня просто идиосинкразия на любые попытки меня "построить строем".
Т.е. ты не любишь .NET потому что тебя туда тянут за рукав?
CS>Все на .NET! А зачем, а почему и кому это выгодно? CS>Никто толком не показывает, не рассказывает и не демонстрирует.
Тут такое дело. Аргумент "Мой код стал проше" может быть услышан только если слушатель хочет это слышать. В противном случае ты получишь ответ про кривые ручки и плохой дизайн. Я уже вот здесь
высказывался на тему что я считаю идеальным кодом. Могу лишь добавить, что пока я писал на плюсах, я об этом даже не задумывался, а сейчас вот начал
Видишь, опять у меня демонстрации не получилось, одна балтология В общем, не знаю я как доказать, что .NET круче. Слишком много всего и про всё можно сказать, что всё тоже самое можно сделать на плюсах. Я сам ещё несколько лет назад готов был затоптать любого джависта неосторожно выкрикнувшего при мне "C++ суксь", а теперь, с определнными оговорками могу и сам это утверждать
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, eao197, Вы писали: E>В подходе же с opCmp я уже не могу просто сделать сравнение на "строго меньше". Мне в любом случае придется предоставлять варианты для случаев "равно" и "строго больше" . И если я по своей лени в D напишу что-то подобное: E>
E>class Compound_Key
E>{
E> int opCmp( Compound_Key o )
E> {
E> if( a_ < o.a_ || ( a_ == o.a_ && b_ < o.b_ ) )
E> return -1;
E> // Оптимистично предполагаем, что всегда будет использоваться (c1<c2).
E> return 0;
E> }
E>};
E>
E>то приведенная тобой конструкция (if(a>b)) на этапе компиляции вообще ошибки не диагностирует.
так писать нужно так
class Compound_Key
{
int opCmp( Compound_Key o )
{ int Result;
Result =a_.opCmp(o.a_);
if (Result!=0) return Result;
Result =b_.opCmp(o.b_);
if (Result!=0) return Result; // и продолжить столько раз, сколько полей
Result =c_.opCmp(o.c_);
return Result;
}
};
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, AndrewVK, Вы писали:
AVK>>Здравствуйте, eao197, Вы писали:
E>>>Зря он так предполагает E>>>Например, при логировании __FILE__ и __LINE__ здорово помогают. Как и макросы, кстати.
AVK>>Еще один важный кусок задач — кодогенераторы.
E>Да, я тоже хотел об этом сказать. Но поскольку в исходном сообщении ЗХ не было упомянута директива #line, то решил об этом не говорить. К тому же, при желании, кодогенераторы могут сами подсчитывать номера строк в генерируемом коде Хоть это и геморройно.
Special Tokens
These tokens are replaced with other tokens according to the following table:
Special Token Replaced with...
__FILE__ string literal containing source file name
__LINE__ integer literal of the current source line number
__DATE__ string literal of the date of compilation "mmm dd yyyy"
__TIME__ string literal of the time of compilation "hh:mm:ss"
__TIMESTAMP__ string literal of the date and time of compilation "www mmm dd hh:mm:ss yyyy"
Здравствуйте, c-smile, Вы писали:
CS>Т.е. если у тебя есть некий временный объект который тебе более не нужен — удали его. CS>И работы GC будет меньше — т.е. сборка мусора будет занимать меньше времени.
Знаешь какая функция больше всего мешает нормальной работе многопоточных приложений? Правильно, Sleep. Ты думаешь она передаёт управление другому потоку и сохраняет тем самым процессорные тики. Но на самом деле она вмешивается в процесс переключения задач и заставляет систему по новой пересчитывать своё состояние.
Процесс вмешательства в работу GC ничем не лучше. Есть только один способ этому не повредить — delete ничего не должен делать с памятью. Т.е. программисты пусть свято верят и радуются жизни, но delete не трогает память. Память потом подчистит GC. Я искренне надеюсь, что в D это реализовано именно так, в противном случае при использовании деструкторов тормозов не избежать.
CS>Достоинства по моему очевидны.
Совсем не очевидны. Я не знаю как работает диспетчер памяти в D, но зато очень хорошо представляю как работает GC в .NET и сишный хип. GC по скорости легко ложит сишный хип на лопатки на выделении большого количества маленьких объектов. Достигается это тем, что выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти. Никаких поисков наиболее подходящих кусков памяти, как в хипах. Теперь, в D, я вызываю деструктор и ты утверждаешь что память освобождается. Куда она освобождается? Запускается GC? Бред. Заносится в список неиспользуеых блоков памяти как в хипах? А потом что? При выделении памяти будем их просматривать? Тогда теряем всё преимущество скорости GC. В общем, я бы попытался с этим разобраться прежде чем столь наивно радоваться такой фиче.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
CS>>Что есть (GC и delete вместе) *очень* разумно.
IT>Я очень сильно сомневаюсь. Как бы не получился совершенно обратный эффект
А в чем сомнения?
delete в C++ есть? есть...
хорошо это или плохо? Хорошо. Для задач которые решает C++.
GC в .NET есть? есть...
хорошо это или плохо? Хорошо. Для задач которые решает .NET
В D есть и то и то.
Значит D может решать задачи С++ и .NET не выходя из одной среды.
В D такой проблемы выбора — managed/не managed — просто нет.
Т.е. если у тебя есть некий временный объект
который тебе более не нужен — удали его.
И работы GC будет меньше — т.е. сборка мусора будет
занимать меньше времени.
Достоинства по моему очевидны.
delete оператор еще одним свойством обладает
как и в C++ — вызов деструктора и метода delete
класса (В D можно переопределять new и delete).
Недостаток единственный — можно "выплеснуть младенца".
Но это решается легко — если есть малейшие сомнения —
не удаляй.
Здравствуйте, VladD2, Вы писали:
CS>> У меня просто идиосинкразия на любые попытки меня "построить строем". CS>>Все на .NET! А зачем, а почему и кому это выгодно? CS>>Никто толком не показывает, не рассказывает и не демонстрирует.
VD>Мне кажется у тебя действительно эта как ее... Строить никого не собираются. Просто дотнет действительно досойный продукт. И уж если зашло сравнение его с Ди, так лучше не скатываться до демагогии и оскорблений, а действительно описать те приемущества которые ты заметил в Ди. Пока ты назвал только одно — возможность писать небезопастный код и упралвлять вручную памятью. Вот это и кажется очень сомнительным.
Я дико извиняюсь но кажется моя фраза про попытки "построить строем"
вызывает двоякое толкование.
Я имею ввиду следующе:
GC сам по себе как механизм полезен.
Но стремеление сделать "все на GC" ("все managed") мне представляется
порочным и скажем так технически неграмотным.
GC это всего лишь один из возможных способов memory management и далеко
не всегда самый эффективный.
Конкретный пример:
Тут где-то пролетала ссылка на HTML renderer написанный как
100% managed .NET component (буду признателен если кто-то её напомнит опять)
Здравствуйте, c-smile, Вы писали:
E>>>>Зря он так предполагает E>>>>Например, при логировании __FILE__ и __LINE__ здорово помогают. Как и макросы, кстати.
AVK>>>Еще один важный кусок задач — кодогенераторы.
E>>Да, я тоже хотел об этом сказать. Но поскольку в исходном сообщении ЗХ не было упомянута директива #line, то решил об этом не говорить. К тому же, при желании, кодогенераторы могут сами подсчитывать номера строк в генерируемом коде Хоть это и геморройно.
CS>Зверь читает доку квадратно-гнездовым образом
CS>Есть там это все...
Тьфу блин, точно пойду повешусь. Я же это все там видел!
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Да я вот все думаю, с какой бы стороны подступиться к интеграции его с С++ными библиотеками... ИМХО, решение должно быть где-то рядом SWIG
Вроде кто-то реализовывал поддержку D. Самые новые исходники там, в svn репозитории. В каком это состоянии, я не в курсе, но возможно во вполне работоспособном. Вот страница с более старыми версиями(включая бинарники) и хоть каким-то описанием.
D, оставаясь наследником C++ по духу, все же решает задачу, об которую (по общеизвестным причинам) в свое время обломал зубы Бьярн. Препроцессора нет.
Возникает закономерный вопрос: а что есть и хватает ли этого?
Ответим на этот вопрос по порядку задач, решаемых препроцессором.
Макросы-константы и макросы-"функции"
Проблема решена еще в С++ — обычными константами и инлайновыми функциями (заметим в скобках, что ключевого слова inline в D нет — подстановка функций остается полностью на совести компилятора).
#include
Директива текствого включения исключена за ненадобностью — в D есть модульность.
Определение модуля:
module mymodule; //этого можно не писать. тогда имя модуля совпадет с именем файла, в котором содержится модуль
//еще можно так:
module mypackage.mysabpackage.mymodule; //логическая группировка модулей в "пакеты"
version(UNICODE) //символ, переданный в качестве ключа компилятору
{
....
}
else
{
....
}
Заметим, что в стандарте D заложена дихотомия Debug/Release, то есть следующая кострюхция будет работать без каких-либо дополнительных телодвижений:
version(Debug)
{
...куча дебужного коду...
}
Кроме того, D придает специальный смысл конструкции if(0) — она является аналогом препроцессорного #if(0) в С/С++ — то есть все, что внутри соответствующего блока, не будет компилироваться.
__LINE__, __FILE__ и др.
D предполагает, что единственный смысл использования "особых макросов" — информативность выражения assert. Соответственно, в D выражение assert является не библиотечной функцией, а частью core language, благодаря чему "само" знает, на какой строке и в каком файле приключилось.
#error и static assert
Как слышится, так и пишется
static assert(int.sizeof >= 4);
#pragma
Для некоторых общеупотребительных прагм у D есть свои конструкции (#pragma pack => align), некоторые не нужны вообще (#prgama once). Для всех остальных остается-таки ключевое словечка pragma в core language.
Дальше и дальше...
Дальше — это уже template's & mixin's. О которых — в следующей серии
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
ЧАСТЬ 4: синтаксический сахар, синтаксический мусор...
про всякие фишечки синтаксиса — вроде бы и не особо нужные, но занятные
Комментарии:
//однострочный комментарий - как в С++
/*
многострочный комментарии - тоже как в С++
*/
/+
вложенный комментарий - вот такого С++ не умеет ;)
/+
это вложено
+/
тут - все еще комментарий
+/
//C++
//модификаторы доступа:class A
{
public:
//ниже пошли паблики
....
private:
//ниже пошли приваты
....
}
staticint boo();
constint a;
//D - свобода выбора======================class A
{
public:
//ниже пошли паблики
....
protected int foo(); //protected относится только к этой функцииprivate
{
//private относится ко всему, что в этом блоке
....
}
}
staticint boo();//одна статическая функцияstatic
{
//блок статических функций
}
static:
//все, ниже пошли статики...
//с const и вообще всеми модификаторами - аналогичная фигня:constint a;
const
{
//куча констант
}
const:
//дальше все нафик константное
Специальные занятные аттрибуты:
//Выравнивание:
align(1) char some_byte;
align(4)
{
//all here is aligned by 4
}
//deprecated:
deprecated
{
int foo();
void boo();
/*
таким аттрибутом можно пометить части библиотеки, которые могут быть
удалены в следующих релизах. Реакция на этот аттрибут зависит от оп-
ций компилятора. Его можно настроить так, чтобы он выдавал предупре-
ждение, ошибку или молчал на использование deprecated фич.
*/
}
//overrideclass A
{
override int foo(); //эта функция обязана быть у моего предка (я хочу заместить функцию предка.
//если ее там нет или у нее другой набор параметров - это ошибка
}
//Гарантируется, что вот такой массив:int[3][6] Matrix;
//- то есть статический массив статических массивов
//хранится в памяти как матрица, то есть все значения идут подряд.
строки в стиле WYSIWYG (What You See Is What You Get):
//Инициализация структур:struct S
{
int a;
char b;
float f;
}
S s = {5, 'a', 0.3}; //можно - как в С++
S s = {b:'a'}; //явная инициализация члена b, остальные проинициализируются по умолчанию
//Инициализация массивов:int[10] arr1 = {0,1,2,3,4,5,6,7,8,9}; //как в С++int[10] arr2 = {1:18, 6:10, 9:-1}; //теперь содержимое arr2 == {0, 18, 0, 0, 0, 0, 10, 0, 0 ,-1}
Еще фишечки:
* switch — возможен по integral types, а так же по строкам; неучтенное значение при отсутствии default: вызовет исключение.
* try — имеет не только catch, но и finally.
Уф... умаялся.
To be contin.......................
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>А вот — очень интересная фича операторов D: они в явном виде поддерживают "зависимые операторы": ЗХ>
ЗХ>//D
ЗХ>A a, b;
ЗХ>if(a == b) ... //вызов A.opEquals
ЗХ>if(a != b) ... //вызов !A.opEquals
ЗХ>
ЗХ>то есть оператора != не существует по определению.
ЗХ>И даже более того: все четыре сравнения (>, <, >=, <=) выполняются одним оператором opCmp:
С точки зрения производительности я бы не назвал opCmp однозначным рулезом.
Во избежание сюрпризов надо писать так:
int opCmp(T a, T b)
{
if(a < b) return -1;
if(a > b) return 1;
return 0;
}
С учетом наличия методов у простых типов, можно, конечно писать return a.opCmp(b), но при этом компилятор все равно обязан сгенерировать код приведенный выше. Иначе — чревато сюрпризами. То есть, снаружи выглядит конечно удобно, но внутри подпадает под случай "вылить воду из чайника и таким образом свести задачу к предыдущей".
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, IT, Вы писали:
IT>>Оберон ещё не забудь. Судя по тестам кульный язык.
VD>Не. Делать тесты ради одного человека — это уже пребор.
Дык, а если тесты для оберонов попросить написать того человека, разьве-ж он откажется...
Здравствуйте, eao197, Вы писали:
ЗХ>>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
E>Вообще-то я не думаю, что сравнение объектов, которые используются в качестве ключа map-а бессмыслено. Ведь в std::map ключи элементов как раз-таки сравниваются
E>А пример мой был к тому, что если в C++ мне потребуется сделать класс, от которого средства языка (std::{multi}map, std::{multi}set, std::find, ...) требуют только наличия operator<(), то я и реализую только это. И если от моего класса начинают требовать чего-то еще, то тут же получают по рукам.
На что я и ответил: по сути, существует два омонима: оператор "меньше" (в "численном" смысле. Преполагает наличие операторов больше, меньше-равно, больше-равно, равно, неравно...) и оператор порядка ("предыдущий").
Первый используется в "арифметических" операциях (a+b < c+d*x); второй — только и исключительно (кажется ) для создания сортированных последовательностей.
Грубо говоря, complex::operator< ты скорее всего будешь использовать "лично", а string::operator< тебе нужен только для того, чтобы можно было создавать всякие штуки вроде сортированных списков — либо для представления их пользователю, либо для эффективных алгоритмов. Так?
То есть в идеале строк вида if(string1 < string2) в прикладном коде ваааще не встретится.
Соответственно, в случае "арифметического оператора" ему нужны соответствующие дополнительные операторы; в случае "оператора порядка" — не, не нужны.
А еще какие-то случаи ты можешь придумать, когда тебе нужен только 1 оператор, а не все?
E>И если я по своей лени в D напишу что-то подобное:
...
E> int opCmp( Compound_Key o )
E> {
E> if( a_ < o.a_ || ( a_ == o.a_ && b_ < o.b_ ) )
E> return -1;
E> // Оптимистично предполагаем, что всегда будет использоваться (c1<c2).
E> return 0;
E> }
...
E>то приведенная тобой конструкция (if(a>b)) на этапе компиляции вообще ошибки не диагностирует.
А вот тут не могу не согласиться. Еще одно замечание не в пользу D — для использования в качестве ключа ассоциативного массива (в D они являются частью core language) класс должен иметь-таки opCmp (а кроме того, кстати, еще и функцию Hash() )
ЗЫ: я все еще не доказываю превосходство/уродство D, а показываю штуки, которые мне в нем показались занятными
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Два последних оператора — не очень-то рулез по производительности. Зато по очевидности — это, имхо намного лучше, чем "многозначный" оператор из D
Этот "многозначный" оператор придуман в первую очередь для случаев, когда сравниваемые значения(или их часть) можно привести к целочисленному типу. Такая модель сравнения давным-давно используется скажем в libc(strcmp, qsort, итд), Java(интерфейс Comparable), .NET(IComparable).
Что может быть проще и очевидней вот такого кода?
class Task
{
private int priority;
public int opCmp(Task t)
{
return priority - t.priority;
}
}
C>void foo(out int bar)
C>{
C>}
C> int bar = 3;
C> foo(bar);
C>// bar is now 0
Вот это то, что мне сильно не нравится в C++ и нравится в C#. Слово "out" или "ref" надо заставлять писать не только в объявлении, но и при вызове. Читаемость кода улучшается многократно. И компилятору легче. А умственный мозг, читающий чужой код — это один из вариантов компилятора и есть.
Здравствуйте, Сергей Губанов, Вы писали:
ЗХ>> вызов конструкторов базового класса — в любом месте конструктора. если нет явного вызова, вызовется в самом начале this()
СГ>А если не хочется вызывать его вовсе? Например, в Delphi конструктор базового класса можно вызвать, а можно не вызывать, как больше нравится (аналогично — деструктор).
ИМХО, если возникла такая ситуация, где ты от базового класса отнаследовался, а конструктор его вызывать не хочешь — нефик было наследоваться.
Если по-научному, то объект для которого не был вызван конструктор, не может предоставить вообще никаких гарантий непротиворечивости своего состояния. Это относится, в частности, и к базовому подобъекту.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[10]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Сергей Губанов,
LCR>>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы).
СГ>Странно, а какая связь между вирутальными (абстрактными) конструкторами (с которых началаясь эта ветка форума) и умными указателями . Я всегда думал, что умные указатели растут из templates + автоматический вызов деструкторов при выходе из блока.
Умный указатель возможен и без использования шаблонов — просто возникает необходимость в приведении типов на стороне клиента, а это неудобно. С шаблонами проще и надёжней. А вот автоматический вызов конструкторов и деструкторов — ключевой механизм.
СГ>С другой стороны, Вы говорите об уже устаревшей Delphi-7, ведь Delphi-8 (на же Delphi for .NET) и Delphi-9 (она же Delphi 2005) стали писаться под .NET, потребность в умных указателях как бы пропала — работает натуральная сборка мусора.
Сборка мусора обкладывается на таких простых вещах:
lock.acquire(obj);
Если lock недолгоживущий, то в случае Delphi мы пишем:
lock.aquire(obj);
...
lock.release(); // do not forget!
в случае С++ мы пишем
{
Lock lock(obj);
...
// free your mind!
}
Lock — это умный класс, он захватывает ресурс в конструкторе и освобождает в деструкторе. Если же lock — долгоживущий, то тут только взгляд и руки.
finally. В случае Дельфи мы пишем:
try
res.acquire();
obj.explode(random(2)); // рванёт - не рванётfinally
res.release(); // do not forget!end;
В случае C++ мы пишем:
{
ResGuard guard(res);
obj.explode(random(2));
// free your mind and be happy.
}
И это — единственный юзкейс finally. Поэтому добавлять в язык шоб було ((c) Vlad2) нет смысла. Нужно обходиться эффективно существующими средствами, а не обвешивать язык кренделями.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Вы правы, но наполовину. Дело в том, что проверить перед уничтожением объекта был ли он создан, вообще-то, еще ни кому ни когда не вредило в любом случае, не зависимо от того есть finally или нет его.
Эта проврека пишется один раз в деструкторе.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Проблема решена еще в С++ — обычными константами и инлайновыми функциями (заметим в скобках, что ключевого слова inline в D нет — подстановка функций остается полностью на совести компилятора).
Вот это плохо. Хотелось бы все-таки неких средств гарантированной оптимизации. То есть, что-то типа MS __forceinline, только еще жестче — функция может быть только inline, она не может иметь собственного адреса, не может быть рекурсивной и т.д. Она может быть только inline. Ну, разумеется, с некими ограничениями по уровню вложенности в случае неявной рекурсии. То есть, если компилятор видит, что "разворачивание" переходит всякие границы (типа 16 или сколько-то там уровней вложенности), то выдает ошибку и не пытается ничего сам решить. Ох, как я не люблю, когда какой-то компилятор вместо меня принимает некое "фундаментальное" решение.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Здравствуйте, FR, Вы писали:
FR>>У меня прямо дежавю какое то, все как в питоне
ЗХ>забавно а как это там выглядит?
сравнение и равенство тоже __cmp__(self, other)
также для ключей словарей нужно определять __hash__(self)
многие встроеные типы имют методы, например print "test".__add__(" string")
можно наследоватся от встроенных типов.
Здравствуйте, c-smile, Вы писали:
CS>Мон шер IT, у меня такое ощущение что ты в плену стереотипов .NET
Хочешь со мной пообщаться в подобном стиле? Можно конечно было бы задвинуть что-нибудь типа "Вам бы, уважаемый, сначала калькулятором научиться пользоваться, а уже потом рассуждать о программировании..", но мне это уже давно не интересно. Да и бывает что в баню я за это отправляю, придётся потом самого себя банить. Так что давай оставим другим сарказм, сатиру и юмор, переходящие в неуклюжие упражнения в демагогии. Ok?
А в плену я у здравого смысла. И подобный механизм у меня вызывает вполне законное недоверие. Если у тебя есть убедительные цифры и аргументы, то я с удовольствием их выслушаю. Точно такое же недоверие в своё время у меня вызывала производительность GC, по-этому я это дело тщательно проверял.
CS>Начать с того что выражение "выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти" вернО до тех пор пока ты говоришь только о выделении памяти. CS>Но если рассматривать весь объем затрат на GC включая copying/generation management то тут имхо имеем паритет с C++. В С++ выделение памяти медленне но нет таких "менопауз".
Ты на основании чего судишь? На основании собственных догадок или научных экспериментов? Я это утверждаю на основании проведённых тестов
.
CS>Вообще как ты понимаешь чудес нет в memory management. Мы как-то постоянно об этом забываем. CS>Тут всегда trade-off: где-то теряем, где-то находим.
Именно об этом я говорю. Чудес не бывает.
CS>Выжать максимум можно только если ты можешь варьировать обеими подходами в "тонких" местах. CS>Что в D как раз и возможно.
Мда... Хип и GC — это две принципиально разные вещи. Как можно скрестить бульдога с носорогом и получить в результате белого лебедя я совершенно не понимаю Объясни мне убогому.
CS>И еще. И в С++ и в D написание своего domain specific аллокатора делающего "выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти" это дело 15 минут. Переопределить new/delete и выбрать способ выделения буфера.
Только не забудь упомянуть про цену такого решения
CS>Далее. "ложит сишный хип на лопатки на выделении большого количества маленьких объектов."
CS>А зачем собственно выделять это самое большое количество маленьких объектов? CS>Когда это можно сделать одним единственным выделением?
А зачем мне одно единственное выделение, когда я могу выделять по мере необходимости? С GC результат будет тот же.
CS>Это мне напоминает процедуру создания себе трудностей с последующим их героическим преодолением. Вельми благодатный процесс. Т.е. создателям потребовались динамические конструкции например приснопамятный ArrayList чтобы все было "как у настоящих пацанов" для этого потребовался boxing который и повлек за собой потребность в "выделении большого количества маленьких объектов". CS>И т.д.
При чём тут боксинг? Речь именно об объектах, полноценных референс-типах, тех же строках.
CS>В D и в C++ такой ерундой не занимаются. vector<int> там это один кусок памяти, а не массив указателей на int выделенных в managed memory space.
Вот только не надо нам рассказывать про vector, более тупого варианта распределения памяти я не встречал. Без явного вызова reserve на больших объёмах данных можно легко "дать фору" любому GC.
CS>Еще раз говорю истина как всегда посредине — между "только heap" и "только GC". CS>И вот там, в этой золотой середине, и сидит D
Не верю. (c)
CS>На самом деле я Вальтеру предложил ввести механизм memory pools — CS>тогда вообще можно говорить CS>new(myGenerationalMemoryPool) MyObject, CS>new(myMarkAndSweepMemoryPool) MyObject, CS>new(Heap) MyObject.
И что это даст? Добавление в результате ещё одного менеджера менеджеров памяти?
CS>Вот такие вот пироги с котятами.
Да уж... мы их едим, а они пищат.
А вообще, котята такие — мне не нравится, что вместо доказательств в защиту D ты всё время скатываешься на поиск недостатков в .NET. Странная манера. Мы же в этом топике не .NET обсуждаем, правда? Но если тебе хочется, давай исходить из того, что .NET плохой, даже очень плохой, можешь больше не пытаться мне это доказать. Лучше докажи, что D хороший. Если получится, то кто знает, может потом вместе доказывать будем
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, Шахтер, Вы писали:
Ш>>Если диапазон значений маленький, то да, но лучше на это не полагаться.
uw>Вообще в D есть контракты, так что для избежания патологических случаев можно делать так: uw>
Здравствуйте, McSeem2, Вы писали:
MS>Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке. MS>Другая часто возникающая потребность — получение частного и остатка. Во всех извесных мне архитектурах это делается одной командой DIV. Но вот мы пишем: MS>
MS>int lift = a/b;
MS>int rem = a%b;
MS>
MS>И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
На самом деле работы в этом направлении(гарантированная оптимизация) ведутся, пока только исследовательские. И для этого не нужна будет специальная конструкция языка. Кстати два возвращаемых значения для функциональных языков(коими ни D,ни C++ естественно не являются) не проблема.
Здравствуйте, L.C.R., Вы писали:
LCR>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками.
finally полезнай вещь в принципе. Его отсуствие при наличии исключений — это явный касяк в дизайне языка.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, Сергей Губанов, Вы писали:
VD>>>Не. Делать тесты ради одного человека — это уже пребор.
СГ>>Дык, а если тесты для оберонов попросить написать того человека, разьве-ж он откажется...
IT>Если попросить его, то оберон несомненно победит.
Дать исходники и попросить перевести на оОберон — вполне нормальное дело. Надо дать человеку "высказаться по существу".
Re[14]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, vdimas, Вы писали:
V>>Со всякими scope-контоллерами подобные алгоритмы не представляют трудностей, записываются "как под диктовку". В случае try-finally мы должны либо городить новый уровень вложенности на каждый №, либо усложнять блок finally, проверяя, что мы успели создать, а что нет. Получаем скорее деструктуризацию, чем структуризацию.
VD>Вот бы глянуть на подобный реальный код. А то реально деструкторы в 99% случаев память особождают...
Подобный код у нас был при загрузке удаленного файла во внутренний кеш по нашим внутренним интерфейсам.
1. Взятие потока из пула, в этом потоке далее:
2. Получение ссылки на удаленный объект — сессию закачки файла
3. Эту сессию необходимо явно "закрывать" в конце операций, ибо она держит конекшн к базе данных, откуда скачивается большой файл
4. Создание локального файла
5. Закачка очередного куска в цикле
6. Скидывание на диск, goto 3
Пункты 1-5 создают ресурсы, требующие контроля.
Автоматизируемые действия:
1 — возврат потока в пул
2 — уничтожение прокси
3 — явный вызов удаленного метода Release()
4 — удаление либо закрытие файла
5 — освобождение динамического буфера памяти
Сама закачка тоже такой из себя объект, который предоставляет информацию о текущем состоянии и принимает внешние "раздражители", и тоже, соответственно, контроллируется.
Эти внешние "раздражители" — суть объекты-команды (обрабатываются как события), которые передаются м/у потоками. Время их жизни тоже зависит от многих причин (успех/неуспех/не доехали до целевого треда ибо его больше нет и т.д.)
Итого имеем 7 ресурсов на ровном месте, требующих явного управления.
Было несколько вложенных и соседствующих try-catch, но исключительно работающих на локализацию стадии, на которой произошла ошибка, т.е. эти try-catch решали логические задачи, а не "механические", и их расположение и "охват" был соответствующий.
VD>Но ЖЦ конечно рулит. Тут ни плюся ни делифи и рядом не стояли.
И все-равно — спорный вопрос. Да, в подавляющем большинстве случаев он все-таки рулит. Особенно он рулит при контроле времени жизни объектов, используемых в нескольких потоках.
Для спец-задач, однако, рулят самописные менеджеры, и ничего пока с этим не поделать. (И не только блочного типа, о которых у тебя статья. Весьма быстры и полезны аллокаторы стекового типа, идеально подходящие для динамического выделения памяти для стековых оберток, априори работающих в одном потоке, там выделение и освобождение — суть двигание "верхней планки" текущего чанка, быстрее пока просто не придумано)
Здравствуйте, FR, Вы писали:
FR>Но с другой стороны inline функции более закрыты (вход параметры выход тоже один) а необдуманое использование миксинга может дать малопонятные побочные эффекты, то есть в миксинге сохраняются не только достоинства но и не достатки макросов.
В принципе да, но
№1:
A mixin has its own scope, even if a declaration is overridden by the enclosing one:
int x = 4;
template Foo()
{
int x = 5;
int bar() { return x; }
}
mixin Foo;
void test()
{
printf("x = %d\n", x); // prints 4
printf("bar() = %d\n", bar()); // prints 5
}
И №2 подмешивание кода с помощью mixin это
достаточно редкое явление.
Собственно как и любая ручная оптимизация она требует
особого внимания.
Но зато эффективно.
Re[4]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, McSeem2, Вы писали:
MS>"Все кому не лень" делают это по одной простой причине — в языках имеется тип "строка". В C++ такого типа не существует. Следовательно, switch/case по строке невозможен по причине отсутствия самой строки.
Понятие строки в плюсах присутствует. Причем в двух экземплярах: 1) масива символов и литералов, 2) класс std::string. Ну, а то что создатели языка не очень то озаботились удобством программистов меня лично уже давно не удевляет.
MS>C# AFAIK тоже не позволяет писать switch/case по объектам произвольного типа. А как было бы прельстиво:
MS>
Более того с помощью данной техниаи можно создавать декларативные фрэймворки. Например, в редакторе кода который я сделал взамен Синтилы обработка клавиатурных сокращений делается сходным обрзом. Только описание соотвествия клавиатурных сокращений и соотвествующих функция задается ХМЛ-ем. При инициализации универсальный код считывает ХМЛ-писание и инициализирует мап делегатами ссылающимися на функции контроллера. За счет рефлексии удается создать делегаты по именам и по именам же перевести строку с описанием клавиатурных сокращений в соотвествующее ей значение перечисления Keys. Вечь код короче чем это описание. Его написание заняло час. А работа с клавиатурой стала очень простой и удобной.
... << RSDN@Home 1.1.4 beta 7 rev. 457>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, Шахтер, Вы писали:
Ш>>Да и в С++ это не проблема. uw>В C++ это именно проблема. Решение конечно есть(std::pair + make_pair), но оно далеко не идеально.
Используй структуры данных.
uw>А если возвращать не два, а три и больше значений, то C++ вообще отдыхает.
То же самое. Гораздо лучше иметь просто структуру данных с именованными полями. Более того, зачастую, лучше в подобных случаях оформлять функцию как конструктор класса.
struct Mul
{
int hi;
unsigned low;
Mul(int a,int b);
};
Здравствуйте, VladD2, Вы писали:
VD>Скромный вопрос... А эти контракты проверяются когда? Если в рантайме, то это просто дурь. А если в компайлтайме, то не ясен механизм проверок.
Тебе лучше сообщить свое мнение авторам C# тогда
class ArrayList {
void Insert(int index , object value)
requires 0 <= index && index <= Count otherwise ArgumentOutOfRangeException;
requires !IsReadOnly && !IsFixedSize otherwise NotSupportedException;
{
....
}
Здравствуйте, VladD2, Вы писали:
VD>Чдо до решаемых задачь, то что-то не видать на Ди драйверов и риалтайм-систем. А остальные задачи можно решать и на дотнете и на С++.
Здравствуйте, VladD2, Вы писали:
VD>Понятие строки в плюсах присутствует. Причем в двух экземплярах: 1) масива символов и литералов, 2) класс std::string. Ну, а то что создатели языка не очень то озаботились удобством программистов меня лично уже давно не удевляет.
Согласен с твоими выводами (нижеудалеными), но возражаю по поводу наличия в C++ типа "строка". Нет такого типа в языке. Есть только некоторые соглашения, типа "массив байтов, завершающийся нулем можно считать строкой". Ну или массив интов в случае unicode. Компилятор ничего не знает ни об strcmp, ни о std::string. Соответственно, как можно строить switch/case по неизвестному типу? Язык не навязывает того, что строка обязана завершаться нулем, например. И поэтому, надо либо вводить в сам язык строгое понятие строки, либо (что лучше) возможность строить switch/case по произвольному типу.
Далее размышляем.
Таким образом, получается, что switch/case по строкам в любом языке является лишь полумерой. Как, например, реализовать switch/case с типом Date? Есть такой тип в C#? Нету. Есть только некий класс, который компилятор интерпретирует как любой другой класс. Конечно же, это абсурд — делать switch/case по конкретным датам. Но по месяцам, по кварталам или по дням недели это очень даже не абсурд. Соответственно, для такого типа, как DateTime нужен не просто switch, нужен switch по конкретным условиям (полям — месяц, квартал, день недели, время года, etc). А это уже ничем не отличается от switch/case по произвольному типу, с некими своими операциями сравнения.
И что характерно, в том же C++ или C# это можно было бы реализовать элементарно. Достаточно такого старого понятия, как "вычисляемый goto":
Фактически, switch это и есть вычисляемый goto, но только кастрированный и неспособный к развитию И при этом — не гарантирующий какую-либо оптимизацию. Все, что можно гарантировать — это O(N) и не более того. В то время, как вычисляемый goto железно обеспечивает O(1).
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Решение этого вопроса довольно изящно: без введения дополнительного ключевого слова и особого синтаксиса:
//Это - С++:class A
{
int val(); //getterint val(int _newval); //setter (собака такая - сеттер)
}
A a;
int i = a.val();
a.val(i);
//==============================
//А вот это - уже D:class A
{
int val(); //getterint val(int _newval); //setter
}
A a;
int i = a.val; //вызывается A.val();
a.val = i; //вызывается A.val(int);
Лихо? Это еще не все. Данные имеют свойства:
int[] arr; //что написано, то и есть - это динамический массив int'овfor(int i = 0; i < arr.length; ++i) //использование свойства массива .length
a.length = 42; //еще одно использование свойства
Зашибись? Но и это еще не все. Типы тоже имеют свойства:
int maxint = int.max; //максимальное значение int'аint sizeint = int.size; //эта фенечка вместо С-шного sizeof(int)float.nan //NaNfloat.infinity //бесканечнасть
(2).max //эквивалентно int.max
2.max //ошибка - у числа 2 нету свойствов
Еще есть такое забавное свойство .init — значение, которым инициализируется переменная:
int val = int.init; //получим 0int a;
val = a.init; //получим 0 - потому что a было проинициализировано нулемint b = 8;
val = b.init; //получим 8typedef int mycoolint = 2;
val = mycoolint.init; //получим 2
mycoolint c;
val = c.init; //получим 2
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Обероны компактнее.
СГ>Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз
На размер описания языка начхать всем кроме разработчиков компилятора.
А для пользователей языка важна компактность записи тех или иных конструкций в языке. А вот с компактностью записи у оберонов проблемы.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>На размер описания языка начхать всем кроме разработчиков компилятора. WH>А для пользователей языка важна компактность записи тех или иных конструкций в языке. А вот с компактностью записи у оберонов проблемы.
Во-первых, не кипятитесь Вы так. Я же пошутил !!!
Во-вторых, хоть это была и шутка, но правда. Сражаться с Оберонами в компактности практически бесполезно. Существование семейства оберонистых языков было открыто способом с помощью которого можно было открыть существование только очень компактных языков (человек взял новый пустой (голый) компьютер и написал для него все от компилятора до операционки с нуля, понятно что сделать это за обозримое время можно только используя очень хороший инструмент, который собственно и был создан параллельно в ходе работы — так было открыто существование оберонов, необходимых и достаточных — минимальных языков программирования общего назначения).
Вот что пишут про одну из новейших оберонистых операционок:
For a native multiprocessor operating system, Aos is small, with a kernel of 7,210 lines of source or about 50KB of object code. For comparison, the 4.4BSD kernel (cf. 8.1.2) consists of 58,289 lines of C code (excluding file systems, network protocols and device drivers, which add another 143,962 lines) [65]. Version 2.4 of the Linux kernel consists of approximately 420,000 lines of C code (excluding drivers, file systems and architecture-specific code, which bring the total to 2.4 million lines) [128], and has a minimum size of around 500KB on Intel processors. Microsoft boasts that Windows 2000 “consists of over 29 million lines of code”, but does not say what is included in this figure, so it is not possible to compare specifics.
Subsystem Lines
Kernel 7210
Service support 2532
File system 4624
User interface 2204
Network 6200
Oberon for Aos 8667
Total 31437
Правда еще есть Lisp, который еще более компактен, но он, согласитесь, уже относится немного к другому классу языков программирования.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Обероны компактнее.
СГ>Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз
Но является ли это однозначным преимуществом языка (в ущерб, скажем, выразительности) — вопрос глубоко спорный...
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Здравствуйте, eao197, Вы писали:
ЗХ>>>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
E>>Вообще-то я не думаю, что сравнение объектов, которые используются в качестве ключа map-а бессмыслено. Ведь в std::map ключи элементов как раз-таки сравниваются
E>>А пример мой был к тому, что если в C++ мне потребуется сделать класс, от которого средства языка (std::{multi}map, std::{multi}set, std::find, ...) требуют только наличия operator<(), то я и реализую только это. И если от моего класса начинают требовать чего-то еще, то тут же получают по рукам.
ЗХ>На что я и ответил: по сути, существует два омонима: оператор "меньше" (в "численном" смысле. Преполагает наличие операторов больше, меньше-равно, больше-равно, равно, неравно...) и оператор порядка ("предыдущий").
Да, здесь я, пожалуй, соглашусь. Просто первоначально термин "порядок" меня смутил (сразу почему-то вспоминается какая-то фигня, вроде "функция более высокого порядка...", "...сложность совсем другого порядка...", "...уровень доходов на порядок меньше/больше..."). Вот если бы сразу использовалось что-то типа оператор "предшествования", то я бы не возражал
ЗХ>А еще какие-то случаи ты можешь придумать, когда тебе нужен только 1 оператор, а не все?
Пожалуй нет. За исключением того, что STL доказал, что достаточно в каком-то типе определить всего один оператор, а все остальные операторы сравнения (именно в "численном" смысле) можно различными темплейтовыми обертками добавить.
ЗХ>ЗЫ: я все еще не доказываю превосходство/уродство D, а показываю штуки, которые мне в нем показались занятными
Да я тоже, просто конкретно это решение мне показалось не столь удачным, как некоторые другие штуки в D.
Когда-то год-полтора назад я сам прочитал описание D и подумал, что это тот язык на который бы я с C++ перешел. Будь он больше обеспечен всякими сторонними библиотеками (криптография там всякая, XML, HTTP, ...)
Может со временем ситуация наладится.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Шахтер, Вы писали:
Ш>Да и в С++ это не проблема.
В C++ это именно проблема. Решение конечно есть(std::pair + make_pair), но оно далеко не идеально.
А в нормальном ФЯ есть tuples(или как переводят — кортежи, ох как я не люблю это слово). Возвращать можно сколько угодно значений и если в языке есть локальная инференция типов, то еще и типы указывать не надо, вообще никогда.
C++:
std::pair<int,int> divmod(int a, int b)
{
std::make_pair(a / b, a % b);
}
ФЯ:
Haskell(хотя в нем не указывать типы(хотя бы generic) это моветон):
divmod a b = (a / b, a % b)
Nemerle(несмотря на статическую типизацию, не указывать типы в большинстве случаев это нормальная практика):
divmod(a,b) { (a / b, a % b) }
В C++ аналогом вышеприведенного кода будет:
template <class T>
std::pair<T,T> divmod(T a, T b)
{
std::make_pair(a / b, a % b);
}
А если возвращать не два, а три и больше значений, то C++ вообще отдыхает. Конечно есть boost::tuple, но не стоит забывать, что это 80kb кода. Так что это именно проблема, для которой вполне осознанно искали и создавали решения, и в принципе ничего нормального не создали.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, c-smile, Вы писали:
CS>>Что можно сделать так это в деструкторе узнать "мы внутри GC или нет".
СГ>А разьве это не всегда так? Разьве деструктор может позвать кто-то еще кроме GC? Если да, то зачем?
К примеру, если мы захватываем системный ресурс, который нужно освободить сразу по окончании работы с ним. В таких случаях использование автоматических объектов предпочтительнее, IMHO.
Здравствуйте, uw, Вы писали:
uw>Что может быть проще и очевидней вот такого кода?
uw>
uw>class Task
uw>{
uw> private int priority;
uw> public int opCmp(Task t)
uw> {
uw> return priority - t.priority;
uw> }
uw>}
uw>
Выговор с лишением зарплаты или премии. Такой код требует, чтобы числа были заведомо маленькими. Иначе переполнение и наязыках вроде С++ ты будешь искать ошибку годами.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Сергей Губанов wrote:
> С другой стороны, Вы говорите об уже устаревшей Delphi-7, ведь > Delphi-8 (на же Delphi for .NET) и Delphi-9 (она же Delphi 2005) стали > писаться под .NET, потребность в умных указателях как бы пропала — > работает натуральная сборка мусора.
С появлением .NET просто отпала потребность в самой Дельфи....
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[11]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, c-smile, Вы писали:
CS>Не думаю что именно в этом предназначение D. CS>Хотя, может ты и прав. Мног чего-то желающих писать CS>ситемные вещи.
Дык что не говори, а Ди мог бы резко понизить планку вхождения в системное программирование и резко его упростить.
Забвано было бы написать VM c JIT-компиляцией на Ди.
CS>GUI задачи я оченно даже вижу на D.
Если только шаравари мелкие. А так лично я предпочту все же Шарп с дотнетом. Во-первых, кучу работы не прицдется делать, так как есть компонентная модель, а во-вторых, сама компонетность среды для ГУИ очень полезна.
VD>> ... Для игр компонентность и рантайм очень полезны.
CS>У нас тут вообще-то Electronoc Arts под боком. Иногда встречаюсь с бойцами оттуда. CS>Вот бы тебе с ними поговорить про "компонентность и рантайм" ...
Если там есть русские, то зави их сюда. А по англицки я свободно балакать не мгу. Слушать и читать еще ничего, а вот писать и говорить к сожалению тяжеловато.
CS>У них все свое и все внутри на голых сях плюсовых с темплейтами.
Оно и понятно. У них на это и деньги есть. А вот если, например, нам с тобой захочется их потеснить, то на плюсах это будет сделать очень не просто. На Ди еще туды-сюды, а вот на чем дотнете или какой-нить яве с костылями очень даже возможно. Памть становится все менее значимым ресурсом, а в сотальном... В общем, так и кончаются гегемонии богатых буратинов.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, L.C.R., Вы писали:
LCR>finally. В случае Дельфи мы пишем: LCR>
LCR>try
LCR> res.acquire();
LCR> obj.explode(random(2)); // рванёт - не рванёт
LCR>finally
LCR> res.release(); // do not forget!
LCR>end;
LCR>
LCR>В случае C++ мы пишем: LCR>
LCR>{
LCR> ResGuard guard(res);
LCR> obj.explode(random(2));
LCR> // free your mind and be happy.
LCR>}
LCR>
1) "try finally end" является конструкцией структурного программирования, такая же как все остальные структурные конструкции while, if, case и т.д. и не имеет ни какого отношения к ООП. Язык имеющий ее не обязан быть ОО языком, он должен быть просто структурным. Катить бочку на нее — все равно что катить бочку на структурное программирование. В то время как конструкция автоматического вызова деструктора статического объекта — есть всего лишь специфическое свойство отдельно взятого языка.
2) Не замучаетесь на каждый чих писать все новые и новые аналоги классов ResGuard (лишние сущности)? Использование структурной конструкции finally избавляет от этой лишней писанины и структурирует программу.
Здравствуйте, Зверёк Харьковский, Вы писали:
E>>Так вот в C++ мне достаточно определить только оператор "строго меньше"...
ЗХ>...что, по сути, является определением совсем другого оператора — оператора порядка, а не оператора сравнения. Ты не застрахован от удивления в клиентском коде, когда ЗХ>
ЗХ>Compound_Key a, b;
ЗХ>if(a < b) //так можно
ЗХ>if(a > b) //а так почему-то нельзя :(
ЗХ>
ЗХ>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
Тут история вот какая:
1) разные отношения
— эквивалентность, которому соответствует семейство сравнений ==, !=
— порядок, которому соответствуют < > <= >= == != (т.е. эквивалентность вытекает из порядка)
Причём для введения каждого из них необходимо и достаточно определить, соответственно, равенство ( == ) и одно из строгих неравенств ( < > )
2) отношение порядка можно задавать как предикатом неравенства (X,X)->bool, так и троичной функцией-компаратором (X,X)->{-,0,+} — эти способы взаимозаменяемы
3) троичный компаратор в роли базиса — практически удобнее, чем неравенство:
— он антисимметричен (а значит, его проще и реализовывать, и использовать)
— все операторы (включая ==) определяются через одно обращение к компаратору:
— — x>y = cmp(x,y)>0; x<=y = cmp(x,y)<=0; x==y = cmp(x,y)==0
— — x<y = less(y,x); x<=y = !less(y,x); x==y = !less(x,y) && !less(y,x)
для дорогостоящих сравнений (например, строк) это может здорово аукнуться.
То, что в STL в роли базиса был взят предикат — это, возможно, упущение авторов. Хотели добиться минимализма (типа — встроенный оператор уже есть, а компаратор потребует нового имени, да ещё и заморочек с ADL). И устроили головную боль пользователям. Хотя в этом есть некое изящество: если операторы < и > определены и согласованы, то смена направления сортировки достигается заменой less<T> на greater<T> (определённые через операторы).
Здравствуйте, vdimas, Вы писали:
V>Да не, "там" очччень дохрена на VB/VBA всякого понаписано. Ситуация с бизнес-приложениями в тех же штатах вообще комическая с нашей т.з. Там или откровенные примитивы типа QuickBook, или сразу монстры типа SAP. Весь промежуточный провал — кто во что горазд. У нас в этой нише прочно сидит 1С, это на порядок более качественное решение чем весь тот сброд, что существует у них (по большей части на VB писанный, и сервера приложений в т.ч !!!).
Джавы у них много на серверах, гораздо больше чем VB.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Наблюдение верное. И даже в некоторой мере очевидное. Но тут есть еще 2 фактора: ЗХ>1) как-никак, компаратор редко удается изящно написать. В этой ветке приводилось достаточно примеров того, насколько неизящен унутре этот самый компаратор.
Предикат — ещё менее изящен
Например, поэлементное (в т.ч. лексикографическое) сравнение выглядит так
int cmp(A a, A b)
{
int c;
c = cmp(a.x, b.x); if(c) return c;
c = cmp(a.y, b.y); if(c) return c;
...
return 0;
}
bool less(A a, A b)
{
if(less(a.x, b.x)) return true; if(less(b.x, a.x)) return false;
if(less(a.y, b.y)) return true; if(less(b.y, a.y)) return false;
...
return false;
}
ЗХ>2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).
Как это?! Если есть порядок, то автоматически есть и равенство.
Другое дело, что можно ввести несколько разных равенств/порядков (пример для строк: порядки с учётом регистра, без учёта регистра, по созвучию, по контрольной сумме).
В этом случае необходимо и достаточно определить внешние функции/функторы.
ЗХ>Соответственно, получится либо "частично определенный" компаратор (который возвращает либо 0 либо не 0), что опять же может запутать юзера; либо два оператора — компаратор и равенство (как собственно и сделано в D, имеющем opEqual и opCmp), что уже несколько дискредитирует всю задумку.
Задумку дискредитирует то, что
— в С++ операторы между собой не связаны
— а в D, где связь есть, не пошли до конца (скажем, могли потребовать: если определён opCmp, то opEqual определяется автоматически и не подлежит перекрытию)
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Я не то имел в виду, когда говорил об избавлении от ненужных операторов. Слияние не operator+ и operator-, а operator+ и operator+=
Это опять накладывает ненужные ограничения. А именно, требует, чтобы тип результата был равен типу левого операнда.
L& operator += ( L& lhs, const R& rhs) { lhs = lhs + rhs; return lhs; }
L operator + (const L& lhs, const R& rhs) { L res = lhs; res += rhs; return res; }
Самый сильный пример того, где это мешает — boost::spirit, где можно складывать унарные функции и скаляры, порождая новые унарные функции.
Перекуём баги на фичи!
Re[4]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, McSeem2, Вы писали:
M>>>*мрачно* Только за это я готов на D перейти. А то как раз ситуевина, млин. Извращаюсь через енумы...
VD>>По-моему, кроме С++ все кому не лень позволяют делать свитчи по строкам.
VD>>К тому же эмулируется это дело очень просто. Строишь хэш-таблицу ключем которой является строка, а значением функция-обработчик...
MS>"Все кому не лень" делают это по одной простой причине — в языках имеется тип "строка". В C++ такого типа не существует. Следовательно, switch/case по строке невозможен по причине отсутствия самой строки.
MS>C# AFAIK тоже не позволяет писать switch/case по объектам произвольного типа. А как было бы прельстиво:
Кстати, да. Первое моё движение, когда я узнал про свич по строкам в Ди — "а по произвольным классам?"
Узнав, что нельзя, "гестапа очень ругалась".
Вопрос: почему нельзя? Что этому мешает? У кого-нибудь есть логичный ответ?
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[5]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Кстати, да. Первое моё движение, когда я узнал про свич по строкам в Ди — "а по произвольным классам?" ЗХ>Узнав, что нельзя, "гестапа очень ругалась". ЗХ>Вопрос: почему нельзя? Что этому мешает? У кого-нибудь есть логичный ответ?
Ничто не мешает. Традиции мешают и косность мышления
Ну, в C++ еще понятно — четкое разделение самого языка и производных этого языка, AKA классов. А в том же C# или Java, с их IL это сделать вообще раз плюнуть.
Хотя и в C++ проникла некая интеграция языка со стандартной библиотекой. Как, например, реализуется dynamic_cast<reference> с его "throw bad_cast"? Ведь dynamic_cast — это конструкция языка, а bad_cast — это конструкция библиотеки. То же самое с bad_alloc. Получается, что язык знает кое-что о стандартной библиотеке. Так почему бы тогда всю стандартную библиотеку не интегрировать в сам язык?
В том же C# или D можно было бы таких синтаксических конфеток наделать — ухх-ням-ням! Но сделали. Плохие танцоры, наверное — что-то мешает.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>__LINE__, __FILE__ и др. ЗХ>D предполагает, что единственный смысл использования "особых макросов" — информативность выражения assert. Соответственно, в D выражение assert является не библиотечной функцией, а частью core language, благодаря чему "само" знает, на какой строке и в каком файле приключилось.
Зря он так предполагает
Например, при логировании __FILE__ и __LINE__ здорово помогают. Как и макросы, кстати.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, McSeem2, Вы писали:
ЗХ>>Проблема решена еще в С++ — обычными константами и инлайновыми функциями (заметим в скобках, что ключевого слова inline в D нет — подстановка функций остается полностью на совести компилятора).
MS>Вот это плохо. Хотелось бы все-таки неких средств гарантированной оптимизации. То есть, что-то типа MS __forceinline, только еще жестче — функция может быть только inline, она не может иметь собственного адреса, не может быть рекурсивной и т.д. Она может быть только inline. Ну, разумеется, с некими ограничениями по уровню вложенности в случае неявной рекурсии. То есть, если компилятор видит, что "разворачивание" переходит всякие границы (типа 16 или сколько-то там уровней вложенности), то выдает ошибку и не пытается ничего сам решить. Ох, как я не люблю, когда какой-то компилятор вместо меня принимает некое "фундаментальное" решение.
mixin есть для таких случаев — гарантированная вставка фрагмента
кода, деклараций и/или классов.
Re[6]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, McSeem2, Вы писали:
MS>Здравствуйте, VladD2, Вы писали:
VD>>Понятие строки в плюсах присутствует. Причем в двух экземплярах: 1) масива символов и литералов, 2) класс std::string. Ну, а то что создатели языка не очень то озаботились удобством программистов меня лично уже давно не удевляет.
MS>Согласен с твоими выводами (нижеудалеными), но возражаю по поводу наличия в C++ типа "строка". Нет такого типа в языке. Есть только некоторые соглашения, типа "массив байтов, завершающийся нулем можно считать строкой". Ну или массив интов в случае unicode. Компилятор ничего не знает ни об strcmp, ни о std::string. Соответственно, как можно строить switch/case по неизвестному типу? Язык не навязывает того, что строка обязана завершаться нулем, например. И поэтому, надо либо вводить в сам язык строгое понятие строки, либо (что лучше) возможность строить switch/case по произвольному типу.
MS>Далее размышляем. MS>Таким образом, получается, что switch/case по строкам в любом языке является лишь полумерой. Как, например, реализовать switch/case с типом Date? Есть такой тип в C#? Нету. Есть только некий класс, который компилятор интерпретирует как любой другой класс. Конечно же, это абсурд — делать switch/case по конкретным датам. Но по месяцам, по кварталам или по дням недели это очень даже не абсурд. Соответственно, для такого типа, как DateTime нужен не просто switch, нужен switch по конкретным условиям (полям — месяц, квартал, день недели, время года, etc). А это уже ничем не отличается от switch/case по произвольному типу, с некими своими операциями сравнения.
MS>И что характерно, в том же C++ или C# это можно было бы реализовать элементарно. Достаточно такого старого понятия, как "вычисляемый goto": MS>
MS>Фактически, switch это и есть вычисляемый goto, но только кастрированный и неспособный к развитию И при этом — не гарантирующий какую-либо оптимизацию. Все, что можно гарантировать — это O(N) и не более того. В то время, как вычисляемый goto железно обеспечивает O(1).
То же самое без всяких извращений.
switch( d.quarter() )
{
case 1 : ... break;
case 2 : ... break;
...
default: ...
}
switch -- это и есть вычислимый goto. Только он мощнее. Поскольку метки могут быть непрерывным интервалом значений, в этом случае компилятор сгенерирует таблицу jam ов, или в случае, когда нет неперерывности -- двоичное дерево сравнений.
Здравствуйте, McSeem2, Вы писали:
MS>Здравствуйте, Шахтер, Вы писали:
Ш>>switch -- это и есть вычислимый goto. Только он мощнее. Поскольку метки могут быть непрерывным интервалом значений, в этом случае компилятор сгенерирует таблицу jam ов, или в случае, когда нет неперерывности -- двоичное дерево сравнений.
MS>Ты прав. Я тут сам запутался в своем словоблудстве. А хотел сказать нечто другое. Конструкция switch ничего не гарантирует. А хочется именно гарантированной оптимизации.
Гарантированной оптимизации язык дать не может. Он может дать только возможность оптимизации. Остальное зависит от качества компилятора.
Здравствуйте, McSeem2, Вы писали:
MS>Согласен с твоими выводами (нижеудалеными), но возражаю по поводу наличия в C++ типа "строка". Нет такого типа в языке.
Как же так, строки есть, а типа нету?
Re[8]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Мне, откровенно говоря, такой подход нравится существенно меньше — уж очень это напоминает некоторые "неявные соглашения", которые способствуют упрощению компилятора, но не самодокументированию кода. Впрочем, думаю, привыкнуть можно
В общем и целом согласен.
Пара "но" разве что.
1) Не так часто переопределяются операторы.
2) Если нужно "унутре" позвать функцию оператор то явный вызов opShift() выглядит наверное лучше.
ЗХ>//C++
ЗХ>A a, b;
ЗХ>if(a > b) ... //вызов A.operator>
ЗХ>if(a < b) ... //вызов A.operator<
ЗХ>//...и т.д.
ЗХ>//D
ЗХ>A a, b;
ЗХ>if(a < b) ... //вызов A.opCmp(b) < 0
ЗХ>if(a > b) ... //вызов A.opCmp(b) > 0
ЗХ>if(a <= b) ... //вызов A.opCmp(b) <= 0
ЗХ>if(a >= b) ... //вызов A.opCmp(b) >= 0
ЗХ>
ЗХ>...и вот эта фичка (несмотря на не совсем очевидное действие сравнения результата с нулем) мне кажется весьма достойной. Как и любые другие, позволяющие записывать всеобщие неявные соглашения (например: оператор != эквивалентен отрицанию оператора ==) в явном виде. Выигрыш имеем двойной: а) уверенность, что в чужом коде определены и корректно работают все операторы сравнение + б) отстутсвие необходимости повторять "руками" дурную работу. ЗХ>Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.
Вот именно. В C++ мне время от времени приходится использовать в качестве ключей в map объекты, содержащие несколько полей:
Но в C++ я делаю только то, что мне нужно. А вот в D, как я понял, потребуется сделать Compound_Key.opCmp, который должен будет отслеживать не только "строго меньше", но и равенство, и "строго больше".
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Никто ж не спорит! Я что подчеркнул — что в D эта "традиция" присутствует в языке в явном виде, а не отдана воле разработчика.
Ну я еще намекнул на то что ребята както странно подходят к реализации одних операций сравнения через другие.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Обероны компактнее.
СГ>Если сложить полные описания всех более-менее известных оберонов, то, думается, описание языка D все равно будет больше их в несколько раз
Этот вопрос, IMHO, несколько месяцев назад разобрали достаточно основательно. Считаю, что нет смысла к нему возвращаться. К тому же здесь это оффтоп.
Здравствуйте, eao197, Вы писали:
ЗХ>>Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.
E>Вот именно. В C++ мне время от времени приходится использовать в качестве ключей в map объекты, содержащие несколько полей: E>
E>Так вот в C++ мне достаточно определить только оператор "строго меньше"...
...что, по сути, является определением совсем другого оператора — оператора порядка, а не оператора сравнения. Ты не застрахован от удивления в клиентском коде, когда
Compound_Key a, b;
if(a < b) //так можноif(a > b) //а так почему-то нельзя :(
Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
Здравствуйте, Mamut, Вы писали:
M>[offtop]
M>На смену волне Обероновой пришла волна D
Ну я вроде стался быть конструктивен. Думал, эта информация будет интересна.
Цель этого мне видится не в ознакомлении всего РСДНа с новым языком — а в обсуждении новых или не очень концепций D и их реализации.
(с) я.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Здравствуйте, eao197, Вы писали:
ЗХ>>>Впрочем, не исключаю, что для нетривиального класса определение оператора opCmp (учитывая все варианты возвращаемых значений) будет выглядет довольно нелаконично и даже искусственно.
E>>Вот именно. В C++ мне время от времени приходится использовать в качестве ключей в map объекты, содержащие несколько полей: E>>
E>>Так вот в C++ мне достаточно определить только оператор "строго меньше"...
ЗХ>...что, по сути, является определением совсем другого оператора — оператора порядка, а не оператора сравнения. Ты не застрахован от удивления в клиентском коде, когда ЗХ>
ЗХ>Compound_Key a, b;
ЗХ>if(a < b) //так можно
ЗХ>if(a > b) //а так почему-то нельзя :(
ЗХ>
ЗХ>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
Вообще-то я не думаю, что сравнение объектов, которые используются в качестве ключа map-а бессмыслено. Ведь в std::map ключи элементов как раз-таки сравниваются
А пример мой был к тому, что если в C++ мне потребуется сделать класс, от которого средства языка (std::{multi}map, std::{multi}set, std::find, ...) требуют только наличия operator<(), то я и реализую только это. И если от моего класса начинают требовать чего-то еще, то тут же получают по рукам.
В подходе же с opCmp я уже не могу просто сделать сравнение на "строго меньше". Мне в любом случае придется предоставлять варианты для случаев "равно" и "строго больше" (либо чесно их реализуя, либо используя что-то типа: Re: Снова D: Зверёк читает мануал
Здравствуйте, eao197, Вы писали:
ЗХ>>На что я и ответил: по сути, существует два омонима: оператор "меньше" (в "численном" смысле. Преполагает наличие операторов больше, меньше-равно, больше-равно, равно, неравно...) и оператор порядка ("предыдущий").
E>Да, здесь я, пожалуй, соглашусь. Просто первоначально термин "порядок" меня смутил (сразу почему-то вспоминается какая-то фигня, вроде "функция более высокого порядка...", "...сложность совсем другого порядка...", "...уровень доходов на порядок меньше/больше..."). Вот если бы сразу использовалось что-то типа оператор "предшествования", то я бы не возражал
Я бы с удовольствием... Но в нужный момент не вспомнил слово "предшествование"
ЗХ>>А еще какие-то случаи ты можешь придумать, когда тебе нужен только 1 оператор, а не все?
E>Пожалуй нет. За исключением того, что STL доказал, что достаточно в каком-то типе определить всего один оператор, а все остальные операторы сравнения (именно в "численном" смысле) можно различными темплейтовыми обертками добавить.
+1
по сути, идея "реализуй необходимый минимум, а все остальное добавится автоматом" — она вполне какчественно реализована в boost::operators и boost::iterator_adaptors.
Но включение этого принципа в явном виде в core language — имхо, вполне достойная задумка! (хотя реализация этой задумки в D, как мы уже выяснили — дааалеко не идеал)
ЗХ>>ЗЫ: я все еще не доказываю превосходство/уродство D, а показываю штуки, которые мне в нем показались занятными E>Да я тоже, просто конкретно это решение мне показалось не столь удачным, как некоторые другие штуки в D. E>Когда-то год-полтора назад я сам прочитал описание D и подумал, что это тот язык на который бы я с C++ перешел. Будь он больше обеспечен всякими сторонними библиотеками (криптография там всякая, XML, HTTP, ...) E>Может со временем ситуация наладится.
Да я вот все думаю, с какой бы стороны подступиться к интеграции его с С++ными библиотеками... ИМХО, решение должно быть где-то рядом
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Да я вот все думаю, с какой бы стороны подступиться к интеграции его с С++ными библиотеками... ИМХО, решение должно быть где-то рядом
Ну а я пока решил подождать и посмотреть, чем же все-таки развитие D продолжится.
К тому же сейчас меня не устраивает еще и то, что компилятор D существует только для Windows и Linux. У меня такая специфика, что в любой момент могут обязать перейти куданить в BSD или Solaris, или еще куда поэкзотичнее. А там пока D нет
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, McSeem2, Вы писали:
ЗХ>>И даже более того: все четыре сравнения (>, <, >=, <=) выполняются одним оператором opCmp:
MS>С точки зрения производительности я бы не назвал opCmp однозначным рулезом. MS>Во избежание сюрпризов надо писать так: MS>
MS>int opCmp(T a, T b)
MS>{
MS> if(a < b) return -1;
MS> if(a > b) return 1;
MS> return 0;
MS>}
MS>
MS>С учетом наличия методов у простых типов, можно, конечно писать return a.opCmp(b), но при этом компилятор все равно обязан сгенерировать код приведенный выше. Иначе — чревато сюрпризами. То есть, снаружи выглядит конечно удобно, но внутри подпадает под случай "вылить воду из чайника и таким образом свести задачу к предыдущей".
Угу, я тоже об этом подумал... Решение вообще говоря, несколько искусственное.
Вот с автогенеренным != мне больше понравилось — естественнее что ли.
Два последних оператора — не очень-то рулез по производительности. Зато по очевидности — это, имхо намного лучше, чем "многозначный" оператор из D
К слову сказать, если я правильно понимаю, boost::operators как раз и позволяет так сделать
В высокоуровневых языках часто возникает ситуация "за лесом деревьев не видать".
Взять, хртя бы простейшее выражение (операция целочисленного масштабирования):
int v = a*b/c;
a, b, c — все int. Так вот, на всех известных мне современных архитектурах, операция MUL выдает результат вдвое большей разрядности. А операция DIV тоже требует двойной разрядности. Таким образом, при использовании ассемблера, можно масштабировать целые значения практически во всем их диапазоне, не переходя на двойную разрядность целиком.
Но копилятор обязан обрезать промежуточный результат a*b снова до одинарной разрядности и нет способа объяснить, что вот в данном случае обрезать не надо. Почему "обязан" — во-первых, компилятор не знает — может быть переполнение играет важную роль в данном алгоритме. Во-вторых, если мы усложним выражение: a*b*c/d — нам уже понадобится не двойная а тройная разрядность. Таким образом, в языках высокого уровня нет способа задействовать простую и эффективную последовательность инструкций mul/div. Таким образом, хотелось бы иметь что-то типа:
v = a.muldiv(b, c);
или
v = a.mulshift(b, 32); // - умножаем и берем старшие 32 бита
Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке.
Другая часто возникающая потребность — получение частного и остатка. Во всех извесных мне архитектурах это делается одной командой DIV. Но вот мы пишем:
int lift = a/b;
int rem = a%b;
И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>>Да я вот все думаю, с какой бы стороны подступиться к интеграции его с С++ными библиотеками... ИМХО, решение должно быть где-то рядом
Сомневаюсь Будет большая проблема с тем, что D строит аналог vtable произвольным образом. То есть он может менять местами методы и даже их удалять за ненадобностью...
E>Ну а я пока решил подождать и посмотреть, чем же все-таки развитие D продолжится. E>К тому же сейчас меня не устраивает еще и то, что компилятор D существует только для Windows и Linux. У меня такая специфика, что в любой момент могут обязать перейти куданить в BSD или Solaris, или еще куда поэкзотичнее. А там пока D нет
Есть GNU D Compiler + http://home.earthlink.net/~dvdfrdmn/d. То есть в теории собирать можно где угодно, нужно только GCC старше 3.3
ЗХ>int c; //переменная типа int
ЗХ>typedef int mycoolint; //тип "типа" intME>typedef int (*mcfp[](int (*fp)(void* v1, void* v2), int& r);
ME>struct S {....};
ME>struct _tagS {....} S1; // определение типа S1!ME>class C {...};
ME>enum E {...};
ЗХ>
И куда делась твоя аналогия? Ты видишь, она годится только для простых случаев.
ЗХ>вообще, фигня это, охота за воробьями... ЗХ>
ЗХ>Dim VBAForeva As Rulezzzz;
ЗХ>
type ocaml_owns_all =
Val of int
| Fun of (float->string) * ocaml_owns_all;;
В данном случае type (может быть в васике тоже самое, в паскале что-то типа этого) совершенно однородно и для простых, и для сложных случаев — выражение после знака равенства может быть сколько угодно сложным и при этом мы в своём головном мозге это выражение раскручиваем по одним и тем же правилам независимо от сложности этого выражения. Правила простые, но применяться они могут к различным уровням разбора, то есть рекурсивно.
Посмотрим на случай с сями. Каждый раз глядя на ензувуа мы должны мысленно его отбросить и выяснить, какого же типа переменная объявлена в данном случае. Потом выяснив тип переменной, мы должны мысленно себе сказать: "Вот, это такой тип". Более того, для других типов (классов, структур, перечислений) определения должны выглядеть по-другому. Примечателен пример определения для типа S1.
В примере выше я пытался объявить тип = "массив указателей на функцию возвращающей инт и принимающей указатель на функцию возвращающей инт, принимающей 2 указателя на воид, и принимающей ссылку на инт" (я понимаю... дурдом, я даже не уверен, что я правильно воткнул квадратные скобки ). Так вот, пользуясь рекурсивной псевдо паскальной нотацией мы можем написать где-то в таком духе:
type mcfp = array of
(
func * : ( (func * : (void *, void *) -> int ), void * ) -> int
);
Определение однородно и расширяемо.
И на засыпку. Можешь ли ты с такой же лёгкостью, как ты говоришь слово "ХА", сказать, что в данном случае указатель на массив, а что массив указателей:
— нужно убрать ME перед type, и вставить закрывающий тэг перед словами "Определение однородно и расширяемо". Никак не могу себя приучить делать предпросмотр...
Конструкторы в D, в общем, имеют что-то общее с С++, но с некоторыми исключениями:
class Constructors: Base
{
int a;
this(); //конструктор всегда зовут this. Что облегчает использование паттерна проектирования copy-paste :)this(int i) //как и в C++, конструкторов может быть несколько, они могут принимать параметры
{
a = i; //инициализация членов - просто в теле конструктораthis(); //в отличие от С++, конструкторы могут вызывать друг друга.
super(10); //вызов конструкторов базового класса - в любом месте конструктора. если нет явного вызова, вызовется в самом начале this(
}
int b = 18; //инициализация членов константами
~this() //с деструктором тоже все банально - он один, без параметров, всегда виртуальный
{
}
};
Статические конструкторы-деструкторы
Сюрприз! D позволяет каждому классу выполнять сколь угодно сложную инициализацию до начала функции main:
class A
{
int r = random(); //так нельзя!static this()
{
//это выполнится до начала main 1 раз. выделение ресурсов, задание начальных значений данных членов...
r = random(); //а вот так - можно!
}
static ~this()
{
//выполнится после конца main
}
}
Теоретически, пара статический конструктор/статический деструктор, возможно, подойдет для создания синглетонов...
RAII
RAII — фича, за отсутсвие которой обычно пеняют языкам с GC (а D — именно такой язык).
В С++ реализация RAII — лишь одно из следствий правил областей видимости и времени жизни переменной:
class Resource
{
Resource()
{
/*
открываем файлы, создаем сокеты и вообще творим всякие непотребства
*/
}
~Resource()
{
//убираем за собой
}
}
//где-то в коде:
{
Resource r; //взяли ресурс
....
} //ресурс освободился - даже в случае исключения
Поскольку в D все переменные пользовательских типов создаются выражением new и удаляются сборщиком мусора как-нибудь при случае, то такой фокус не пройдет. Поэтому в D можно явно сделать класс RAII классом:
autoclass Resource //весь фокус - тут
{
this()
{
/*
открываем файлы, создаем сокеты и вообще творим всякие непотребства
*/
}
~this()
{
//убираем за собой
}
}
//где-то в коде:
{
Resource r = new Resource; //так авто-классы использовать нельзяauto Resource r = new Resource; //только с явным указанием намерений
....
} //при выходе из scope - вызовутся деструкторы всех auto-переменных, ресурсы освободятся - даже в случае исключения
Здравствуйте, uw, Вы писали:
ЗХ>>Да я вот все думаю, с какой бы стороны подступиться к интеграции его с С++ными библиотеками... ИМХО, решение должно быть где-то рядом uw>SWIG
uw>Вроде кто-то реализовывал поддержку D. Самые новые исходники там, в svn репозитории. В каком это состоянии, я не в курсе, но возможно во вполне работоспособном. Вот страница с более старыми версиями(включая бинарники) и хоть каким-то описанием.
Вав! Про свиг знал, про то что он есть под D — даже предположить не мог. Получи заслуженную оценочку
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Сюрприз! D позволяет каждому классу выполнять сколь угодно сложную инициализацию до начала функции main: ЗХ>
ЗХ>class A
ЗХ>{
ЗХ> int r = random(); //так нельзя!
ЗХ> static this()
ЗХ> {
ЗХ> //это выполнится до начала main 1 раз. выделение ресурсов, задание начальных значений данных членов...
ЗХ> r = random(); //а вот так - можно!
ЗХ> }
ЗХ> static ~this()
ЗХ> {
ЗХ> //выполнится после конца main
ЗХ> }
ЗХ>}
ЗХ>
ЗХ>Теоретически, пара статический конструктор/статический деструктор, возможно, подойдет для создания синглетонов...
"возможно, подойдет для создания синглетонов..." собственно это они и есть.
Второе.
"инициализацию до начала функции main" это немного не так.
Вот исходник Harmonia WinMain, я выделил то место где инициализируются/"терминируются"
статические конструкторы/деструкторы
extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleUnitTests();
extern (Windows)
int WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
int result = 0;
gc_init(); // initialize garbage collector
_minit(); // initialize module constructor tabletry
{
_moduleCtor(); // call module constructors
_moduleUnitTests(); // run unit tests (optional)
}
catch (Object o) // catch any uncaught exceptions
{
// failed [code skiped]....
result = -2;
}
if( result == 0 )
{
try
{
NativeApplication.initialize();
// main message pump loopwhile( true )
{
if(!NativeApplication.doEvents())
break;
}
result = 0;
}
catch (Object o) // catch any uncaught exceptions
{
result = -1; // failed
// [code skiped]
}
finally
{
NativeApplication.finalize();
}
}
gc_term(); // run finalizers; terminate garbage collectorreturn result;
}
Есть 2 точки деструкции объекта: когда его можно удалить (например, на объект есть единственная ссылка, и она выходит из зоны видимости), и когда объект действительно удаляется. Желательно иметь возможность написать свой код для обоих случаев. (auto — это да, а ещё?)
Можно ли вызывать виртуальные функции в конструкторах и деструкторах?
Здравствуйте, LCR, Вы писали:
LCR>c-smile:
LCR>Вот ещё два момента, из-за которых я плохо сплю: LCR> Есть 2 точки деструкции объекта: когда его можно удалить (например, на объект есть единственная ссылка, и она выходит из зоны видимости), и когда объект действительно удаляется. Желательно иметь возможность написать свой код для обоих случаев. (auto — это да, а ещё?)
"на объект есть единственная ссылка" это определить в принципе возможно
но вычислительно относительно дорого (нужно прогнать gc_mark).
Что можно сделать так это в деструкторе узнать "мы внутри GC или нет".
LCR> Можно ли вызывать виртуальные функции в конструкторах и деструкторах? LCR>Ы?
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>>Два последних оператора — не очень-то рулез по производительности. Зато по очевидности — это, имхо намного лучше, чем "многозначный" оператор из D uw>Этот "многозначный" оператор придуман в первую очередь для случаев, когда сравниваемые значения(или их часть) можно привести к целочисленному типу. Такая модель сравнения давным-давно используется скажем в libc(strcmp, qsort, итд), Java(интерфейс Comparable), .NET(IComparable).
uw>Что может быть проще и очевидней вот такого кода?
uw>
uw>class Task
uw>{
uw> private int priority;
uw> public int opCmp(Task t)
uw> {
uw> return priority - t.priority;
uw> }
uw>}
uw>
Здравствуйте, uw, Вы писали:
uw>Здравствуйте, McSeem2, Вы писали:
MS>>Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке. MS>>Другая часто возникающая потребность — получение частного и остатка. Во всех извесных мне архитектурах это делается одной командой DIV. Но вот мы пишем: MS>>
MS>>int lift = a/b;
MS>>int rem = a%b;
MS>>
MS>>И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
uw>На самом деле работы в этом направлении(гарантированная оптимизация) ведутся, пока только исследовательские. И для этого не нужна будет специальная конструкция языка. Кстати два возвращаемых значения для функциональных языков(коими ни D,ни C++ естественно не являются) не проблема.
Здравствуйте, McSeem2, Вы писали:
MS>В высокоуровневых языках часто возникает ситуация "за лесом деревьев не видать". MS>Взять, хртя бы простейшее выражение (операция целочисленного масштабирования): MS>
MS>int v = a*b/c;
MS>
MS>a, b, c — все int. Так вот, на всех известных мне современных архитектурах, операция MUL выдает результат вдвое большей разрядности. А операция DIV тоже требует двойной разрядности. Таким образом, при использовании ассемблера, можно масштабировать целые значения практически во всем их диапазоне, не переходя на двойную разрядность целиком.
MS>Но копилятор обязан обрезать промежуточный результат a*b снова до одинарной разрядности и нет способа объяснить, что вот в данном случае обрезать не надо. Почему "обязан" — во-первых, компилятор не знает — может быть переполнение играет важную роль в данном алгоритме. Во-вторых, если мы усложним выражение: a*b*c/d — нам уже понадобится не двойная а тройная разрядность. Таким образом, в языках высокого уровня нет способа задействовать простую и эффективную последовательность инструкций mul/div. Таким образом, хотелось бы иметь что-то типа:
MS>
MS>Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке.
MS>Другая часто возникающая потребность — получение частного и остатка. Во всех извесных мне архитектурах это делается одной командой DIV. Но вот мы пишем: MS>
MS>int lift = a/b;
MS>int rem = a%b;
MS>
MS>И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
Здравствуйте, Шахтер, Вы писали:
CS>>Здравствуйте, Шахтер, Вы писали:
uw>>>>
uw>>>>class Task
uw>>>>{
uw>>>> private int priority;
uw>>>> public int opCmp(Task t)
uw>>>> {
uw>>>> return priority - t.priority;
uw>>>> }
uw>>>>}
uw>>>>
Ш>>>Код некорректный.
CS>>Суров ты брат Шахтер и не многословен. CS>>Объясни что в этих двух соснах не так?
Ш>max_int > (-1) , max_int — (-1) == min_int < 0 .
Ах это! Ну дык там диапазон возможных
значений всего от -15 до 15 (Win32 thread priority levels)
А так, да, согласен — для краевых значений int это не работает.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, Шахтер, Вы писали:
CS>>>Здравствуйте, Шахтер, Вы писали:
uw>>>>>
uw>>>>>class Task
uw>>>>>{
uw>>>>> private int priority;
uw>>>>> public int opCmp(Task t)
uw>>>>> {
uw>>>>> return priority - t.priority;
uw>>>>> }
uw>>>>>}
uw>>>>>
Ш>>>>Код некорректный.
CS>>>Суров ты брат Шахтер и не многословен. CS>>>Объясни что в этих двух соснах не так?
Ш>>max_int > (-1) , max_int — (-1) == min_int < 0 .
CS>Ах это! Ну дык там диапазон возможных CS>значений всего от -15 до 15 (Win32 thread priority levels)
CS>А так, да, согласен — для краевых значений int это не работает.
Если диапазон значений маленький, то да, но лучше на это не полагаться.
Простой не сложить случайно киллограммы с километрами.
WM>Вот чтобы хотелось увидеть от нового языка, это какой-нибудь хитрый способ наследования от базовых типов, чтобы можно было писать:
WM>
WM>class IdealInt : public int
WM>{
WM> //...
WM>};
WM>
Я пытаюсь вот Вальтера нагнуть на фичу extrenal method definition.
Пока в D можно писать так (но только для массивов)
Здравствуйте, c-smile, Вы писали:
CS>Что можно сделать так это в деструкторе узнать "мы внутри GC или нет".
А разьве это не всегда так? Разьве деструктор может позвать кто-то еще кроме GC? Если да, то зачем?
(Например, в Component Pascal, вызвать финализатор может только GC и никто другой, это потому что виртуальный пустой метод FINALIZE()- экспортируется "только для реализации", но не для вызова).
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ> вызов конструкторов базового класса — в любом месте конструктора. если нет явного вызова, вызовется в самом начале this()
А если не хочется вызывать его вовсе? Например, в Delphi конструктор базового класса можно вызвать, а можно не вызывать, как больше нравится (аналогично — деструктор).
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>> вызов конструкторов базового класса — в любом месте конструктора. если нет явного вызова, вызовется в самом начале this()
СГ>А если не хочется вызывать его вовсе? Например, в Delphi конструктор базового класса можно вызвать, а можно не вызывать, как больше нравится (аналогично — деструктор).
А можно пример, где нужно запретить вызов конструктора базового класса?
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>А можно пример, где нужно запретить вызов конструктора базового класса?
1) В Delphi это необходимость. Дело в том, что конструкторы могут быть виртуальными и абстрактными. Понятно, что абстрактный конструктор звать не надо.
А вообще, если такая возможность в языке есть, то и за другими примерами дело не встанет. Причем примеры могут быть такие, что с непривычки волосы дыбом встанут типа это ошибка дизайна и т.п.:
2) Например, в конструкторе базового класса захватывается некий ресурс, а мы теперь этого делать не хотим (откладываем это на потом — по мере надобности). Аналогично в деструкторе, только наоборот.
3) Например, это нужно во всех случаях когда не хочется выливать воду из уже наполовину заполненного чайника...
Ведь наследование, как известно, нарушает инкапсуляцию.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, eao197, Вы писали:
E>>А можно пример, где нужно запретить вызов конструктора базового класса?
СГ>А вообще, если такая возможность в языке есть, то и за другими примерами дело не встанет. Причем примеры могут быть такие, что с непривычки волосы дыбом встанут типа это ошибка дизайна и т.п.:
СГ>2) Например, в конструкторе базового класса захватывается некий ресурс, а мы теперь этого делать не хотим (откладываем это на потом — по мере надобности). Аналогично в деструкторе, только наоборот.
Мне кажется, что в этом случае лучше перепроектировать иерархию классов. Или расширить конструктор базового класса флагом, показывающим, нужно ли захватывать ресурс. А еще лучше, унаследоваться не от такого базового класса, а от исходного интерфейса, а функциональность нужного базового класса агрегировать в себя.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Мне кажется, что в этом случае лучше перепроектировать иерархию классов. Или расширить конструктор базового класса флагом, показывающим, нужно ли захватывать ресурс. А еще лучше, унаследоваться не от такого базового класса, а от исходного интерфейса, а функциональность нужного базового класса агрегировать в себя.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Если по-научному, то объект для которого не был вызван конструктор, не может предоставить вообще никаких гарантий непротиворечивости своего состояния. Это относится, в частности, и к базовому подобъекту.
За исключением случаев когда базовый конструктор виртуальный и уж тем более абстрактный, что имеет место быть, например, в Delphi.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>За исключением случаев когда базовый конструктор виртуальный и уж тем более абстрактный, что имеет место быть, например, в Delphi.
В Delphi конструктором назвали то, что в паттернах называется ObjectFactory...
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, eao197, Вы писали:
E>>Мне кажется, что в этом случае лучше перепроектировать иерархию классов. Или расширить конструктор базового класса флагом, показывающим, нужно ли захватывать ресурс. А еще лучше, унаследоваться не от такого базового класса, а от исходного интерфейса, а функциональность нужного базового класса агрегировать в себя.
СГ>Это-то понятно
В таком то, что язык не дает проигнорировать код конструктора нельзя считать недостатком языка. Совсем наоборот, это хорошо.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Hello, LCR!
You wrote on Tue, 03 May 2005 16:32:29 GMT:
L> Только давай чуть-чуть усовершенствуем ЗХ>>
ЗХ>> int c; //переменная типа int
ЗХ>> typedef int mycoolint; //тип "типа" int
L> ME>typedef int (*mcfp[](int (*fp)(void* v1, void* v2), int& r);
Тут ашипка - скобочки не хватает. Надо typedef int (*mcfp[])(int
(*fp)(void* v1, void* v2), int& r);
"Аналогия" никуда не делась. Вполне можно написать
[ccode]
int foo(int (*fp)(void* v1, void* v2), int& r)
{
return 20;
}
int bar(int (*fp)(void* v1, void* v2), int& r)
{
return 20;
}
int (*mcfp[])(int (*fp)(void* v1, void* v2), int& r) = {foo, bar, 0};
[/ccode]
L> ME>struct S {....};
L> ME>struct _tagS {....} S1; // определение типа S1!
L> ME>class C {...};
L> ME>enum E {...};
ЗХ>>
L> И куда делась твоя аналогия?
Вообще-то это на самом деле не аналогия, а почти цитата из стандарта
L> Ты видишь, она годится только для простых случаев.
The simpledeclaration
declspecifierseq opt initdeclaratorlist opt;
is divided into two parts: declspecifiers, the components of a
declspecifierseq, are described in 7.1 and declarators, the components of an
initdeclaratorlist, are described in clause 8.
Так вот, typedef относится как раз к declspecifiers.
With best regards, Sergey.
Posted via RSDN NNTP Server 1.9
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Я тащусь! Как ты так здорово распарсил это чудо и вычислил, что скобки не хватает!
typedef int (*mcfp[])(int (*fp)(void* v1, void* v2), int& r);
Но вопрос то не в этом. Если мы поставим квадратные скобки в любом другом "междускобьи":
typedef int (*mcfp)(int (*fp)(void* v1, void* v2), int& r) [];
typedef int (*mcfp)[](int (*fp)(void* v1, void* v2), int& r);
typedef int [] (*mcfp)(int (*fp)(void* v1, void* v2), int& r);
то такая простановка скобок в каждом из положений указанном выше выглядит разумной. К моему несчастью всё, что мне кажестя разумным, компилятор (с распечаткой стандарта в качестве ударного механизма) таковым не считает.
Я напомню, с чего всё начиналось. Начиналось с того, что я указал на идеологический косяк в D, который он перенял из C касаемо объявлений типов. На что Зверёк мне возразил, и сказал, что дескать всё гладко (то есть якобы определения для любых типов аналогичны typedef x y). Мой последующий контраргумент касается того, что эта гладкость прокатывает только для простых случаев, а рекурсивные определения наподобие
type mcfp = .. /* anything you want */;
прозрачнее и одновременно сколь угодно расширяемы.
PS: у меня ещё одна ошибка была L>>typedef struct _tagS {....} S1; // определение типа S1!
MS>В высокоуровневых языках часто возникает ситуация "за лесом деревьев не видать". MS>Взять, хотя бы простейшее выражение (операция целочисленного масштабирования): MS>
MS>int v = a*b/c;
MS>
MS>a, b, c — все int. ... MUL ... DIV ... простую и эффективную последовательность инструкций mul/div. Таким образом, хотелось бы иметь что-то типа: MS>
MS>Повторю еще раз — в рамках арифметической записи задача нерешаема в любом языке.
А что мешает ввести такой тернарный оператор:
(* / ) типа как ( ? : )
И при синт.разборе искать его сначала,
а если не найдется, то применить традиционные умножение/деление?
MS>Другая часто возникающая потребность — получение частного и остатка. ... DIV .... Но вот мы пишем: MS>
MS>int lift = a/b;
MS>int rem = a%b;
MS>
MS>И у нас нет ни малейшей гарантии того, что компилятор соптимизирует данную конструкцию в одну команду. А хотелось бы именно гарантии. Но для этого нужна специальная конструкция языка, причем весьма нетривиальная — с двумя взвращаемыми значениями.
Есть такой вариант:
c % o = d1 \ d2;
или
(c % o) = d1 \ d2;
где c и o являются lvalue соотв.типа.
Что скажут разработчики синтпарсеров и компиляторов,
не сильно ли навороченные эти две предложенные мной конструкции?
На предмет: a) непротиворечивости с традиционными
б) легкости разбора
с) а кто будет ими пользоваться?
?
c-smile:
CS>Да, МcSeem?
(Шёпот из-за угла: "Дайте человеку поработать ").
Играемся с памятью:
MyObject o = new MyObject (200);
delete o;
o.method(); // segmentation fault
Результат ожидаемый. Ну может быть сообщение слишком лаконично.
printf ("create an object\n");
MyObject o = new MyObject (100);
printf ("kill the object\n");
delete o;
printf ("dance on the grave %)\n");
for (int i = 1; i <=100; i++)
delete o; // segmentation fault
Результат ожидаемый, но где-то в аппендиксе теплилась надежда на то, что вдруг менеджер кучи помечает это место так, что можно удалять несколько раз. Ну или другое решение — объект в delete передаётся по ссылке, так что
MyObject o = ...;
delete o;
// o == null
printf ("dance on... Where is the grave?!!! %)\n");
for (int i = 1; i <=100; i++)
delete o; // segmentation fault
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>ИМХО, если возникла такая ситуация, где ты от базового класса отнаследовался, а конструктор его вызывать не хочешь — нефик было наследоваться. ЗХ>Если по-научному, то объект для которого не был вызван конструктор, не может предоставить вообще никаких гарантий непротиворечивости своего состояния. Это относится, в частности, и к базовому подобъекту.
А какие гарантии у объекта переопределяющего виртуальный метод? Надо вызывать базовый метод или нет?
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, LCR, Вы писали:
LCR>В Delphi конструктором назвали то, что в паттернах называется ObjectFactory...
Тогда уж FactoryMethod... В общем, ерунда это все. Это дизайнерское решение создателей языка. Оно неплохо работает на практике и доказывает, что С++ подход не тольк не единственный, но и далеко не лучший.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Элементарный. Предположим у тебя есть два вида координат. Одни реальные, другие виртуальные. Логика у них идентичная, но данные у них не совместимы (координаты то в разных системах). Имея жесткое определение типа ты можешь определить один тип, а второй вывести из него. Далее останется написать методы преобразования и ты получашь готовое решение без шума и пыли.
Альтернативой является наследование. Но например, в C# наследования для структур нет. Да и наследование порой порождает кучу проблем.
WM>Вот чтобы хотелось увидеть от нового языка, это какой-нибудь хитрый способ наследования от базовых типов, чтобы можно было писать:
WM>
WM>class IdealInt : public int
WM>{
WM> //...
WM>};
WM>
У этого тоже есть куча проблем. Если язык декларирует "все является объектом" и предоставляет набор виртуальных методов у базового класса, то наследование вэлью-типов может привести к неоднозначностям.
К тому же появляются нехилые проблемы с приведением типов. Ведь наследник может иметь другой размер.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Скромный вопрос... А эти контракты проверяются когда? Если в рантайме, то это просто дурь. А если в компайлтайме, то не ясен механизм проверок.
VD>Или это нечто вроде ассертов? Опять же может грохнуть в релизе...
В D (ассерты == исключения). Просто выбрасывается исключение AssertError. Если не ловить, то работает как ассерт.
В релизе все ассерты естественно игнорируются, но вместо ассертов можно использовать произвольный код. Естественно все проверки происходят в рантайме. Собственно проверки на валидность тех или иных значений это обычное дело, не так ли? Так вот контракты это просто синтаксический сахар для подобных проверок. И судя по всему используется это в основном для отладки.
Кстати диапазон допустимых значений в моем примере не так уж мал. [min_int/2,max_int/2] для очень многих задач вполне достаточно. Для беззнаковых чисел это вообще [0, max_int(!= max_uint)]. Бессмысленно даже говорить о том, что short или byte таким образом можно сравнивать абсолютно безболезненно. Для остальных случаев конечно потребуются сравнения, или можно как-нибудь задействовать int64.
P.S. Забавно, что все соглашаются, что может быть integer overflow и никто не обратил внимание на то, что код абсолютно не корректен(например отсутствие return в opCmp). Немножко не те языки уже начинают вырабатывать стойкие привычки.
Если кому нужно вот нормальный код, да еще и с тестированием производительности:
import std.perf, std.stdio, std.random;
class Task
{
// (INT_MAX/2)static const int MaxPriority = 1073741823;
// (INT_MIN/2)static const int MinPriority = -1073741824;
public this(int priority_)
{
priority = priority_;
}
int opCmp(Object o)
{
Task t = cast (Task) o;
return priority - t.priority;
}
public int Priority()
{
return priority;
}
public void Priority(int p)
{
priority = p;
}
invariant
{
assert((priority >= MinPriority) && (priority <= MaxPriority));
}
private int priority;
}
const int CHUNK_SIZE = 2000;
const int N_CYCLES = 100;
void main()
{
HighPerformanceCounter t = new HighPerformanceCounter();
t.start();
Task[] tl;
try
{
for (int i = 0; i < N_CYCLES; ++i)
{
for (int j = 0; j < CHUNK_SIZE; ++j)
tl ~= new Task((rand() % (1073741823 * 2)) - 1073741824);
tl.sort;
}
// tl[0].Priority = 2147483647;
}
catch(Exception e)
{
writefln(e.msg);
}
t.stop();
writefln("time elapsed : %d",t.milliseconds());
foreach (Task t; tl)
writefln("%d",t.Priority);
}
VladD2:
VD>Тогда уж FactoryMethod...
Термин эквивалентный ObjectFactory, btw.
VD>В общем, ерунда это все. Это дизайнерское решение создателей языка. Оно неплохо работает на практике и доказывает, что С++ подход не тольк не единственный, но и далеко не лучший.
Подход C++ также показал свою пригодность для программирования. Можешь поподробнее про это доказательство, а то что-то я не врубаюсь... На мой взгляд это дизайнерское решение ничего не доказывает.
Манул пj языку не смотрел — некогда, сложность синаксиса, с точки зрения
создания "правильной среды разработки"
по примерам в форуме не могу оценить, можете сейчас оценить сложность
написания такой среды относительно Java и C++
( имеется в виду на сколько сложно будет сделать IDE которая бы парсила
код на лету, делал правильный автокомлит,
рефакторинг etc)
L> то такая простановка скобок в каждом из положений указанном выше L> выглядит разумной. К моему несчастью всё, что мне кажестя L> разумным, компилятор (с распечаткой стандарта в качестве ударного L> механизма) таковым не считает.
Мне это тоже не нравится Мозги сломаешь, пока догадаешься, где какую
скобку лепить, а где звездочку. Только вот вся это возня со скобками
прекрасно обходится с помощью обсуждаемого typedef.
L> Я напомню, с чего всё начиналось. Начиналось с того, что я указал на L> идеологический косяк в D, который он перенял из C касаемо объявлений L> типов.
Вряд ли это можно назвать косяком. Собственно, выдумывать для typedef особый
синтаксис, отличный от синтаксиса объявлений переменных и типов мне не
кажется разумным. Т.е., если тип из предыдущего примера мы хотим объявлять
как
type mcfp = array of
(
func : ( (func : (void , void ) -> int ), void * ) -> int
);
то объявлять (и инициализировать при необходимости) переменные по старому,
как
int (*mcfp[])(int (fp)(void v1, void* v2), int& r) = {foo, bar,
0};
было бы глупостью. Ну а если поменять и это, сложновато будет
позиционировать D как наследника С
L> На что Зверёк мне возразил, и сказал, что дескать всё гладко (то есть L> якобы определения для любых типов аналогичны typedef x y). Мой L> последующий контраргумент касается того, что эта гладкость прокатывает L> только для простых случаев, а рекурсивные определения наподобие
type
L> mcfp = .. /* anything you want */;
L>
L> прозрачнее и одновременно сколь угодно расширяемы.
L> PS: у меня ещё одна ошибка была L>>> typedef struct _tagS {....} S1; // определение типа S1!
Ошибка была только в комментарии и выводах. Без typedef это определение типа
_tagS и переменной S1. Simple declaration, однако К чему там было
написано про енум Е и класс С, я, честно говоря, вообще не понял. Для енумов
тоже можно использовать typedef, и это тоже будет выглядеть как объявление
переменной, перед которым написали declspecifier.
With best regards, Sergey.
Posted via RSDN NNTP Server 1.9
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, VladD2, Вы писали:
ЗХ>>ИМХО, если возникла такая ситуация, где ты от базового класса отнаследовался, а конструктор его вызывать не хочешь — нефик было наследоваться. ЗХ>>Если по-научному, то объект для которого не был вызван конструктор, не может предоставить вообще никаких гарантий непротиворечивости своего состояния. Это относится, в частности, и к базовому подобъекту.
VD>А какие гарантии у объекта переопределяющего виртуальный метод? Надо вызывать базовый метод или нет?
Вопрос, конечно, интересный и неоднозначный. ИМХО, если объект наследника может модифицировать состояние базового подобъекта только через открытые и защищенные методы — этого достаточно для герентии непротиворечивости состояния оного подобъекта. Т.е. базовый метод вызывать не надо.
Здравствуйте, achmed, Вы писали:
A>Манул пj языку не смотрел — некогда, сложность синаксиса, с точки зрения A>создания "правильной среды разработки" A> по примерам в форуме не могу оценить, можете сейчас оценить сложность A>написания такой среды относительно Java и C++ A>( имеется в виду на сколько сложно будет сделать IDE которая бы парсила A>код на лету, делал правильный автокомлит, A>рефакторинг etc)
В общем-то, — я не специалист разработки сред
Единственное, что могу сказать:
Major Goals of D
...
* Make D substantially easier to implement a compiler for than C++.
...
* Have a context-free grammar.
...
Здравствуйте, achmed, Вы писали:
A>( имеется в виду на сколько сложно будет сделать IDE которая бы парсила A>код на лету, делал правильный автокомлит, A>рефакторинг etc)
DMD Front End Starter Kit
The dmdfe program consists of the Digital Mars D compiler front end with the backend hooks stubbed out. The goal is to make it easy to write tools that can parse and do basic semantics analysis on D code.
Здравствуйте, uw, Вы писали:
VD>>Или это нечто вроде ассертов? Опять же может грохнуть в релизе... uw>В D (ассерты == исключения). Просто выбрасывается исключение AssertError. Если не ловить, то работает как ассерт.
uw>В релизе все ассерты естественно игнорируются, но вместо ассертов можно использовать произвольный код. Естественно все проверки происходят в рантайме. Собственно проверки на валидность тех или иных значений это обычное дело, не так ли? Так вот контракты это просто синтаксический сахар для подобных проверок. И судя по всему используется это в основном для отладки.
По мне так неразумный выбор. В дотнете сделано умнее. Ассерты управляются флагами компиляции. И в релизе ты их можешь вообще убрать. А исключения как минимум будут досаждать дурацкими диалогами или ты их не увидишь в релизе.
uw>Кстати диапазон допустимых значений в моем примере не так уж мал. [min_int/2,max_int/2] для очень многих задач вполне достаточно.
Не. Так считать нельзя. Если один из параметров близок к пределу, то грохнуть может и на минимальных значениях второго. Так что тут нужно сразу оговаривать, что оба параметра не привышают лимит одновременно. А это уже и есть спецусловие. Оно коенчно зачастую проходит, но как я уже говорил может принести не мало проблем исли что. В управляемых средах с этим вопрос решается просто. Всегда можно включить проверку переполения и получить разумную диагностику (правда при диком падении производительности).
uw> Для беззнаковых чисел это вообще [0, max_int(!= max_uint)].
Гы. В беззнаковх числах подобное сравнение — это 100%-ная ошибка.
Попробуй на досуге выполнить вот это:
uint v1 = 0, v2 = 2;
Console.WriteLine(v1 - v2);
uw> Бессмысленно даже говорить о том, что short или byte таким образом можно сравнивать абсолютно безболезненно.
Действительно бессмысленно.
uw> Для остальных случаев конечно потребуются сравнения, или можно как-нибудь задействовать int64.
Можно, но при этом вариант с полноценным сравнением окажется лидиром в жолтой майке.
В общем, оптимизации порою стоят так дорого, что лучше их не далать. Точнее нужно полностью осознавать что делашь. Да и то проверять все и вся.
uw>P.S. Забавно, что все соглашаются, что может быть integer overflow и никто не обратил внимание на то, что код абсолютно не корректен(например отсутствие return в opCmp). Немножко не те языки уже начинают вырабатывать стойкие привычки.
Дык об этом тебе компилятор напомнит (если он не дурак). А переполнение это еще те грабли. Те кто по ним ступали не додут соврать.
uw>Если кому нужно вот нормальный код, да еще и с тестированием производительности:
Спасибо. Я пока что погляжу на Ди со стороны. Я уже гядел на него и с первого раза он мне понравился, но потом я как-то разочаловался. Много в нем спорного. А отсуствие полноценной компонентности так вообще для меня почти приговор. К КОМ-у же возвращаться после дотнета нет ни какого желания.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отнюдь. Это два разных порождающих паттерна.
VD>>В общем, ерунда это все. Это дизайнерское решение создателей языка. Оно неплохо работает на практике и доказывает, что С++ подход не тольк не единственный, но и далеко не лучший.
LCR>Подход C++ также показал свою пригодность для программирования.
Согласен. Но не более того.
LCR> Можешь поподробнее про это доказательство, а то что-то я не врубаюсь... На мой взгляд это дизайнерское решение ничего не доказывает.
А ты зайди на форум по С++ и поинтересуйся сколько раз задавался вопрос о вызове виртуальных функций из конструктора и деструктора. Всем вопрощающим обычно указывают на их неразумность и начинают доказывать правильность концепции предворительной инициализации (и это при том, что ее этот язык гарантировать вообще не может). В дельфи же при этом никаких проблем нет. Остается один аргумент "а если забудешь вызвать родительский конструктор". Но аргумент явно надуманный, так как практически ни у кого это проблем не вызывает, а вот невиртуальность в конструкторах и еще больше в деструкторах ой как неудобна.
Ну, и наследуемость конструкторов тоже очень удобноая фишка. Я даже на Шарпе от этого устаю. Создал колеекцию и давай объявлять в ней 20 конструкторов. Брррр!
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Вопрос, конечно, интересный и неоднозначный. ИМХО, если объект наследника может модифицировать состояние базового подобъекта только через открытые и защищенные методы — этого достаточно для герентии непротиворечивости состояния оного подобъекта. Т.е. базовый метод вызывать не надо.
Вопрос прост как три копейки. Просто он с сильной подковыкой для апологетов С++-ных конструктров. (к шарпу это тоже относится хотя и не совсем).
Так вот надо или не надо вызвать базовый метод — это часть контракта базового класса. По уму нужно было бы явно специфицировать данное требование. Ну, предположим гипотетический синтаксис:
class Base
{
[Required]
public Constructor()
{
}
}
class A : Base
{
public Constructor()
{
...
Constructor(); // OK
...
}
}
calss B
{
public Constructor()
{
...// Ошибка! Должен вызываться базовый конструктор.
}
}
ну, и тоже самое с методами. Тогда и проблем бы небыло.
К сожалению подобного нет и в дельфи. Однака как показала практика проблем от подобного рода ошибок в Дельфи практически не наблюдалось. Так что можно сделать вывод об ошибочности доводов апологетов С++.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Так вот надо или не надо вызвать базовый метод — это часть контракта базового класса. По уму нужно было бы явно специфицировать данное требование.
Здравствуйте, VladD2, Вы писали:
ЗХ>>конечно, а зачем?
VD>Не, ну, ты определись. Или конечно или зачем. А то это меня пугает сильнее надписей.
фразу "конечно, а зачем?" очень любил один мой школьный товарищ. Она мне настолько нравится и настолько соответствует многим вещам, обсуждаемым в этом форуме, что, как видите, я давно занес ее в ориджин.
Дословно она означает "Звучит это великолепно, выглядит очень красиво. Безусловно, это гениальная идея. А кому и зачем это может пригодиться? Может, выкинем это нафик, пока не поздно?"
Возможно, из-за моих длинных рассуждений потерялась суть; буду краток
В С++ типы объявляются несколькими способами (классы, структуры, указатели-массивы на что-либо и чего-либо — все по-разному) и объявление типа с помощью typedef как-бы "задом наперёд".
Это я и считаю идеологическим косяком.
Я неединственный, кто испытывает дискомфорт от этого и коли уж изобретать новый язык, то наверное можно было бы работу с типами сделать по-лучше. Но этого не сделал создатель, и мне в связи с этим остаётся просто вздохнуть — не бывать совершенству в этом мире. Привыкли же к С++ и ничего
Здравствуйте, VladD2, Вы писали:
VD>Отнюдь. Это два разных порождающих паттерна.
Да прям. Случайно не путаешь с AbstractFactory?
VD>А ты зайди на форум по С++ и поинтересуйся сколько раз задавался вопрос о вызове виртуальных функций из конструктора и деструктора. Всем вопрощающим обычно указывают на их неразумность и начинают доказывать правильность концепции предворительной инициализации (и это при том, что ее этот язык гарантировать вообще не может). В дельфи же при этом никаких проблем нет. Остается один аргумент "а если забудешь вызвать родительский конструктор". Но аргумент явно надуманный, так как практически ни у кого это проблем не вызывает, а вот невиртуальность в конструкторах и еще больше в деструкторах ой как неудобна.
Тяжело в ученье — лекго в бою. (с) Суворов.
А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками.
Здравствуйте, L.C.R., Вы писали:
LCR>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками.
+1
Причем эта проблема посерьезней будет.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор...
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>фразу "конечно, а зачем?" очень любил один мой школьный товарищ. Она мне настолько нравится и настолько соответствует многим вещам, обсуждаемым в этом форуме, что, как видите, я давно занес ее в ориджин. ЗХ>Дословно она означает "Звучит это великолепно, выглядит очень красиво. Безусловно, это гениальная идея. А кому и зачем это может пригодиться? Может, выкинем это нафик, пока не поздно?"
Нда. С таким рвением обсуждать вопросы перегрузки операторов и вообще ни во что не ставить средства повыщения надежности программ. Однако наша философия превращается в черти что.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, Сергей Губанов, Вы писали:
СГ>А если не хочется вызывать его вовсе? Например, в Delphi конструктор базового класса можно вызвать, а можно не вызывать, как больше нравится (аналогично — деструктор).
Конструктор — это не просто метод, это часть процесса инициализации объекта. Если не вызывать базовый конструктор, то нет никакой формальной гарантии и возможности инициализации базовых приватных переменных объекта.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, L.C.R., Вы писали:
LCR>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы).
Странно, а какая связь между вирутальными (абстрактными) конструкторами (с которых началаясь эта ветка форума) и умными указателями . Я всегда думал, что умные указатели растут из templates + автоматический вызов деструкторов при выходе из блока.
С другой стороны, Вы говорите об уже устаревшей Delphi-7, ведь Delphi-8 (на же Delphi for .NET) и Delphi-9 (она же Delphi 2005) стали писаться под .NET, потребность в умных указателях как бы пропала — работает натуральная сборка мусора.
Здравствуйте, c-smile, Вы писали:
CS>delete в C++ есть? есть... CS>хорошо это или плохо? Хорошо. Для задач которые решает C++.
CS>GC в .NET есть? есть... CS>хорошо это или плохо? Хорошо. Для задач которые решает .NET
CS>В D есть и то и то. CS>Значит D может решать задачи С++ и .NET не выходя из одной среды.
Ага. Я бы сказал консолидирует проблемы обоих подходв.
Чдо до решаемых задачь, то что-то не видать на Ди драйверов и риалтайм-систем. А остальные задачи можно решать и на дотнете и на С++.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, IT, Вы писали:
IT>Конструктор — это не просто метод, это часть процесса инициализации объекта. Если не вызывать базовый конструктор, то нет никакой формальной гарантии и возможности инициализации базовых приватных переменных объекта.
1. Может быть предварительная инициализация. Как в том же дотнете.
2. Можно заставлять вызывать конструктор. Компилятору не сложно отследить, что все ветви выполнения содержат вызов базового конструктора.
3. В базовом конструкторе можно декларировать необязательность вызова конструктора.
В общем, это все решаемые проблемы. Я в свое время повозился с Дельфи и могу сказать с уверенностью, что отсутствие контроля компилятора за вызовом базовых конструкторов на практике проблем не создает. А вот кибкость от этого несколько увеличивается. Все же возможность вызова виртуальных функций в конструкторе позволяет создавать довольно хитрые схемы инициализации не прибегая к нагораживанию кучи паттеров на ровном месте.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>В общем, это все решаемые проблемы. Я в свое время повозился с Дельфи и могу сказать с уверенностью, что отсутствие контроля компилятора за вызовом базовых конструкторов на практике проблем не создает. А вот кибкость от этого несколько увеличивается.
Каким образом?
VD>Все же возможность вызова виртуальных функций в конструкторе позволяет создавать довольно хитрые схемы инициализации не прибегая к нагораживанию кучи паттеров на ровном месте.
А в .NET виртуальные методы в конструкторах разве не вызываются?
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Процесс вмешательства в работу GC ничем не лучше. Есть только один способ этому не повредить — delete ничего не должен делать с памятью. Т.е. программисты пусть свято верят и радуются жизни, но delete не трогает память. Память потом подчистит GC. Я искренне надеюсь, что в D это реализовано именно так, в противном случае при использовании деструкторов тормозов не избежать.
delete удаляет блок их хипа.
В D имплементирован вариант http://www.hpl.hp.com/personal/Hans_Boehm/gc/
Но в отличие от C++ на D из за его структуры объектов этот GC работает
детерминистки.
CS>>Достоинства по моему очевидны. IT>Совсем не очевидны. Я не знаю как работает диспетчер памяти в D, но зато очень хорошо представляю как работает GC в .NET и сишный хип. GC по скорости легко ложит сишный хип на лопатки на выделении большого количества маленьких объектов. Достигается это тем, что выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти. Никаких поисков наиболее подходящих кусков памяти, как в хипах. Теперь, в D, я вызываю деструктор и ты утверждаешь что память освобождается. Куда она освобождается? Запускается GC? Бред. Заносится в список неиспользуеых блоков памяти как в хипах? А потом что? При выделении памяти будем их просматривать? Тогда теряем всё преимущество скорости GC. В общем, я бы попытался с этим разобраться прежде чем столь наивно радоваться такой фиче.
Мон шер IT, у меня такое ощущение что ты в плену стереотипов .NET
Начать с того что выражение "выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти" вернО до тех пор пока ты говоришь только о выделении памяти.
Но если рассматривать весь объем затрат на GC включая copying/generation management то тут
имхо имеем паритет с C++. В С++ выделение памяти медленне но нет таких "менопауз".
Вообще как ты понимаешь чудес нет в memory management. Мы как-то постоянно об этом забываем.
Тут всегда trade-off: где-то теряем, где-то находим.
Выжать максимум можно только если ты можешь варьировать обеими подходами в "тонких" местах.
Что в D как раз и возможно.
И еще. И в С++ и в D написание своего domain specific аллокатора делающего
"выделение памяти сводится к простому сдвигу одного указателя на величину запрашиваемой памяти"
это дело 15 минут. Переопределить new/delete и выбрать способ выделения буфера.
Далее. "ложит сишный хип на лопатки на выделении большого количества маленьких объектов."
А зачем собственно выделять это самое большое количество маленьких объектов?
Когда это можно сделать одним единственным выделением?
Это мне напоминает процедуру создания себе трудностей с последующим их героическим преодолением. Вельми благодатный процесс. Т.е. создателям потребовались динамические конструкции например приснопамятный ArrayList чтобы все было "как у настоящих пацанов" для этого потребовался boxing который и повлек за собой потребность в "выделении большого количества маленьких объектов".
И т.д.
В D и в C++ такой ерундой не занимаются. vector<int> там это один кусок памяти, а не
массив указателей на int выделенных в managed memory space.
Еще раз говорю истина как всегда посредине — между "только heap" и "только GC".
И вот там, в этой золотой середине, и сидит D
На самом деле я Вальтеру предложил ввести механизм memory pools —
тогда вообще можно говорить
new(myGenerationalMemoryPool) MyObject,
new(myMarkAndSweepMemoryPool) MyObject,
new(Heap) MyObject.
Это лучше спрашивать у действующих дельфистов. Мой опыт с дельфи был в 97-ом (что ли, в общем с дельфи 2-3).
В общих чертах дельфийский конструктор — это как бы виртуальный фабричный метод с всеми вытекающими.
IT>А в .NET виртуальные методы в конструкторах разве не вызываются?
Вызваются. Но ты надесь знашь, как это раздражает С++-ных теоретиков. Для них это как пенопастом по стеклу.
Но тут есть очень похожий момент с конструкторами в дельфи. Так же как возможность виртуальных вызовов в шарпе раздражает С++-ников, так же конструкторы дельфи разражают всех кто не пописал на Дельфи.
Я не говорю что в Дельфи сделано все как надо. Я просто утверждаю, что бенефитов от такого решения больше чем проблем. А вот от решения С++ проблем больше чем бенефитов. Всто это я говорю на собственном опыте и наблюдении за другими программистами.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, c-smile, Вы писали:
CS>Вот DKernel — OS kernel на D. CS>http://www.prowiki.org/wiki4d/wiki.cgi?KernelWithD CS>Проект не закончен но на digital mars news в среднем раз в месяц CS>бойцы выходят с написанием очередной ОС.
Ну, что же. Может быть это и есть предназначение Ди. В принципе он мне нравится намного больше чем С++.
Вот игры что-то какие-то не вразумительные. Ну, да может тоже прорвется. Хотя тут уже приемуществ не так много. Для игр компонентность и рантайм очень полезны.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, c-smile, Вы писали:
CS>>Вот DKernel — OS kernel на D. CS>>http://www.prowiki.org/wiki4d/wiki.cgi?KernelWithD CS>>Проект не закончен но на digital mars news в среднем раз в месяц CS>>бойцы выходят с написанием очередной ОС.
VD>Ну, что же. Может быть это и есть предназначение Ди. В принципе он мне нравится намного больше чем С++.
Не думаю что именно в этом предназначение D.
Хотя, может ты и прав. Мног чего-то желающих писать
ситемные вещи.
GUI задачи я оченно даже вижу на D.
CS>>C играми желающих не меньше...
.... VD>Вот игры что-то какие-то не вразумительные. Ну, да может тоже прорвется. Хотя тут уже приемуществ не так много.
Думаю да.
VD> ... Для игр компонентность и рантайм очень полезны.
У нас тут вообще-то Electronoc Arts под боком. Иногда встречаюсь с бойцами оттуда.
Вот бы тебе с ними поговорить про "компонентность и рантайм" ...
У них все свое и все внутри на голых сях плюсовых с темплейтами.
Здравствуйте, IT, Вы писали:
VD>>В общем, это все решаемые проблемы. Я в свое время повозился с Дельфи и могу сказать с уверенностью, что отсутствие контроля компилятора за вызовом базовых конструкторов на практике проблем не создает. А вот кибкость от этого несколько увеличивается.
IT>Каким образом?
Давай ты решишь простую задачку. На шарпе. Итак — имеем некий псевдокод:
public class Node
{
private Node _parent;
public Node(Node parent)
{
_parent = parent;
}
public Node Parent
{
get { return _parent; }
}
}
public RootNode : Node
{
public RootNode()
{
base(this);
}
}
VladD2 wrote:
> C>С появлением .NET просто отпала потребность в самой Дельфи.... > Дельфи — это язык. От платформы он не особо зависит. По крайней мере > для перехода на дотнет костылей ему понадобилось гораздо меньше чем > плюсам.
В том-то и дело, что Дельфи — не ЯЗЫК, а технология. Ее плюс — она
позволяет достаточно просто создавать сравнительно небольшие
_автономные_ GUI-приложения. Отсутствие GC в Дельфи вполне понятно, так
как он тянет за собой лавину измений, да и не особо нужен GC в
формочко-ориентированых приложениях.
С приходом .NET тоже появилась возможность достаточно просто создавать
GUIшные приложения, только теперь уже не автономные, а зависящие от
двадцатимегабайтного фреймворка.
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Cyberax, Вы писали:
C>В том-то и дело, что Дельфи — не ЯЗЫК, а технология.
Дельфи это и язык, и технология. В наше время язык без богатого рантайма обречен на забвение. Дельфи не исключение. Но в первую очередь Дельфи это язык. Не даром его из "Обжект Паскаля" переименовали в "Дльфия лэнг".
C> Ее плюс — она C>позволяет достаточно просто создавать сравнительно небольшие C>_автономные_ GUI-приложения.
Дельфи неплохо подходит для любых задач где есть нужда в компонентных технологиях.
C> Отсутствие GC в Дельфи вполне понятно, так C>как он тянет за собой лавину измений, да и не особо нужен GC в C>формочко-ориентированых приложениях.
В Делфьи научились обходить проблемы, но наличие ЖЦ дает дополнительную свободу программисту и делает язык более высокоуровневым.
C>С приходом .NET тоже появилась возможность достаточно просто создавать C>GUIшные приложения, только теперь уже не автономные, а зависящие от C>двадцатимегабайтного фреймворка.
Я и раньше легко создавал ГУИ, да и другие компонентные вещи на связке VB + VC++, а до этого на Дельфи. Дотнет конечно дает намного более комлексное и приятное в использовании решение, но и дельфи в него вписывается очень горманично. Насколько я понимаю у Дельфи на сегодня есть только две проблемы:
1. Откровенно слабоватый маркетинг связанный с размерами и богатством Борланда.
2. Качество. Я не раз слышал нарекания на качетсво дельфи. МС сейчас вылизывает свои прдукты очень серьезно. И Борланду тоже прийдется очень постараться.
А технологические проблемы Борланд точно решит.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, c-smile, Вы писали:
CS>Т.е. new аллоцирует объекты на хипе и регистрирует их в (глобальном) списке. CS>Т.е. ты можешь сделать delete конкретного объекта как обычно. CS>А можешь попросить все объекты в хипе просканировать себя (mark) CS>и выполнить затем опять же delete тех объектов которые не помечены (sweep)
CS>Что тебе это дает?
Боюсь это даст менее эффективную работу ЖЦ и уж точно это приведет к старым добрым пробелмам С++ вроде проходво по памяти, ликам и т.п.
Одна из задач ЖЦ сделать программирование безопасным и предсказуемым. Об этом тоже не стоит забывать. В том же шарпе за просто можно нашурудить с указателями и выделением памяти вручную, но вот как-то не хочется. Задачи рашаются и без этого.
CS>Ну вот допишу свою Harmonia увидишь. CS>Честно, D — рулез. CS>Уже в общем и так видно.
А что будет видно то?
CS>Я думаю для людей серьезно программирующих на Java CS>и .NET и познавших "блеск и нищету куртизанок" CS>D представляет очень серьезный интерес. ИМХО, конечно.
Ну, вот я когда Ди только появился пристально на него смотрел, но как-то в конце концов плюнул на него. Слишком уж не мало спорного у него. Да и перспектива не понятна.
CS>Да, где-то местами своеобразный, но в общем и целом — кайф.
Пока что ты перечислил или кайф который я уже имю в Шарпе или такой кайф который лично мне очень не нравится. Ну, да может я все же что-то упустил.
CS>Возможность например "грохнуть" пул как одно целое и забыть CS>про все объекты там нааллоцированные. Например HTML страница со своим DOMом CS>при выгрузке оной может быть просто удалена как одно целое.
Да, вот это действительно ценным механизм оптимизации. Если бы его продумать как следует и реализовать так чтобы проблем не возникало...
Вот только боюсь опять будут проблемы с безопастностью. Ведь что значит грохнуть весь хип? А если на объекты в нем остались ссылки?
Согласен, скорость это может поднять координально. Но ведь чтобы избавиться от проблем прийдется отслеживать все внешние ссылки на этот хип или производить принудительный сбор мусора всех поколений (что не дешево). Да и при этом проблема не решается. Что если контроль показал, что ссылки все же есть? Производить копирующую сборку?
В обещм, может быть... но хотелось бы иметь такую фичу в защищенном управлемом коде, а не в виде хака. Хаки мне уеже в плюсах осточертели. Если ты не обратил внимания, то самый быстырй хип в тестах ИТ это мой QuickHeap. И я с радостью променял его на более медленный хип дотнета просто ради простоты и безопастности.
CS>Да не скатываюсь я. Меня скатывают это да.
Да скатывашся. Но это нармально. Не с плюсами же ЖЦ сравнивать?
CS>Я никогда ничего про .NET на пустом месте и по своей инциативе CS>не говорю.
А не ты ли создал тему где привел ссылку на какого-то бездарного писаку отрекающегося от дотнета?
CS> У меня просто идиосинкразия на любые попытки меня "построить строем". CS>Все на .NET! А зачем, а почему и кому это выгодно? CS>Никто толком не показывает, не рассказывает и не демонстрирует.
Мне кажется у тебя действительно эта как ее... Строить никого не собираются. Просто дотнет действительно досойный продукт. И уж если зашло сравнение его с Ди, так лучше не скатываться до демагогии и оскорблений, а действительно описать те приемущества которые ты заметил в Ди. Пока ты назвал только одно — возможность писать небезопастный код и упралвлять вручную памятью. Вот это и кажется очень сомнительным.
CS>Просто благие призывы: CS> CS>и все.
Вот это и есть демагогия.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
CS>>Возможность например "грохнуть" пул как одно целое и забыть CS>>про все объекты там нааллоцированные. Например HTML страница со своим DOMом CS>>при выгрузке оной может быть просто удалена как одно целое.
VD>Да, вот это действительно ценным механизм оптимизации. Если бы его продумать как следует и реализовать так чтобы проблем не возникало...
VD>Вот только боюсь опять будут проблемы с безопастностью. Ведь что значит грохнуть весь хип? А если на объекты в нем остались ссылки?
А не оставляй ссылки.
VD>Согласен, скорость это может поднять координально. Но ведь чтобы избавиться от проблем прийдется отслеживать все внешние ссылки на этот хип или производить принудительный сбор мусора всех поколений (что не дешево). Да и при этом проблема не решается. Что если контроль показал, что ссылки все же есть? Производить копирующую сборку?
Не надо никакого контроля особого.
Контроль он "денег стоит".
В Apache для того чтобы удалить весь
пул скопом делается одно простое движение.
Запрос выполнился — страница клиенту отдана — все, можно закрывать.
В PHP вообще никакого GC нет — он не нужен.
Т.е. наличие пулов — это еще один инструмент.
И как любой интсрумент при неправильном его использовании
может доставить неприятности.
VD>В обещм, может быть... но хотелось бы иметь такую фичу в защищенном управлемом коде, а не в виде хака. Хаки мне уеже в плюсах осточертели. Если ты не обратил внимания, то самый быстырй хип в тестах ИТ это мой QuickHeap. И я с радостью променял его на более медленный хип дотнета просто ради простоты и безопастности.
Хаки? Ну это дело стиля и дисциплины.
Свой собсвенный код на C++ я к хакам не отношу.
И про безопасность... Ну тебе то чего про безопасность
беспокоится? Ты ж не первый год плаваешь?
Безопасность нужна когда ты тонны кода индусам заказываешь которых напекли за пять месяцев
— это да.
Но опять же за все приходится платить.
Есть задачаи где платежи на code management оправданы и есть прямо противоположные.
VladD2 wrote:
> C>В том-то и дело, что Дельфи — не ЯЗЫК, а технология. > Дельфи это и язык, и технология. В наше время язык без богатого > рантайма обречен на забвение. Дельфи не исключение. Но в первую > очередь Дельфи это язык. Не даром его из "Обжект Паскаля" > переименовали в "Дльфия лэнг".
Как язык Дельфи не блещет особыми достижениями, в ней нет нормальных
средств для ручного управления памятью (умные указатели, автоматические
классы и т.п.), нет автоматического управления памятью, нет каких-лиюо
средств метапрограммирования, нет продвинутых средств типа лямбды и
замыканий.
Поэтому как язык особо Дельфи никому и не нужна.
> C> Ее плюс — она > C>позволяет достаточно просто создавать сравнительно небольшие > C>_автономные_ GUI-приложения. > Дельфи неплохо подходит для любых задач где есть нужда в компонентных > технологиях.
А "компонентые технологии" обычно нигде кроме простого GUI и не нужны....
> C> Отсутствие GC в Дельфи вполне понятно, так > C>как он тянет за собой лавину измений, да и не особо нужен GC в > C>формочко-ориентированых приложениях. > В Делфьи научились обходить проблемы, но наличие ЖЦ дает > дополнительную свободу программисту и делает язык более высокоуровневым.
И при этом требует кардинального изменения в организации окружения.
> C>С приходом .NET тоже появилась возможность достаточно просто создавать > C>GUIшные приложения, только теперь уже не автономные, а зависящие от > C>двадцатимегабайтного фреймворка. > Я и раньше легко создавал ГУИ, да и другие компонентные вещи на связке > VB + VC++
Чего-то сложнее формочек с несколькими таблицами на VB нормально не
пишется, так как метод "drag-and-drop контролов на форму" становится
неприменим, зато становится необходимой нормаль.
> 1. Откровенно слабоватый маркетинг связанный с размерами и богатством > Борланда. > 2. Качество. Я не раз слышал нарекания на качетсво дельфи. МС сейчас > вылизывает свои прдукты очень серьезно. И Борланду тоже прийдется > очень постараться.
3. Отсутствие целевого рынка (VB.NET/C#+WinForms делают те же задачи,
что и Дельфи.NET).
4. Непонятная позиция Borland'а в отношении Дельфи.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, AndrewVK, Вы писали:
AVK>>Сможешь повторить на реальном шарпе?
IT>Это искуственное ограничение языка.
Это же всего лишь гипотетический пример, не стоит из него делать столь далеко идущих выводов. Ну пуская в RootNode нужно передавать не this, а какой нибудь указатель, причем выбор нужно сделать исходя из условия. Можно конечно сочинить статический метод (иногда я так и делаю), но, согласись, выглядит это уродливо, хотя от попыток кривить дизайн работой с полями экземпляра перед работой базового конструктора конечно страхует.
Ссылка полезная для оценки какого типа задачи на
каком языке/платформе лучше делать.
CS>>Честно, D — рулез.
IT>А что нужно чтобы на нём начать писать? Он в студию как-нибудь встраивается? А то я ленивый стал, изучать новые текстовые редакторы в лом.
Закачать компилятор и поставить его
в c:/dmd и тулзы в c:/dm
Кривые там тесты, например python psyco тесты выполняются с отключенным psyco и получается что версия питона с jit компилятором работает медленее чем интерпретируемый вариант(реально на многих тестах psyco вариант на порядок быстрее). Да и по тестам по C++ видно что написано криво.
При том от запуска к запуску лидер может менятся, практически скорость программ одинаковая. Пробовал сишные файлы компилировать GCC и VC7.1 результат практически тот же. У меня сильные подозрения что плюсовые файлы компилировались с отключенной оптимизацией.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, VladD2, Вы писали:
VD>>Забвано было бы написать VM c JIT-компиляцией на Ди.
CS>Вальтер написал на D VM для JavaScript CS>http://www.digitalmars.com/dscript/index.html CS>JITа там конечно нет.
Нафиг для JavaScript нужна VM? Интерпретатор и есть интерпретатор. Это всем не то, что Ява-рантайм, или CLR.
CS>Но просто компилятор есть.
Компилятор чего?
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Машейничество это а не тесты. Об это не раз говорилось. Они там загадочный CPU Time измеряют. Не трудно догадаться, что для управляемых языков это измерение мремени компиляции и инициализации виртуальной машины. Плюс во время включаются такие вещи как чтение файлов, используются не идентичные по реализации структуры данных и т.п. Ну, и писали их люди в оптимизации для управляемых сред мало чего понимающие.
Можно взять их идеи за основу и переделать по человечески. Ну, и перемерять под Виндвс (где есть достойные JIT-ы дотнета и Явы).
К выходу второго фрэймворка нужно будет сделать новых Шустриков и включить туда Ди, Питон и Окамл. Да проверить на вшивость как следует. Вот тогда можно будет что-то утверждать.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Машейничают. Измеряют время работы ЕХЕ-шника, а не чистого кода. Ну, и пишут там, что измеряют подсчет слов, а на деле измеряют скорость чтения файла с диска.
В общем, неплохая идея превращена в полную профанацию. Об этих "тестах" тут уже не раз говаривалось. Но некоторые товарищи несмущаясь приводят их снова и снова.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Cyberax, Вы писали:
C>Как язык Дельфи не блещет особыми достижениями, в ней нет нормальных C>средств для ручного управления памятью (умные указатели, автоматические C>классы и т.п.), нет автоматического управления памятью, нет каких-лиюо C>средств метапрограммирования, нет продвинутых средств типа лямбды и C>замыканий.
Про управление памятью я уже говорил. Отсуствие ЖЦ — это конечно недостаток, но управление памятью в Дельфи отнимало не бьльше чем при пронраммировании на С++. Умные указатели и т.п. — это все костыли.
Что касается метапрограммирования. Да его там нет. Но за то там есть компоненты, компонентная модель и метаинформация оплностью отсутсвующая в плюсах. А метапрограммированием можно заниматься и вне рамок языка если есть метаинформация или хороший парсер.
Лямбды там действительно нет. Но есть вложенные методы и замыкания. Дельфи, кстати, один из немногих языков в которых замыкания называются замыканиями.
C>Поэтому как язык особо Дельфи никому и не нужна.
На дельфи писали, пишут и еще очень долго будут писать приложения. Во всем мире популярность его конечно не так что у плюсов, но у нас дельфи более чем поеулярен. И если бы не дотнет, то Дельфи еще долго была бы лидером в жолтой майке.
C>А "компонентые технологии" обычно нигде кроме простого GUI и не нужны....
Так оно и есть... если добавить одну оговорку — лично тобой.
>> В Делфьи научились обходить проблемы, но наличие ЖЦ дает >> дополнительную свободу программисту и делает язык более высокоуровневым.
C>И при этом требует кардинального изменения в организации окружения.
Отнюдь.
C>Чего-то сложнее формочек с несколькими таблицами на VB нормально не C>пишется, так как метод "drag-and-drop контролов на форму" становится C>неприменим, зато становится необходимой нормаль.
Опять же тобой. VB6- с успехом использовался для создания компонентов в трехзвенке, а об АСП я вообще молчу.
>> 1. Откровенно слабоватый маркетинг связанный с размерами и богатством >> Борланда. >> 2. Качество. Я не раз слышал нарекания на качетсво дельфи. МС сейчас >> вылизывает свои прдукты очень серьезно. И Борланду тоже прийдется >> очень постараться.
C>3. Отсутствие целевого рынка (VB.NET/C#+WinForms делают те же задачи, C>что и Дельфи.NET).
Старный ты человек. На ранке могут, а вренее должны, соусуществовать разные решения. Только одино решение приведет к застою и ушудшению ситуации.
C>4. Непонятная позиция Borland'а в отношении Дельфи.
Да позиция более чем понятна. Просто пп. 1-2 мешает.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, c-smile, Вы писали:
CS>А не оставляй ссылки.
Это не серьзно. Главное что даем мне ЖЦ — это снимает с меня заботу об управлении памятью. Ты же предлагаешь мне вернуться обратно в каменный век.
CS>Не надо никакого контроля особого. CS>Контроль он "денег стоит".
Тогда уж лучше не нужно таких оптимизаций. Не намного медленее будет и с ЖЦ если профиль приложения под него подогнать. Деревья на одну секунуд не создаются. Обычно они после построения продвигаются в 1-2 поколение и каши не просят (на скорость сборки нулевого не влияют).
CS>В Apache для того чтобы удалить весь CS>пул скопом делается одно простое движение. CS>Запрос выполнился — страница клиенту отдана — все, можно закрывать. CS>В PHP вообще никакого GC нет — он не нужен.
И что я выигрываю используя Апач? В дотнете всей этой трахомудии нет, но ASP.Net работает не медлненее JSP под апачем. К тому же ты говоришь об оптимизации фрэймворка. А их пишут более отвественные люди и отлаживают тщетельнее чем прикладной код. Ты же предлагаешь отдать такие опасные оптимизации именно прикладникам. Опять же согласен, что где-то внутри ОС где скорость критична я лекго пошел бы на подобную оптимизацию. Но вот уже в компиляторе я бы предпочел пользоваться автоматикой. Те сотые доли секунды которые нужны на полный ЖЫ никак меня не спасут. А вот время на отладке я точно сэкономлю.
CS>Т.е. наличие пулов — это еще один инструмент. CS>И как любой интсрумент при неправильном его использовании CS>может доставить неприятности.
Изивин, но инструмент инструменту рознь. Бывают, например, бриты опасные, а бывают безопасные. Может опасная бреет чуть лучше, но вот почему-то почти все перестали ими пользоваться.
CS>Но опять же за все приходится платить. CS>Есть задачаи где платежи на code management оправданы и есть прямо противоположные.
Согласен. Только 90% задачь более чем пригодна для решения их управляемыми средсвами. Расплат в основном идет за счет памяти. А ее что-то все больше и больше.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, FR, Вы писали:
FR>>Еще насчет этих тестов, сильно сомнительные результаты, например тест sum-file benchmark, у них такие результаты:
CS>Ты прав. На самом деле всякого рода бенчмарки это всегда палка о двух концах. CS>Очень много всяких но. Какой процессор, какая ось и т.д.
CS>Т.е. все очень приблизительно.
Только вряд ли все это может дать разницу в разы или даже на порядки.
Например у них C++ g++ почти в 9 раз медленее чем D (У меня gcc3.2 и D v0.122 дают практически одинаковый результат). Ничем кроме ошибок замера это не объяснить. И таких мест в этих тестах полно.
CS>А ты D компилировал с -release -inline -O ?
да
CS>На моей машине (Pentium4) CS>D идет "ноздря в ноздрю" с C++ CS>где-то отстает но в основном на уровне CS>и лучше чем VC++ из VS6
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, IT, Вы писали:
CS>>>Вот по тестам в разбивку: CS>>>http://shootout.alioth.debian.org/great/index.php?sort=fullcpu
IT>>Я не понял только как делались замеры времени.
VD>Машейничают. Измеряют время работы ЕХЕ-шника, а не чистого кода. Ну, и пишут там, что измеряют подсчет слов, а на деле измеряют скорость чтения файла с диска.
Угу, но даже повторяя все по их методике почему-то у меня d, си и с++ показывают практически одинаковые результаты, тогда как у них разница в разы.
Здравствуйте, FR, Вы писали:
FR>Угу, но даже повторяя все по их методике почему-то у меня d, си и с++ показывают практически одинаковые результаты, тогда как у них разница в разы.
Значит многократно мошейничают.
ЗЫ
На что только не способено человеческое вожделение.
... << RSDN@Home 1.1.4 beta 4 rev. 351>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>К выходу второго фрэймворка нужно будет сделать новых Шустриков и включить туда Ди, Питон и Окамл. Да проверить на вшивость как следует. Вот тогда можно будет что-то утверждать.
Оберон ещё не забудь. Судя по тестам кульный язык.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Сергей Губанов wrote:
> 1) "try finally end" является конструкцией структурного > программирования, такая же как все остальные структурные конструкции > while, if, case и т.д. и не имеет ни какого отношения к ООП.
Как помнится мне, в конструкции структурного программирования входят
только циклы и ветвления. Про исключения там нет ничего.
Так что можно сказать, что конструкции типа ScopeGuard — это тоже пример
структурного программирования, причем более удобный чем try..finally.
ООП для реализации ScopeGuard'ов действительно не нужен.
> Язык имеющий ее не обязан быть ОО языком, он должен быть просто > структурным. Катить бочку на нее — все равно что катить бочку на > структурное программирование. В то время как конструкция > автоматического вызова деструктора статического объекта — есть всего > лишь специфическое свойство отдельно взятого языка.
Так же как и try..finally — специфическое свойство нескольких языков.
> 2) Не замучаетесь на каждый чих писать все новые и новые аналоги > классов ResGuard (лишние сущности)?
Шаблоны (template'ы) и boost::bind спасут отца советской демократи.
> Использование структурной конструкции finally избавляет от этой лишней > писанины и структурирует программу.
Нет, try..finally загрязняют программу и делают ее менее читабельной.
Вдобавок еще и менее надежной, так как элементарно можно забыть про
finally и получить утечку ресурсов.
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Сергей Губанов, Вы писали:
СГ>2) Не замучаетесь на каждый чих писать все новые и новые аналоги классов ResGuard (лишние сущности)? Использование структурной конструкции finally избавляет от этой лишней писанины и структурирует программу.
Здравствуйте, Cyberax, Вы писали:
C>Как помнится мне, в конструкции структурного программирования входят C>только циклы и ветвления. Про исключения там нет ничего.
Извините, конечно, но помнить этого не надо — это надо понимать. Естественно, когда структурное программирование только начинало формироваться инструкции finally еще не было. Но мир-то на месте не стоит. Структурное программирование развивается. Finally — появляется как естественное развитие структурного программирования. И кто знает, быть может, в будущем в структурное программирование добавится еще не одна инструкция.
Кстати, finally и исключения хоть и взаимосвязаны по происхождению, но на самом деле могут преспокойно быть отделены друг от друга: finally можно использовать даже тогда, когда нет никаких исключений:
PROCEDURE Do()
BEGIN
...
BEGIN
...
IF condition1 THEN f(); RETURN END;
...
IF condition2 THEN g(); RETURN END;
...
FINALLY
h()
END;
...
END Do;
Пример BEGIN-FINALLY-END блока на только что вымышленном мной языке программирования
Re[14]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Сергей Губанов wrote:
> C>Как помнится мне, в конструкции структурного программирования входят > C>только циклы и ветвления. Про исключения там нет ничего. > Извините, конечно, но помнить этого не надо — это надо понимать. > Естественно, когда структурное программирование только начинало > формироваться инструкции finally еще не было.
Замечательно, потому что под стр. программированием я понимаю то, что
написано у Кнута.
> Но мир-то на месте не стоит. Структурное программирование развивается. > Finally — появляется как естественное развитие структурного > программирования.
ScopeGuard'ы — тоже. Да и вообще, забудьте наконец-то про "структурное
программирование" — оно давно уже перестало быть чем-то особенным.
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[15]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Cyberax, Вы писали:
C>Да и вообще, забудьте наконец-то про "структурное C>программирование" — оно давно уже перестало быть чем-то особенным.
Боюсь что нет, например, в C# есть goto, т.е. один из самых современных языков программирования имеет средство нарушения структурности
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Сергей Губанов, Вы писали:
СГ>1) "try finally end" является конструкцией структурного программирования, такая же как все остальные структурные конструкции while, if, case и т.д. и не имеет ни какого отношения к ООП. Язык имеющий ее не обязан быть ОО языком, он должен быть просто структурным. Катить бочку на нее — все равно что катить бочку на структурное программирование. В то время как конструкция автоматического вызова деструктора статического объекта — есть всего лишь специфическое свойство отдельно взятого языка.
Тут Киберакс уже ответил про новые аналоги ResGuard. Я же вставлю свои 5 копеек в отношении "try finally end". Что это такое? Это объектно-ориентированный аналог такой штуки, которая называется longjump. Грязный хак в чистом виде!
Разумеется в структурном программировании (которое всеми своими ветвлениями старается отбрыкаться от бедного goto) введение и легализация подобной концепции — это нонсенс. Поэтому лонгджампа нет и у Кнута, и у Дейкстры и у других авторов.
Исключения — это уже дальнейшее развитие и облагораживание лонгджампа средствами ООП и поддержкой ОС.
Сергей Губанов wrote:
> C>Да и вообще, забудьте наконец-то про "структурное > C>программирование" — оно давно уже перестало быть чем-то особенным. > Боюсь что нет, например, в C# есть *goto*, т.е. один из самых > современных языков программирования имеет средство нарушения > структурности
И что? В С++ных программах еще и ассемблерные вставки бывают Никто же
палкой не заставляет использовать goto.
ЗЫ: в Java, кстати, goto нет.
--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[16]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Боюсь что нет, например, в C# есть goto, т.е. один из самых современных языков программирования имеет средство нарушения структурности
Ну имеет и дальше то что? goto может быть практически незаменим при генерации кода.
Да и в редких случаях его можно довольно красиво использовать значительно упрощая код. Например
Здравствуйте, WolfHound, Вы писали:
WH>goto может быть практически незаменим при генерации кода. WH>Да и в редких случаях его можно довольно красиво использовать значительно упрощая код. WH>Например
Попробовал, кажется получилось красивее чем в Вашем примере с goto:
PROCEDURE Merge(a, b: Node; less: Less): Node;
VAR head, tail: Node;
BEGIN
IF a = NIL THEN RETURN b END;
IF b = NIL THEN RETURN a END;
IF less(a, b) THEN head := a; a := a.next ELSE head := b; b := b.next END;
tail := head;
LOOP
IF a = NIL THEN tail.next := b; EXIT END;
IF b = NIL THEN tail.next := a; EXIT END;
IF less(a, b) THEN
tail.next := a; tail := a; a := a.next
ELSE
tail.next := b; tail := b; b := b.next
END
END;
RETURN head;
END Merge;
Если вместо less(a, b): BOOLEAN использовать min(a, b): Node, то будет еще красивее.
WH>...и с одной точкой выхода из функции.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Попробовал, кажется получилось красивее чем в Вашем примере с goto:
Что за дурацкая привычка лепить все в одну строчку?
PROCEDURE Merge(a, b: Node; less: Less): Node;
VAR head, tail: Node;
BEGIN(* Это лишнее ибо эта функция не расчитана на прямое использование
IF a = NIL THEN
RETURN b
END;
IF b = NIL THEN
RETURN a
END;
*)
(*Дублирование кода*)IF less(a, b) THEN
head := a;
a := a.next
ELSE
head := b;
b := b.next
END;
tail := head;
LOOP
(*лишние проверки в цикле*)
(*если на предыдущей итерации не выполнилось less(a, b)
то это условие никогда не выполнится*)IF a = NIL THEN
tail.next := b;
EXIT
END;
(*если на предыдущей итерации выполнилось less(a, b)
то это условие никогда не выполнится*)IF b = NIL THEN
tail.next := a;
EXIT
END;
IF less(a, b) THEN
tail.next := a;
tail := a;
a := a.next
ELSE
tail.next := b;
tail := b;
b := b.next
END
END;
RETURN head;
END Merge;
Итого: лишнии проверки в цикле и два неосуществимых пути. Это не способствует ни пониманию ни производительности.
СГ>Зачем с одной точкой выхода?
Чтобы все совсем структурно было...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>К слову, эта идея (избавления от "ненужных операторов") не распространена на операторы вида op= (+=, -= и т.д.). Почему? То есть, конечно, логику в этом, видимо, можно найти... Но лень.
Логика такая, что не все домены имеют обратные операции.
Если мы реализуем группу — тогда да, на каждый плюс найдётся свой минус. Но какой декремент может быть, например, для строк? str+=tail, но не str-=tail.
Кстати, хохму придумал. Почему бы не трактовать для строк a-b как b+a, и соответственно a-=b как a=a-b=b+a, то есть прибавление к началу строки?
Здравствуйте, Кодт, Вы писали:
ЗХ>>Я, когда мне нужно использовать в качестве ключей мапы класс, сравнение объектов которого бессмысленно, предпочитаю определять для этого свой функтор-компаратор, который не выглядит как operator<
К>Тут история вот какая: К>1) разные отношения К>- эквивалентность, которому соответствует семейство сравнений ==, != К>- порядок, которому соответствуют < > <= >= == != (т.е. эквивалентность вытекает из порядка) К>Причём для введения каждого из них необходимо и достаточно определить, соответственно, равенство ( == ) и одно из строгих неравенств ( < > ) К>2) отношение порядка можно задавать как предикатом неравенства (X,X)->bool, так и троичной функцией-компаратором (X,X)->{-,0,+} — эти способы взаимозаменяемы К>3) троичный компаратор в роли базиса — практически удобнее, чем неравенство: К>- он антисимметричен (а значит, его проще и реализовывать, и использовать) К>- все операторы (включая ==) определяются через одно обращение к компаратору: К>- — x>y = cmp(x,y)>0; x<=y = cmp(x,y)<=0; x==y = cmp(x,y)==0 К>- — x<y = less(y,x); x<=y = !less(y,x); x==y = !less(x,y) && !less(y,x) К>для дорогостоящих сравнений (например, строк) это может здорово аукнуться.
К>То, что в STL в роли базиса был взят предикат — это, возможно, упущение авторов. Хотели добиться минимализма (типа — встроенный оператор уже есть, а компаратор потребует нового имени, да ещё и заморочек с ADL). И устроили головную боль пользователям. Хотя в этом есть некое изящество: если операторы < и > определены и согласованы, то смена направления сортировки достигается заменой less<T> на greater<T> (определённые через операторы).
Наблюдение верное. И даже в некоторой мере очевидное. Но тут есть еще 2 фактора:
1) как-никак, компаратор редко удается изящно написать. В этой ветке приводилось достаточно примеров того, насколько неизящен унутре этот самый компаратор.
2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай). Соответственно, получится либо "частично определенный" компаратор (который возвращает либо 0 либо не 0), что опять же может запутать юзера; либо два оператора — компаратор и равенство (как собственно и сделано в D, имеющем opEqual и opCmp), что уже несколько дискредитирует всю задумку.
Здравствуйте, Кодт, Вы писали:
ЗХ>>К слову, эта идея (избавления от "ненужных операторов") не распространена на операторы вида op= (+=, -= и т.д.). Почему? То есть, конечно, логику в этом, видимо, можно найти... Но лень.
К>Логика такая, что не все домены имеют обратные операции. К>Если мы реализуем группу — тогда да, на каждый плюс найдётся свой минус. Но какой декремент может быть, например, для строк? str+=tail, но не str-=tail.
К>Кстати, хохму придумал. Почему бы не трактовать для строк a-b как b+a, и соответственно a-=b как a=a-b=b+a, то есть прибавление к началу строки?
Я не то имел в виду, когда говорил об избавлении от ненужных операторов. Слияние не operator+ и operator-, а operator+ и operator+=
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[16]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, VladD2, Вы писали:
VD>Про управление памятью я уже говорил. Отсуствие ЖЦ — это конечно недостаток, но управление памятью в Дельфи отнимало не бьльше чем при пронраммировании на С++. Умные указатели и т.п. — это все костыли.
Умный указатель, это "заместитель" по GoF. Все паттерны по сути — костыли, они же трюки и приемчики.
Управление памятью в Дельфи отнимает не больше чем в С++ только в GUI. И там и там оно вообще ничего не отнимает ибо много чего берет на себя библиотека и явно их вызывать почти никогда не нужно. Если же речь шла об активном динамическом создании/удалении объектов, то в дельфи — это приличный объем кода на ровном месте (писал когда-то на Дельфи иерарахические структуры описаний графических примитивов — то еще удовольствие ).
Re[17]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Cyberax, Вы писали:
C>VB6 использовался (да и сейчас используется) для простых C>GUI-интерфейсов. В бизнес-логике VB6 я чего-то не встречал.
Да не, "там" очччень дохрена на VB/VBA всякого понаписано. Ситуация с бизнес-приложениями в тех же штатах вообще комическая с нашей т.з. Там или откровенные примитивы типа QuickBook, или сразу монстры типа SAP. Весь промежуточный провал — кто во что горазд. У нас в этой нише прочно сидит 1С, это на порядок более качественное решение чем весь тот сброд, что существует у них (по большей части на VB писанный, и сервера приложений в т.ч !!!). Дотнет, кстати, весьма неплохо подходит как раз для заполнения этой ниши, предоставляя единообразный масштабируемый фреймворк для всех уровней.
C>Мне не очень понятна, например, в отношении C++Builder'а.
Это вообще старый и больной вопрос. До сих пор считаю, что ставка на ObjectPascal была ошибочной. Им стоило двигать в визуальном-виндовом направлении свой С++, который был одним из лучших на то время. Расстановка сил на данный момент могла бы быть несколько другой.
Здравствуйте, WolfHound, Вы писали:
WH>Что за дурацкая привычка лепить все в одну строчку?
Это не дурацкая привычка.
Вы
же
не
пишите
по
одному
слову
на
одной
строчке,
а пишите так как удобнее читать.
WH>Итого: лишнии проверки в цикле и два неосуществимых пути. Это не способствует ни пониманию ни производительности.
Не могу с Вами согласиться.
Эффективная реализации процедуры less, может быть, например, такой:
PROCEDURE NodeLess(a, b: Node): BOOLEAN;
BEGIN
RETURN a.key < b.key
END NodeLess;
т.е. внутри нее a и b не проверяются на неравенство NIL.
Отсюда следует, что прежде чем вызвать less(a, b) надо быть точно уверенным, что ни a ни b не равны NIL.
LOOP
IF a = NIL THEN tail.next := b; EXIT END;
IF b = NIL THEN tail.next := a; EXIT END;
IF less(a, b) THEN
tail.next := a; tail := a; a := a.next
ELSE
tail.next := b; tail := b; b := b.next
END
END;
написан правильно, нет ни одной лишней проверки, и нет неосуществляемых путей.
1) less(a, b) вызывается только тогда когда (a # NIL) & (b # NIL) = TRUE
2) Оба пути в IF равновероятны на случайных данных.
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, vdimas, Вы писали:
V>...либо усложнять блок finally, проверяя, что мы успели создать, а что нет...
Вы правы, но наполовину. Дело в том, что проверить перед уничтожением объекта был ли он создан, вообще-то, еще ни кому ни когда не вредило в любом случае, не зависимо от того есть finally или нет его.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Это не дурацкая привычка. СГ>Вы же не пишите по одному слову на одной строчке, а пишите так как удобнее читать.
Не надо путать естественные языки и языки программирования.
СГ>Не могу с Вами согласиться.
А придется. СГ>Эффективная реализации процедуры less, может быть, например, такой:
Это не имеет значения. СГ>Отсюда следует, что прежде чем вызвать less(a, b) надо быть точно уверенным, что ни a ни b не равны NIL.
Условия вызова исходной функции таковы что на вход всегда подаются коректные, отсортированые списки состоящие хотябы из одного элемента.
СГ>Стало быть цикл: СГ>
СГ> LOOP
СГ> IF a = NIL THEN tail.next := b; EXIT END;
СГ> IF b = NIL THEN tail.next := a; EXIT END;
СГ> IF less(a, b) THEN
СГ> tail.next := a; tail := a; a := a.next
СГ> ELSE
СГ> tail.next := b; tail := b; b := b.next
СГ> END
СГ> END;
СГ>
СГ>написан правильно,
Правильно но не эффективно.
Разберем его.
Допустим в начале цикла списки a и b содержат элементы.
Те ни одно из условий
IF a = NIL THEN tail.next := b; EXIT END;
IF b = NIL THEN tail.next := a; EXIT END;
не выполнится.
Далие происходит проверка
IF less(a, b) THEN
Теперь если это условие выполнилось то мы из списка a забираем один элемент при этом мы не модифицируем список b.
Далие переходим на начало списка. Так как мы не меняли список b то условие
IF b = NIL THEN tail.next := a; EXIT END;
гарантировано не выполнится.
Вот вам один неосуществимый путь и одна лишняя проверка.
Тоже самое касается другого списка. СГ>нет ни одной лишней проверки, и нет неосуществляемых путей.
Почемуто в моей реализацие на одну проверку в цикле меньше.
СГ>1) less(a, b) вызывается только тогда когда (a # NIL) & (b # NIL) = TRUE СГ>2) Оба пути в IF равновероятны на случайных данных.
В этом цикле не два, а 6 путей из которых 2 невозможны.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Кодт, Вы писали:
ЗХ>>2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).
К>Как это?! Если есть порядок, то автоматически есть и равенство.
Это насчет "иногда и наоборот"?
Ну, я могу представить такую ситуацию, когда сортировка объектов возможна (существует отношение порядка), а равенство возможно только в смысле равенства самому себе (identity).
Например, куча non-copiable объектов, которые все существуют в программе в единственном экземпляре; а пользователь оперирует оными объектами через указатели/ссылки. Для проверки равенства самому себе достаточно сравнения указателей; другого равенства заведомо не может быть.
К>Задумку дискредитирует то, что К>- в С++ операторы между собой не связаны К>- а в D, где связь есть, не пошли до конца (скажем, могли потребовать: если определён opCmp, то opEqual определяется автоматически и не подлежит перекрытию)
факт.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>>>2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).
К>>Как это?! Если есть порядок, то автоматически есть и равенство. ЗХ>Это насчет "иногда и наоборот"? ЗХ>Ну, я могу представить такую ситуацию, когда сортировка объектов возможна (существует отношение порядка), а равенство возможно только в смысле равенства самому себе (identity). ЗХ>Например, куча non-copiable объектов, которые все существуют в программе в единственном экземпляре; а пользователь оперирует оными объектами через указатели/ссылки. Для проверки равенства самому себе достаточно сравнения указателей; другого равенства заведомо не может быть.
Ну и кто мешает в предикате/компараторе делать такую быструю проверку?
bool less(const A& a, const A& b)
{
if(&a == &b) return false;
return deep_less(a,b);
}
int compare(const A& a, const A& b)
{
if(&a == &b) return 0;
return deep_less_or_greater(a,b); // компаратор, от которого не ожидают нуля
}
Здравствуйте, Кодт, Вы писали:
ЗХ>>>>2) иногда (часто?) между объектами типа определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).
К>>>Как это?! Если есть порядок, то автоматически есть и равенство. ЗХ>>Это насчет "иногда и наоборот"? ЗХ>>Ну, я могу представить такую ситуацию, когда сортировка объектов возможна (существует отношение порядка), а равенство возможно только в смысле равенства самому себе (identity). ЗХ>>Например, куча non-copiable объектов, которые все существуют в программе в единственном экземпляре; а пользователь оперирует оными объектами через указатели/ссылки. Для проверки равенства самому себе достаточно сравнения указателей; другого равенства заведомо не может быть.
К>Ну и кто мешает в предикате/компараторе делать такую быструю проверку?
может быть, логика... типа, если они логически не могут быть равны, то и возможности сравнить на равенство — не надо.
Впрочем, это я уже загнул. Спешу напомнить, что мной было сказано:
...определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
FAQ — це мiй ай-кью!
Re[14]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Здравствуйте, vdimas, Вы писали:
V>>...либо усложнять блок finally, проверяя, что мы успели создать, а что нет...
СГ>Вы правы, но наполовину. Дело в том, что проверить перед уничтожением объекта был ли он создан, вообще-то, еще ни кому ни когда не вредило в любом случае, не зависимо от того есть finally или нет его.
Подобная проверка зачастую невозможна без нарушений инкапсуляции проверяемого объекта либо усложнения его интерфейса именно для целей проверки. Учитывая всеобщую лень и стремление к минимизации кода, наиболее вероятным представляется первый вариант. Последствия нарушения инкапсуляции могут быть самыми разнообразными, вплоть до катастрофических в "больших" проектах, где функциональность разделена на уровни, а сами программисты — на заказчиков и потребителей функциональности.
Re[3]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, VladD2, Вы писали:
M>>*мрачно* Только за это я готов на D перейти. А то как раз ситуевина, млин. Извращаюсь через енумы...
VD>По-моему, кроме С++ все кому не лень позволяют делать свитчи по строкам.
VD>К тому же эмулируется это дело очень просто. Строишь хэш-таблицу ключем которой является строка, а значением функция-обработчик...
"Все кому не лень" делают это по одной простой причине — в языках имеется тип "строка". В C++ такого типа не существует. Следовательно, switch/case по строке невозможен по причине отсутствия самой строки.
C# AFAIK тоже не позволяет писать switch/case по объектам произвольного типа. А как было бы прельстиво:
class Key
{
Key(int i, string s);
. . .
bool operator < (const Key&) ...
};
. . .
switch(Key(i, s))
{
case Key(1, "123"):
case Key(1, "124"):
. . .
}
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, eao197, Вы писали:
E>>Зря он так предполагает E>>Например, при логировании __FILE__ и __LINE__ здорово помогают. Как и макросы, кстати.
AVK>Еще один важный кусок задач — кодогенераторы.
Да, я тоже хотел об этом сказать. Но поскольку в исходном сообщении ЗХ не было упомянута директива #line, то решил об этом не говорить. К тому же, при желании, кодогенераторы могут сами подсчитывать номера строк в генерируемом коде Хоть это и геморройно.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
К>>Ну и кто мешает в предикате/компараторе делать такую быструю проверку?
ЗХ> может быть, логика... типа, если они логически не могут быть равны, то и возможности сравнить на равенство — не надо. ЗХ>Впрочем, это я уже загнул. Спешу напомнить, что мной было сказано: ЗХ>
ЗХ>...определено только отношение равенства, но не порядка. (иногда и наоборот, но это уже клинический случай).
Действительно, клинический. Порядок сильнее равенства, а равенство сильнее идентичности. То есть, объект сам себе (идентичность истинна) должен быть равен при любом раскладе.
Здравствуйте, c-smile, Вы писали:
ЗХ>>>Проблема решена еще в С++ — обычными константами и инлайновыми функциями (заметим в скобках, что ключевого слова inline в D нет — подстановка функций остается полностью на совести компилятора).
MS>>Вот это плохо. Хотелось бы все-таки неких средств гарантированной оптимизации. То есть, что-то типа MS __forceinline, только еще жестче — функция может быть только inline, она не может иметь собственного адреса, не может быть рекурсивной и т.д. Она может быть только inline. Ну, разумеется, с некими ограничениями по уровню вложенности в случае неявной рекурсии. То есть, если компилятор видит, что "разворачивание" переходит всякие границы (типа 16 или сколько-то там уровней вложенности), то выдает ошибку и не пытается ничего сам решить. Ох, как я не люблю, когда какой-то компилятор вместо меня принимает некое "фундаментальное" решение.
CS>mixin есть для таких случаев — гарантированная вставка фрагмента CS>кода, деклараций и/или классов.
Во! Факт, мною не учтенный.
Кстати, возможно, это более логичный подход: у inline-овых функций есть некая странноватая смысловая нагрузка "выглядит как функция, но на самом деле это просто кусок кода". "Странность" заключается в том, что нет никакой возможности воспользоваться бенефитами реальной подстановки: получить доступ к контексту выполнения. В этом смысле идея миксина как "макроса, только правильного" — возможно, вполне имеет правов на жизнь.
ЗЫ: Пошел спать. Проснусь — распишу-таки преподробно про D-шные templates и mixins. Давно пора было.
Здравствуйте, Зверёк Харьковский, Вы писали:
CS>>mixin есть для таких случаев — гарантированная вставка фрагмента CS>>кода, деклараций и/или классов.
ЗХ>Во! Факт, мною не учтенный. ЗХ>Кстати, возможно, это более логичный подход: у inline-овых функций есть некая странноватая смысловая нагрузка "выглядит как функция, но на самом деле это просто кусок кода". "Странность" заключается в том, что нет никакой возможности воспользоваться бенефитами реальной подстановки: получить доступ к контексту выполнения. В этом смысле идея миксина как "макроса, только правильного" — возможно, вполне имеет правов на жизнь.
Но с другой стороны inline функции более закрыты (вход параметры выход тоже один) а необдуманое использование миксинга может дать малопонятные побочные эффекты, то есть в миксинге сохраняются не только достоинства но и не достатки макросов.
Здравствуйте, FR, Вы писали:
CS>>>mixin есть для таких случаев — гарантированная вставка фрагмента CS>>>кода, деклараций и/или классов.
ЗХ>>Во! Факт, мною не учтенный. ЗХ>>Кстати, возможно, это более логичный подход: у inline-овых функций есть некая странноватая смысловая нагрузка "выглядит как функция, но на самом деле это просто кусок кода". "Странность" заключается в том, что нет никакой возможности воспользоваться бенефитами реальной подстановки: получить доступ к контексту выполнения. В этом смысле идея миксина как "макроса, только правильного" — возможно, вполне имеет правов на жизнь.
FR>Но с другой стороны inline функции более закрыты (вход параметры выход тоже один) а необдуманое использование миксинга может дать малопонятные побочные эффекты, то есть в миксинге сохраняются не только достоинства но и не достатки макросов.
Не готов обсуждать этот вопрос. Пока я только читаю спеку и пишу небольшие тестовые программки. Прелесть/гадость миксинов еще не осознал.
FR wrote:
> Есть вопрос, я правильно понял что GC в D основан на сишном Boehm GC?
Не только "основан", а так и есть — натуральный Boehm GC. Причем сам D
не особо приспособлен для точного сборщика мусора — в последний раз,
когда я смотрел его спеку (примерно год назад), в D была поддержка
C-подобных union'ов и еще нескольких подобных фич. Ну и еще нет
стандарта на ABI для GC, и т.п.
#include <stddef>
struct Foo { int x; int y; };
off = offsetof(Foo, y);
The D Way
An offset is just another property:
struct Foo { int x; int y; }
off = Foo.y.offset;
А как тут быть, если `y` — класс имеющий член `offset` ?
Кё> #include <stddef>
Кё> struct Foo { int x; int y; };
Кё> off = offsetof(Foo, y);
Кё>The D Way
Кё>An offset is just another property:
Кё> struct Foo { int x; int y; }
Кё> off = Foo.y.offsetof;
Кё>
Кё>А как тут быть, если `y` — класс имеющий член `offsetof` ?
Компилятор скажет нечто типа
".alignof property cannot be redefined"
Что ИМХО лучше чем если ты в C++ переопредилишь offsetof()
и компилятор молча это скушает.
alignof offsetof sizeof это predefined
property names — фактически ключевые слова.
CS>Компилятор скажет нечто типа CS>".alignof property cannot be redefined"
CS>Что ИМХО лучше чем если ты в C++ переопредилишь offsetof() CS>и компилятор молча это скушает. CS>alignof offsetof sizeof это predefined CS>property names — фактически ключевые слова.
Понятно, хотя я бы предпочёл имена _offsetof, _alignof, _sizeof, _max, _min. Зачем воровать у программиста слова
А вот еще вопрос по foreach (компилятор качается):
Зачем переменной нужен тип, это оставляет старую проблему "нужен typeof":
foreach (int x; my_integers) ;
Для читабельности это плюс, но не в случае, если контейнер определён строкой выше
Переменная цикла — ссылка на элемент контейнера, или скопированное оттуда значение?
Re[4]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
MS>"Все кому не лень" делают это по одной простой причине — в языках имеется тип "строка". В C++ такого типа не существует. Следовательно, switch/case по строке невозможен по причине отсутствия самой строки.
switch почти аналогичен if;else if;else if;else. Что мешает в С++ задействовать оператор == и выполнять switch для объектов произвольного типа? Заодно и не только константы можно будет использовать в case-метках. А нет оператора, так выдавать ту же ошибку, что и в оперторе if().
[c]
string s;
switch (s)
{
case this->stringSample: break;
case "a": break;
default: break;
}
Здравствуйте, c-smile, Вы писали:
CS>alignof offsetof sizeof это predefined property names — фактически ключевые слова.
Неправильный подход.
Нужно ввести одно ключевое слово meta и далие с ним можно таварить тАкое...
Например заменить им все эти predefined property names
off = Foo.y.offsetof;
на
off = meta(Foo.y).offsetof;
Если туда добавить поле type то получаем typeof
meta(x+y*z).type t = x+y*z;
Если добавить поддержку коллекций времени компиляции то можно будет делать автоматическую сериализацию както так
[serializeble]
struct Foo
{
int x;
int y;
[non_serializeble]
int tmp;
}
template<class T>
void serialize(T const& val, stream& st)
{
static assert(meta(T).attributes.contains(meta(serializeble)));
foreach(meta field in meta(T).fields)
if(!field.attributes.contains(meta(non_serializeble)))
st.serialize(field.const_ref(val), field.name);
}
Ну и так далие.
И отделались всего одним ключевым словом.
Если в D будет нечто подобное то он будет представлять некоторый интерес. Иначе
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
CS>>alignof offsetof sizeof это predefined property names — фактически ключевые слова. WH>Неправильный подход. WH>Нужно ввести одно ключевое слово meta и далие с ним можно таварить тАкое... WH>Например заменить им все эти predefined property names WH>off = Foo.y.offsetof; WH>на WH>off = meta(Foo.y).offsetof; WH>Если туда добавить поле type то получаем typeof WH>meta(x+y*z).type t = x+y*z;
А зачем? Почему не ввести специальный тип "Foo.x":
Здравствуйте, Кодёнок, Вы писали:
Кё>А зачем? Почему не ввести специальный тип "Foo.x":
хъ Кё>Что-то вроде указателя на член класса, но в compile-time.
Ты предлагаешь частный случай моего решения.
Зачем делать частный случай если можно сделать общий?
Болие того общий случай требует меньше зарезервированных слов в языке.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[17]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, vdim
V>Умный указатель, это "заместитель" по GoF. Все паттерны по сути — костыли, они же трюки и приемчики.
+1
V>Управление памятью в Дельфи отнимает не больше чем в С++ только в GUI.
В дельфи есть компонентная модель и дизайнеры которые позволяют размещать компоненты визуально и контролируют их срок жизни. А обертки можо делать нра IUnknown. В общем, если подходить с умом, то жить можно. Но ЖЦ конечно рулит. Тут ни плюся ни делифи и рядом не стояли.
... << RSDN@Home 1.1.4 beta 7 rev. 457>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Кстати, да. Первое моё движение, когда я узнал про свич по строкам в Ди — "а по произвольным классам?" ЗХ>Узнав, что нельзя, "гестапа очень ругалась". ЗХ>Вопрос: почему нельзя? Что этому мешает? У кого-нибудь есть логичный ответ?
Думаю, косность мышления. Строки действительно используются в качестве ключей очень часто. К тому же Шапр интерпртирует их как строеннй тип (хотя это и не совсем так). Принципиальных ограничений нет.
... << RSDN@Home 1.1.4 beta 7 rev. 457>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
V>Со всякими scope-контоллерами подобные алгоритмы не представляют трудностей, записываются "как под диктовку". В случае try-finally мы должны либо городить новый уровень вложенности на каждый №, либо усложнять блок finally, проверяя, что мы успели создать, а что нет. Получаем скорее деструктуризацию, чем структуризацию.
Вот бы глянуть на подобный реальный код. А то реально деструкторы в 99% случаев память особождают...
... << RSDN@Home 1.1.4 beta 7 rev. 457>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Кё>А вот еще вопрос по foreach (компилятор качается):
Кё>Зачем переменной нужен тип, это оставляет старую проблему "нужен typeof":
Кё>
Кё>foreach (int x; my_integers) ;
Кё>
Кё>Для читабельности это плюс, но не в случае, если контейнер определён строкой выше
Кё>Переменная цикла — ссылка на элемент контейнера, или скопированное оттуда значение?
foreach (int x; my_integers) sum += x;
foreach (inout int x; my_integers) x = 12;
Зачем тип? для всякого разного кастинга.
Re[7]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, Шахтер, Вы писали:
Ш>switch -- это и есть вычислимый goto. Только он мощнее. Поскольку метки могут быть непрерывным интервалом значений, в этом случае компилятор сгенерирует таблицу jam ов, или в случае, когда нет неперерывности -- двоичное дерево сравнений.
Ты прав. Я тут сам запутался в своем словоблудстве. А хотел сказать нечто другое. Конструкция switch ничего не гарантирует. А хочется именно гарантированной оптимизации. И эту проблему как раз решает вычисляемый goto. Если у нас целый тип и диапазон значений непрерывен, используем как есть. Если же у нас строки или что другое, делаем бинарный поиск в явном виде и опять же отсылаем по вычисленной метке. Разница лишь в том, что switch гарантирует лишь O(N), а здесь мы сами принимаем решение — O(1), O(log N) или O(N).
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[9]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
Здравствуйте, Шахтер, Вы писали:
Ш>Гарантированной оптимизации язык дать не может. Он может дать только возможность оптимизации. Остальное зависит от качества компилятора.
Именно! В том-то и беда консткукции switch/case. Кмпилятор хоть что-то должен гарантировать. Это непростой вопрос, на самом деле. Комплятор типа C++ или Java или C# должен обеспечить сложность конструкции, не более зедекларированной. То есть, например, цикл for(i=0; i<N; i++) не может превышать O(N). Ну, при условии, что i и N — базовые типы, конечно же. В любом случае, такой цикл не может быть ни O(N^2), ни O(N log N). Другое дело, что в некоторых частных случаях, компилятор имеет право сгенерировать код, сложностью O(1), например, когда N — константа. Часто он так и поступает. Но гарантии нет. То же самое со switch. Компилятор в этом случае обязан гарантировать O(N), то есть, простой линейный поиск. Он имеет право сделать таблицу с бинарным поиском, имеет право сделать таблицу прямых переходов, если это возможно. Но нет ни малейшей гарантии того, что это будет сделано. И если мне нужна именно гарантия бинарного поиска по строкам, я не использую switch хоть в том же C#. Я использую именно бинарный поиск в явном виде и динамический полиморфизм. А если бы был вычисляемый goto, можно было бы поступить гораздо проще.
Предвижу возражения. Типа надо взять и посмотреть MSIL. Но с другой стороны, на все возможные компиляторы это не распространяется! Допустим, MS C# сгенерирует как надо. А Mono сгенерирует? А какой-нибудь левый компилятор имени Сидора Колобкова сгенерирует? Вот то-то и оно.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[7]: ЧАСТЬ 4: синтаксический сахар, синтаксический мусор..
MS>>Согласен с твоими выводами (нижеудалеными), но возражаю по поводу наличия в C++ типа "строка". Нет такого типа в языке. Т>Как же так, строки есть, а типа нету?
А что является строкой в C++?
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, FR, Вы писали:
FR>Можно ли в D сделать инициализацию переменных в шаблонах по умолчанию, например как перевести вот этот плюсовый код:
FR>
FR>template <typename T>
FR>struct Test
FR>{
FR> void fill(T* begin, int n, T t = T())
FR> {
FR> }
FR>};
FR>
FR>на D:
FR>
FR>struct Test(T)
FR>{
FR> void fill(T* begin, int n, T t = ???????)
FR> {
FR> }
FR>}
FR>
Начну с того что в D такой template (fill) просто не нужен, достатчно
написать по месту например так:
int* p = ...;
p[0..n] = somevalue;
Что в общем-то будет нагляднее.
Вариант наиболее близкий к тому что тебе надо можно найти в
имплементации Dictionary в Harmonia:
class Dictionary(KEY, VALUE)
{
private:
uint[KEY] map;
VALUE elements[];
public:
// get symbol of element, if it does not exist
// it will be created using ctor call
symbol opIndex(KEY key, VALUE function(KEY k) ctor)
{
symbol sym = map[key];
if( sym == 0 ) // it is not in dictionary yet
{
sym = cast(symbol)(elements.length + 1);
elements.length = sym;
elements[sym - 1] = ctor(key);
map[ key ] = sym;
}
return sym;
}
// get symbol of element, if it does not exist
// it will be silently created with default (init)
// value of the VALUE type
symbol opIndex(KEY key)
{
return map[key];
}
}
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, FR, Вы писали:
CS>Начну с того что в D такой template (fill) просто не нужен, достатчно CS>написать по месту например так:
fill у меня чисто для примера.
CS>Вариант наиболее близкий к тому что тебе надо можно найти в CS>имплементации Dictionary в Harmonia:
Угу но на C++ это гораздо красивей. Вообще есть очущение что шаблоны в D не доделаны.
Я правда нашел что у встроенных типов есть свойство .init которое можно использовать для инициализации по умолчанию, но я не понял что будет для классов у которых .init не реализован? Как я понял UB.
Здравствуйте, L.C.R., Вы писали: LCR>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками.
Реализация умных указателей(классов) для Delphi занимает в крайнем случае не
более 50 строк.
Re[10]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, vlad_gri, Вы писали:
LCR>>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками. _>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк.
Не верю. Код в студию.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, vlad_gri, Вы писали:
LCR>>>А вот обратная сторона медали: в Delphi невозможны умные указатели (и вообще, умные классы). Отсюда — насущная необходимость в finally, и обязательная уборка руками. _>>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк. WH>Не верю. Код в студию.
Наследоваться от TInterfacedObject
С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[12]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, GlebZ, Вы писали:
WH>>Не верю. Код в студию. GZ>Наследоваться от TInterfacedObject
А теперь сделай слабые ссылки. Или попробуй взять тип из чужой библиотеки который не отнаследован от TInterfacedObject...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>А теперь сделай слабые ссылки. Или попробуй взять тип из чужой библиотеки который не отнаследован от TInterfacedObject...
Дяденька, я не сварщик, я каску на стройке нашел.
Мне тоже подобные идеи не нравятся, но они есть.
С уважением, Gleb.
... << RSDN@Home 1.1.4 beta 4 rev. 358>>
Re[11]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, vlad_gri, Вы писали:
_>>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк. WH>Не верю. Код в студию.
Здравствуйте, vlad_gri, Вы писали:
_>>>Реализация умных указателей(классов) для Delphi занимает в крайнем случае не более 50 строк. WH>>Не верю. Код в студию. _>http://rsdn.ru/File/41945/AutoObjects.rar
Что случиться если этот код
procedure TForm1.Test_Auto_MemoryClick(Sender: TObject);
var
P : PChar;
begin
P := Auto_MemoryAlloc(32768).Ptr;
StrCopy(P, 'Hello there');
Caption := P;
end;
переписать так
procedure TForm1.Test_Auto_MemoryClick(Sender: TObject);
var
P : PChar;
i : Integer;
begin
for i := 0 to 1000000000 do
begin
P := Auto_MemoryAlloc(32768).Ptr;
StrCopy(P, 'Hello there');
Caption := P;
end;
end;
К томуже отсутствие типизации, накладные расходы...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Что случиться если этот код WH>переписать так WH>
WH>procedure TForm1.Test_Auto_MemoryClick(Sender: TObject);
WH>var
WH> P : PChar;
WH> i : Integer;
WH>begin
WH> for i := 0 to 1000000000 do
WH> begin
WH> P := Auto_MemoryAlloc(32768).Ptr;
WH> StrCopy(P, 'Hello there');
WH> Caption := P;
WH> end;
WH>end;
WH>
Закончится память, если ее недостаточно.
WH>К томуже отсутствие типизации, накладные расходы...
Отсутствие типизации присутствует
Какие накладные расходы
Re[14]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, vlad_gri, Вы писали:
_>Закончится память, если ее недостаточно.
Те всетки это ерунда, а не смартпоинтеры. Ибо в С++ в такой ситуации память не закончится(если ее конечно будет больше чем 32768).
А если там будет не память, а фаил или соеденение с БД или... то мы приедем гораздо раньше.
WH>>К томуже отсутствие типизации, накладные расходы... _>Отсутствие типизации присутствует
Вот именно что присутствует.
procedure TForm1.Test_Auto_ObjectClick(Sender: TObject);
var
SL:TFileStream;
begin
SL := Auto_MemoryAlloc(32768).Ptr;
Memo1.Lines.LoadFromStream(SL);
end;
К томуже если придется передать объект в другую функцию то придется передавать IAuto_Ptr _>Какие накладные расходы
На создание временного объекта в хипе, на вызов виртуальных методов, на сохранение IAuto_Ptr черт знает где.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[15]: ЧАСТЬ 3: Конструкторы, деструкторы, и RAII
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, vlad_gri, Вы писали:
_>>Закончится память, если ее недостаточно.
Это я поторопился ответить.
На самом деле все происходит так-же как и в C++ т.е. в каждом цикле память освобождается.
WH>Те всетки это ерунда, а не смартпоинтеры. Ибо в С++ в такой ситуации память не закончится(если ее конечно будет больше чем 32768). WH>А если там будет не память, а фаил или соеденение с БД или... то мы приедем гораздо раньше.
WH>>>К томуже отсутствие типизации, накладные расходы... _>>Отсутствие типизации присутствует WH>Вот именно что присутствует.
WH>
В одной старой книжке по Turbo Pascal есть такие строки.
Стандартный тип-указатель Pointer дает указатель, не связанный ни с каким конкретным базовым типом.
Этот тип совместим с любым другим типом-указателем....
и еще
.... ответственность за правильность использования того или иного параметра возлагается на
программиста.
WH>К томуже если придется передать объект в другую функцию то придется передавать IAuto_Ptr
Как раз этого делать вовсе не обязательно.
procedure TForm1.Test_Auto_ObjectClick(Sender: TObject);
var
SL:TFileStream;
begin
SL := Auto_Object(TFileStream.Create('AutoObjects.pas',fmOpenRead)).Ptr;
// Передаем обьект SL в процедуру
Memo1.Lines.LoadFromStream(SL);
end;
_>>Какие накладные расходы WH>На создание временного объекта в хипе, на вызов виртуальных методов, на сохранение IAuto_Ptr черт знает где.
Каждый новый обьект занимает в хипе всего 16 байт.
Виртуальные методы вызываются только при создании и уничтожение IAuto_Ptr,
этим вполне можно пренебреч.
Что такое
черт знает где
лично я понятия не имею.
К стати реализация auto_ptr в C++ дает похожие накладные расходы.