Здравствуйте, Кодёнок, Вы писали:
Кё>По-моему, это называется ACCUMULATE.
Тоже хорошее название. Можно и так. Хотя можно и Fold.
Кё>Что-то вроде функции accumulate(list, start, func) -> S, где collection — последовательность элементов типа E, start — значение типа S, func — функция func(elem, sum) -> S от аргументов elem типа E и уже накопленной "суммы" sum типа S. Обычно S = E
Кё>В языках с лямбдой очень удобно, в остальных же передать блок кода (путь даже простой и короткий) задача непростая, в том же Обероне и действительно проще написать еще один цикл.
+1
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Dyoma, Вы писали:
D>В Smalltalk это надо назвать в два слова, одно означает смысл начального значения, второе — лямбду. Синтаксис такой, аргументы вставляются внутрь имени. Обычно очень удобно когда несколько параметров их смысл виден в месте вызова.
Понимашь ли, вот и "Акумулейт" и объяснение Кодёнока я понимаю без проблем. А вот твое понять немонгу. Мне нужно очень серьезное напряжение мозгов, чтобы вообще понять, что ты объясняешь тоже самое. Боюсь, что это не твое неумение обяснить, а как раз влияние Смолтока. Ну, уж больно через одно место в нем многое сделано.
Кстаит, с ФЯ зачастую тоже самое. В стремлении сделать все как можно компактнее в ФЯ получаются настоящие шифровки. Те же названия методов вроде map() императивного программиста вводят просто в ступор. Это же нужно еще бошку так раком поставить, чтобы думть, что функция намапливает функцию на список. А ведь назови ее как-нибудь ConvertAll() и вопросов даже не возникло бы.
D>Есть несколько вариантов: D>1. Простой. Если надо в обратном порядке и/или не все, но в прямом или обратном порядке то D>(array select: [:e | <условие>]) reversed inject: x into: [...]
Нда. Снова шифрограмма.
D>(array asSortedCollection: [:a :b | <a сравнить с b>]) inject...
Дык Кодёнок и спрашивал можно ли методы вызвать последовательно "фильтр...акумуляция...ххх...". Значит можно.
D>(array inject: OrderedCollection new into: [:reordered :e | <перемешиваем в reordered>]) inject: x into: [...] D>Но это уже пахнет нездоровым извращением
От тут нельзя не согласиться. От этой строчки в глазах рябит .
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Не совсем зря. В c.l.s до сих пор(!) спорят о том, как можно было бы правильно его назвать. Но 30 летнею историю не перепишеш.
А что мешало создать еще один метод который будет иметь имя Fold или Acumulate?
ANS>Но если так хочется понятности, то можно использовать fold:.
То есть он таки есть? Ну, слава богу. Значит, скорее всего, есть и аналогичные в других странных местах?
Тогда просьба к тем, то приводит примеры на Смолтоке: Будьте добры выбирать названия методов понятные тем, кто не знает и не хочет изучать 30-ти летнюю испторию Смолтока.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Dyoma, Вы писали:
D>Ксати есть есть один, всем известный, логический язык "прикладного уровня" — SQL и те кто на нем пытался хоть что-то сделать (речь, конечно, не о тривиальном запросе) очень быстро упираются в необходимость использовать императивные вставки типа PL/SQL, или получив результат запроса доработать его на на другом языке. D>Можно конечно ждать озарений от теоретиков, которые найдут разрешимое исчисление, достаточное в большинстве прикладных задач, но... на сколько мне известно очень давно не было заметных подвижек в этом направлении
Кстати, без особых проблем вычислял на SQL такие вещи как баланс по предприятию без единого гвоздя, тфу ты, без единого импереативного оператора.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
E>Так вот, имхо, Java/C# стали всего лишь дальнейшей эволюцией C++ времен 1990-1992 годов, а то и еще более раннего периода. По крайней мере отсутствие шаблонов в первых версиях Java/C# говорит о том, что следующая важная стадия в развитии C++ была авторами этих языков упущена.
Не, не так. Java/C# не являются клоном С++ вообще. Они являются другими версиями создания ООЯ на базе С. Типа без тех ошибок что были у Страуструпа.
А отсутствие конструкций для обобщенного программирования (шаблонов то ведь нет и не будет в этих языках) скорее объясняется как раз тем, что создатели языка пытались скопировать технику полиморфизма не у С++, а скорее у Смолтока. Но Смолток динамически-типизированный язык, а Java/C# — не. И то что легко прокатывало в нем и ему подобных языках (динамический полиморфизм) оказалось не стольк продуктивным решением для статически типизированных языков. Разработчики этих языков поняли свою ошибку и попытались ее исправить. Но Java/C# являются еще и компонентными языками, так что скомуниздить шаблоны 1 в 1 тоже не удалось. Тогда они пошли по похожим но разным путям. МС сделала обобщенный промежуточный язык, а Сан сделал поддержку обобщенного программирования как легкую обертку над динамическим полиморфизмом.
E> Но вернемся к Java/C#. Эти языки сделали программирование в стиле C++ более простым, логичным и безопасным.
Я бы сказал, что они создали стиль программирования отличный от С++. Это скорее стиль Дельфи. С++ это все же сначало С, потом шаблоны, и уж потом ООП, а можно и безнего. А Java/C# — это сначало ООП, потом обобщенное программирование, а потом все что угодно, но не С.
E> Избавившись в конце-концов от совместимости с языком C удалось сделать более строгий синтаксис, что привело к упрощению синтаксического и семантического анализа кода на Java/C#. А это уже сделало возможным создание современных продвинутых IDE с навороченным рефакторингом.
Думаю, что эти языки специально разрабатывались в рассчете на создание для них продвинутых IDE. Они принципиально компонентные, модульные, динамические и ООП. А отказ произошел не просто от совместимости с С (C# в ансэфе очень близок к С), а от всего что затрудняет реализацию главных концепций. А в С++ таких вещей оказалось куда больше. С как раз был содран в C#-е очень близко. Отказались только от макросов и инклюдов. Даже препроцессор частично остался.
E> А отказ от принципа "ты платишь только за то, что используешь" позволил сохранять в программе массу дополнительной метаинформации.
Это вообще не ясное утверждение. Метоинформация я имел еще в 95-ом году в виде TLB от COM-объектов. И как не странно создавал эти СОМ-объекты я на С++.
Просто в языки привнесли защиту и автоматику, которые привели к некоторым дополнительным затратам ресурсов. Но и возожности аппаратуры возрасли. Мы же не в 95-ом где самый мощьный процессор был Пентиум 2 аж с 200-ами МГц?!
E> Что сделало возможным такие вещи, как рефлекшен.
Чууушь!
E> А использование байт-кода и виртуальной машины в Java позволило применять такие механизмы, как динамическая загрузка кода и интанцирование объектов по имени класса.
Опять берем КОМ и даже Корбу и понимаем, что все эти утверждения высасоны из пальца.
E>Но почему же лично я не считаю, что Java/C# совершили прорыв в смене сознания, как это сделал в свое время C++?
Видимо потому что незнашь этих языков.
E> Да потому, что C++ позволил массе реальных C-программистов применять ООП на практике. Java/C# не сделали этого, потому, что ООП уже не нужно было продвигать в массы.
Дык Java/C# позволили той самой массе применять КОП! Что не менее революционно чем ООП. Опять же КОП был и раньше, но эти системы на рядц с Жлабэйсиком и КОМ-ом именно что привнесли КОП в массы.
E> Все, что они сделали -- это создали новую, более эффективную (хотя это не бесспорно) технологию разработки ОО программ в духе C++.
Ну, и тут тоже самое. ООП сам по себе нафиг не уперся. Главное, что С++ позволил упростить разработку ПО при этом не сильно проиграв в эффективности более низкоуровневым языкам вроде ассемблера и С. Тоже делают и Java/C#.
E> Но дальше они не пошли. Ведь что мы имеем в C++: статическая типизация; иерархия классов; объекты, которые не могут изменить свой тип (класс) в процессе жизни; передача сообщений между объектов в виде синхронного вызова методов. То же самое происходит в Java/C# с некоторыми изменениями/дополнениями (вложенные и анонимные классы в Java или делегаты в C#).
Ну, начать с того, что делегатов то в С++ мы как раз не имеем. Еще в С++ мы как раз не имеем той самой компонентной модели. За то мы имеем в нем целую кучу граблей, неудосбтв и грязи в синтаксисе. От всего этого и избавляют Java/C# .
E> Но здесь нет смены парадигмы.
Да, есть. КОП > ООП.
А C# еще и функциональный стиль привносит.
E> Понятно, что сменились некоторые приемы, где-то используется рефлекшен вместо шаблонов, где-то делегаты вместо указателей на методы.
Да, не вместо. А вместо отуствия.
E> Но это не принципиально. Принципиальными изменениями, например, могли бы стать: E>- асинхронная доставка сообщений;
Да, есть она. Любой делегат можно вызвать асинхронно/
E>- изменение иерархии классов по ходу работы программы;
Классов? А какие тогда они классы? А порождать новые классы и их экземпляры можно. Только это уже фрэймворк, а не язык.
E>- изменение типа (класса) объекта по ходу работы программы;
Глупость это. Или это тип, или его можно изменять по ходу программы.
E>- поддержка одновременно динамической и статической типизации (причем первый шаг к этому в C# уже планируется в виде ключевого слова var (Краткий пересказ
Опять чушь. "var" никого отношения к динамической типизации не имеет. А динамическая типизация в ограниченных масштабах есть и так. Есть такой тип object. С ним можно вытварять очень много. Есть так же рефлексия с помощью которой хочть черта лысого можно динамически вызвать. Но C# — это статически типизированный язык. Если хотити динамики, то их есть у меня. Есть VB.NET с той самой "утиной типизацией", кстати в 9.0 с ней даже по круче будет. Там придумали "утиные интерфесы" — т.е. описываешь интерфейс как "утиный" и приводишь в рантайме к нему любой объект... если у объектоа методы совпадают, то можно вызвать методы через утиный интерфейс. Что это дает? А тот самый комплит ворд и подсказки среды, плюс еще возможность обнаружить ошибку при инициализации ссылки на интерфейс, а не при вызове 101-вого метода. Далее создали динамические переменные. Когда можно намисать та:
a = "SomeMethodName"
...
b.a(x, y)
за синтаксис не ручвюсь, но смысл думаю понятен.
Но это все из другой оперы. Это все для скриптов. А в нормальных ОО-программах типизация должна быть типзацией, а не утиными историями.
E>Возьмем, к примеру, DSL (здесь я согласен с Re: Следующий язык программирования — 2
). Но он не смог стать популярным. Тому есть множество причин. Скажем, для меня способ написания программы в виде S-выражений не удобен (ни для написания, ни для чтения), хотя Лисп-программисты утверждают, что это не проблема.
Дык и Смолтокщики тоже утверждают. Так вот ходят оба вместе с Лиспщиком и утверждают... рядом с толпами С++-ников, C#-щиков и других Дельфистов.
E> Тем не менее, факт остается фактом. Лисп показал себя не пригодным для широкого применения. А это значит, что огромная масса программистов, которые не знают Лиспа, даже не представляют себе, как же может выглядеть из приложение, написанное на нескольких DSL-ях (по своему DSL на каждом уровне абстракции).
Дык, чтобы этого небыло мы и создали этот сайт .
E> А теперь вообрази, что им дают в распоряжение такой язык и показывают, как это просто. Язык, который поддерживает DSL так же легко и естественно, как ОО-языки ООП. Вот лично ты готов сейчас представить свой текущий проект в виде всего лишь нескольких строчек на DSL верхнего уровня? Каждая из которых раскрывается в несколько строчек на DSL еще более низкого уровня, а те, в свою очередь, точно так же. И так до тех пор, пока дело не дойдет до обычного универсального языка программирования?
Здорово. Осталось только придумать как это воплотить в жизнь. Причем не на насквозь тинтерпретируемом и нетипизированном Руби, а на статически типизированном языке общего назначения. По этом поводу один анекдот:
---------------------
На консилиуме ученых и военных...
Входит в кабинет секритарша и гворит:
— Тут к вам рвется какой-то товарищь... я его сдержать немогу, говоит что дело государственной важности...
— Ну, что же впустите.
— Здравствуйте! Я изобретатель! Дайте рассказать про свою идею.
— Ну, что же говорите, раз все равно ворвались.
— Значичь идея такова... Вражеские самалеты подетаютк к нашей границе и вдруг переворачиваются и падают. Здорово?!
— Здорово! И как же это все работеат?!
— Не, ну, вы же ученые? Вам и думать как реализовать. А мое дело идею предложить!!!
Вот та же фигня с твоей идеей.
E>Готов? Лично я не готов.
Я готов. Излагай...
E>Тем не менее, сейчас я сталкиваюсь с подобными вещами, когда программирую на Ruby. Например, моя система управления компиляцией C++ проектов...
Слушаей, если Руби так крут, то закаким чертом ты вообще используешь С++. Ну, реши ты свою задачу на Руби, а уж тонкие места на С++ оттюнишь. А?! Или у Руби тоже есть проблемы? Может тогда о них поговорить?
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
E>>Так вот, имхо, Java/C# стали всего лишь дальнейшей эволюцией C++ времен 1990-1992 годов, а то и еще более раннего периода. По крайней мере отсутствие шаблонов в первых версиях Java/C# говорит о том, что следующая важная стадия в развитии C++ была авторами этих языков упущена.
VD>Не, не так. Java/C# не являются клоном С++ вообще. Они являются другими версиями создания ООЯ на базе С. Типа без тех ошибок что были у Страуструпа.
Влад, ты злой
Я тоже буду злым тогда.
Короче, слушай сюда. Java/C# не являются ни развитием, ни "осознанием ошибок" C++. Они взяли наихудшую парадигму из языка и возвели ее в степень догмы. А именно — идею наследования. Наследование — это самая большая провокация в индустрии. Ни в каком моделировании наследования не существует и в реальной жизни тоже — ни в электронике, ни в бухгалтерии, ни где бы то ни было еще. Есть одно — генеология. Но это не имеет ни малешего отношения к тому, что называется наследованием в программировании. Все эти многоэтажные иерархии классов только усложняют жизнь, вместо того, чтобы упрощать. И служат они одной единственной цели — раздувать и дальше этот мыльный пузырь и продолжать кормить миллиарды индусов. В результате этой идеи возникла дутая индустрия, не обеспеченная никакими реальными активами. А вся мировая практика говорит о том, что рано или поздно этот пузырь лопнет. Ни разу еще не было случая, чтоб не лопнуло. Как лопнули дот-комы — вот этого я и опасаюсь. И тогда все эти гигатонны кода просто станут никому не нужным мусором. Впрочем, они этим мусором и являются, просто время коллапса еще не пришло.
VD>Ну, и тут тоже самое. ООП сам по себе нафиг не уперся. Главное, что С++ позволил упростить разработку ПО при этом не сильно проиграв в эффективности более низкоуровневым языкам вроде ассемблера и С. Тоже делают и Java/C#.
Это твое утверждение можно переформулировать фразой из давнишней песни группы "Ноль":
В школе мне в уши и в рот клизму поставили
Так получил я полезные, нужные знания...
Во-первых, C++ не упростил, а только усложнил разработку ПО. Во-вторых, "не проиграл в эффективности" а выиграл. Проиграли в эффективности программы на C++, построенные на принципах наследования, но никак не сам C++.
Лично я использую C++ как более эффективное средство для оптимизации кода и для построения более компактных, быстрых и надежных программ (по сравнению с Си). И альтернативы не вижу, несмотря на весь этот "ужас-ужас" C++. При этом я фактически не использую наследование, оставаясь, тем не менее, в рамках парадигмы ООП. Вот такой вот парадокс.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, VladD2, Вы писали:
E>> А теперь вообрази, что им дают в распоряжение такой язык и показывают, как это просто. Язык, который поддерживает DSL так же легко и естественно, как ОО-языки ООП. Вот лично ты готов сейчас представить свой текущий проект в виде всего лишь нескольких строчек на DSL верхнего уровня? Каждая из которых раскрывается в несколько строчек на DSL еще более низкого уровня, а те, в свою очередь, точно так же. И так до тех пор, пока дело не дойдет до обычного универсального языка программирования?
VD>Здорово. Осталось только придумать как это воплотить в жизнь. Причем не на насквозь тинтерпретируемом и нетипизированном Руби, а на статически типизированном языке общего назначения.
А вот на счет статически типизируемого -- это уже твоя идея. Я лишь сказал про универсальный язык, который может быть либо интерпритируемым, либо компилируемым в байт-код, в промежуточный код или в нейтив-код. Руби как раз универсальный язык общего назначения. На котором, имхо, DSL можно плодить. Тебе не нравится программировать на интерпритируемом и динамически типизируемом языке -- да ради бога, не программируй. Жди, когда M$ сделает для тебя C# 3.0.
E>>Готов? Лично я не готов.
VD>Я готов. Излагай...
Чего изглагать? Я же написал -- не готов. Пока.
E>>Тем не менее, сейчас я сталкиваюсь с подобными вещами, когда программирую на Ruby. Например, моя система управления компиляцией C++ проектов...
VD>Слушаей, если Руби так крут, то закаким чертом ты вообще используешь С++. Ну, реши ты свою задачу на Руби, а уж тонкие места на С++ оттюнишь. А?! Или у Руби тоже есть проблемы? Может тогда о них поговорить?
1. На C++ у нас создан собственный фреймворк для агентно-ориентированного программирования. С помощью этого фреймфорка написаны все C++ приложения. Их нужно сопровождать и развивать. Поэтому я продолжаю использовать C++.
2. С языком Ruby я познакомился в августе прошлого года. Сделал на Ruby один проект (тот самый mxx_ru). Затем эпизодически использовал Ruby для написания маленьких вспомогательных скриптов. И только в последние два-три месяца стал серьезно расматривать Ruby в качестве дополнения к C++. Отсюда два следствия:
2.1. У меня еще нет достаточного опыта в создании сложных/больших систем на Ruby. А без такого опыта очень стремно использовать Ruby в коммерческих проектах. Вот и набираюсь опыта потихоньку.
2.2. Для Ruby нужно создать средства, которые позволили бы интегрировать Ruby с нашим агентным фреймворком. Этих средств пока нет. Нет потому, что о перспективности интерграции Ruby и C++ я стал задумываться всего пару месяцев назад.
А у Ruby пока есть одна самая важная сложность: динамическая типизация. Из-за нее вести разработку следует не так, как я привык -- нужно существенно увеличивать объем тестирования. А еще, имхо, на Ruby нужно делать компоненты (модули) гораздо мельче, чем на C++, чтобы проще было тестировать.
Но главной проблемой у Ruby является отношение окружающих к подобным языкам, которое ты здесь очень ясно обозначил. Если помнишь, полгода назад мы с тобой в топике Типизация
спорили с _vovin про C++, Smalltalk, строгую, статическую и динамическую типизацию. Тогда я был ортодоксальным сторонником статической типизации. Но тот разговор не прошел даром. После него мое отношение к динамически типизируемым языкам вообще, и Ruby в частности, изменилось на противоположное. Зато теперь мне самому приходится сталкиваться с неприятием динамически типизируемых языков.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Понимашь ли, вот и "Акумулейт" и объяснение Кодёнока я понимаю без проблем. А вот твое понять немонгу. Мне нужно очень серьезное напряжение мозгов, чтобы вообще понять, что ты объясняешь тоже самое. Боюсь, что это не твое неумение обяснить, а как раз влияние Смолтока. Ну, уж больно через одно место в нем многое сделано.
VD>Кстаит, с ФЯ зачастую тоже самое. В стремлении сделать все как можно компактнее в ФЯ получаются настоящие шифровки. Те же названия методов вроде map() императивного программиста вводят просто в ступор. Это же нужно еще бошку так раком поставить, чтобы думть, что функция намапливает функцию на список. А ведь назови ее как-нибудь ConvertAll() и вопросов даже не возникло бы.
Мне тут вспомнилось как лет 10 с фигом назад я въезжал в исходники TurboVision. Структрное программирование на паскале мне было тогда очень понятно. Но когда я видел вызовы методов, которые определены в разных классах и везде поразному!...
У тогда меня тоже было ощущение что как-то все раком. Однако продолжал разбираться, потому как не смотря на "кривость" подхода все у них как-то очень гладко получалось, да очень хотелось пользовать этот TurboVision.
VD>Нда. Снова шифрограмма.
Ну тогда тебе простой вопрос. Как ты думаешь какой будет результат:
Язык типа C:
Здравствуйте, VladD2, Вы писали:
VD>Например, аналогичный метод в дотнете назвали "Fold", то есть "свертывать". "inject" же — это "вводить", "вприскивать", "вставлять" наконец. Как это название ассоциируется с поведением.
Вообще-то метод называется inject:into:
collection inject: initialValue into: block
Читается так "коллекция вставь начальное значение в блок, вычисляющий следующее"
VD>Мне вообще очень часто "радуют" названия методов и других фич в разных эксперементальных языках. Порою похоже, что на обдумывание реализации авторы затратили намного больше сил и времяни чем на придумывание названия.
А теперь премся над C++:
class MyClass {...}
x = new MyClass(); // Я что в этой строке новый класс создаю??? А почему мне все говорят, что объект?
struct MyStruct {...}
y = new MyStruct(); // Вот тут я понял - y присвоить новая структура MyStruct
Ксати я тут, конечно, просто прикалываюсь, но многие начинающие программисты действительно думают, что объектная программа это когда классы посылаю друг-другу сообщения. Вот так...
VD>Думаю, никто не будет спорить, что подобный метод можно реализовать почти на любом языке? Здорово, что он есть штатно. Не здорово, что так назван.
Фишка в том что на C-образных языках такой метод — не естественное (читай ракообразное решение). Как там в C#3.0 — не знаю... тебе виднее, что можно в лямбду запихать. В Smalltalk можно в блок запихать все, в том числе и выход из метода в котором это блок создан:
arg = "exit" ifTrue:[^true].
...
Перевод:
if (arg == "exit") return true;
...
VD>А как же дописать, то если ни if, ни циклов?
if — делается стандартым путем Replace Condition with Polymorphism.
class True : Boolean {
<T> T ifTrue(Block<T> block) {
return block.calculate();
}
}
class False : Boolean {
<T> T ifTrue(Block<T> block) {
return null;
}
}
Это очень вольный перевод со Smalltalk на C.
Циклы. Есть методы в библиотеке реализованне не на Smalltalk (в java это называется native). Например, у Integer есть to:do:
1 to: 5 do: [:i | ... ]
Перевод:
for (int i = 1; i < 5; i++) ...
По сути также в java (и наверняка в C#) в библиотеке есть класс Object, который дает тебе возможность отнаследовать от него (неявно) твои классы.
VD>Нехочу ввзяываться в очередной спор "ФЯ вс. все остальное", но все же, думаю, что если бы для МЛ и массив был бы естестеннен, то и МЛ был бы более естественне, и что самое важно, более используем.
И у нас был бы еще один клон C...
VD>Вот и я о том же. Думается, что если бы его создатели добавили бы еще пару возможностей из ФЯ, и еще нечто вроде миксинов/трэтсов, чтобы заменить множественное наследование, то через некоторое время про ФЯ и С++ можно было бы спокойно забыть. Но до этого явно пока долеко .
Мысль здравая, но очень спорная один раз этот путь прошел язык C когда в него добавили всякие клевые фенечки получился C++, потом выкинули мусор получилось java и C#.
Анекдот:
Фабрика производит простые карандаши, вносятся рац.предложения:
1. Очень коротким карандашом писать неудобно и огрыки всеравно выкидывают, давайте последнии 2 см не будем заполнять грифелем. Утверждено.
2. Последнии 2 см без все равно без грифеля, давайте съекономим дерево и будем делать карандаши на 2 см короче. Утверждено.
3. Чем длинее карандаш, тем польшую его часть удается использовать. Давайте сделаем карандаши на 2 см длинее. Утверждено.
VladD2 wrote:
> C>У меня сейчас в кэше лежит 750Мб файлов (всего 1Гб памяти), поэтому у > C>меня очень быстро работает компиляция и отладка. > А "очень быстро" — это сколько?
Порядка 20 секунд. Большую часть времени занимает связывание.
С++, однако.
> C>Если я запущу какую-нибудь программу, даже на небольшое время сжирающую > C>56Мб, то у меня эти самые 56Мб дискового кэша будут очищены. Значит при > C>следующей компиляции эти файлы снова будут читаться с диска. А я > C>предпочитаю, чтобы у меня все летало. > Может лучше сменить компилятор? Что уж там по 10 мег выигрывать, когда > можно 780 освободить?
А ничего не сделать — используется куча библиотек, и при линковке они
должны подгружаться. Инкрементальное связывание помогает, но не сильно.
Здравствуйте, VladD2, Вы писали:
VD>Это тоже возможно. Берешь продукт вроде R#-а и вперед делать синтаксически дифер. Вот только такой дифер будет иметь проблемы с коментариями и т.п. Но сравнивать из-за этого объекты и темболее отказыватся от хранения кода в текстовых файлах смысла нет.
Тут я никак не могу согласиться. Текстовые файлы как минимальная единица исходного кода — это просто атавизм, который сильно мешает дальнейшему развитию. К примеру, возьмем средства, расширяющие возможности студии — всякие там решарперы, visual assist'ы и together. Если нужно поставить более чем одно из таких средств, то каждое из них хранит свою собственную копию AST кода и следит за ее актуальностью, что выливается в затраты памяти и проблемы с синхронизацией между ними. Например, resharper + together = очень нехилые тормоза при любом рефакторинге.
Плюс к этому, хранение кода на уровне элементов AST намного упростит работу с VCS. К примеру, можно будет получить список изменений, которые проводились только в интересующей тебя функции, а не во всем файле, где она находится.
Здравствуйте, eao197, Вы писали:
E>Алаверды на Ruby: E>
E>a.inject { |s, v| s += v }
E>
Ала еще более верды на C#:
int sum = 0;
foreach(int a in array)
sum += a;
Имхо, читается лучше всех остальных приведенных вариантов.
Java/C: используют индексную переменную, которая нафиг не нужна, т.е. является мусором. Кроме того, содержат совершенно стандартный код управления значением этой переменной, который тоже является мусором. Помимо лишних кнопок на клавиатуре, этот мусор может содержать ценное зерно, которое сразу не будет замечено. Например, вот такой цикл имеет совсем другой смысл:
for (int i = 0; i < array.length && i < maxlen; i++)
sum += array[i];
при беглом сканировании есть риск пропустить доп. условие.
Smalltalk: идея с блоком кода, конечно, замечательна. Однако логика инициализации суммы скрыта. Если не читать документацию на метод inject:into:, то никакой связи между 0 и sum нет.
ML: вот здесь действительно "другое мышление". Вместо наивного представления о том, что сумма вычисляется путем сложения равноправных элементов, применяется вычисление суммы более короткого массива и значения первого элемента. На первый взгляд это одно и то же, но на самом деле есть две важные особенности:
1. Если в С/Java/Smalltalk/Ruby мы декомпозировали массив на набор однородных элементов, то здесь мы делим на голову и хвост. При этом приведенный пример частично специализирует сумму только для пустого массива. Но можно предоставить, к примеру, и реализацию для одного элемента. Не знаю, как там насчет более сложных матчингов, но в любом случае это совсем другой способ декомпозиции.
2. Важен порядок. Вот второй вариант записи той же функции:
fun sum(head::tail) = sum(head) + tail | sum([]) = 0.
Если результат одинаков, то почему запись разная?
Надо отметить, что это совсем не то же самое, что и замена в С/Java:
int sum = 0;
for (int i = array.length-1; i >=0; i--)
sum += array[i];
Потому, что тут уже в действие вступает коммутативность сложения. А в функциональном ML мы играли только на ассоциативности. Для умножения матриц, например, это важно.
Так вот вариант из C# не дает нам управления порядком обхода. И это безусловно хорошо, т.к. не оставляет читателю кода пространства для гаданий о целях такого изменения.
Совсем сократить программу все же нельзя: остаются декларации типов. Это можно поправить, поскольку оператор foreach обладает необходимой информацией о типе IEnumerable, стоящего в его аргументе, а, стало быть, мог бы вывести тип первого аргумента:
foreach(/*int*/ a in/*(IEnumerable<int>)*/array)
sum+=a;
С суммой ситуация хужее. Ее тип, теоретически, тоже можно было бы вывести из типа складываемых аргументов (по крайней мере, агрегатная функция SUM в SQL это делает). Но оставаясь в рамках С# я не вижу способа корректно это сделать. Во-первых, все же требуется задать для нее начальное значение (может быть, мы хотим сложить несколько массивов). А это делается еще до задания цикла, в котором мы получаем необходиму. информацию о типе. Во-вторых, sum употребляется сразу и справа и слева от оператора присваивания: sum = sum + a. То есть для вывода типа надо решить уравнение T = typeOfAddition(T, typeof(a)). С первого же взгляда видно, что это уравнение допускает массу решений: корректным T будет и int, и long, и float, и double, и еще неопределенное количество типов, для которых оператор сложения перегружен подходящим образом.
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, VladD2, Вы писали:
E>>Так вот, имхо, Java/C# стали всего лишь дальнейшей эволюцией C++ времен 1990-1992 годов, а то и еще более раннего периода. По крайней мере отсутствие шаблонов в первых версиях Java/C# говорит о том, что следующая важная стадия в развитии C++ была авторами этих языков упущена.
VD>Не, не так. Java/C# не являются клоном С++ вообще. Они являются другими версиями создания ООЯ на базе С. Типа без тех ошибок что были у Страуструпа.
Интересное мнение. Итак, мы имеем: процедурный (не ОО) язык С, произошедший от него ОО язык С++, ОО языки Java/C# (появившиеся гораздо позже C++). При этом утверждается, что Java и C# напрямую производные от C, а не от C++. Вероятно, ты считаешь это логичным. Я -- нет.
VD>А отсутствие конструкций для обобщенного программирования (шаблонов то ведь нет и не будет в этих языках) скорее объясняется как раз тем, что создатели языка пытались скопировать технику полиморфизма не у С++, а скорее у Смолтока.
Я думаю, что разработчики Java/C# могли бы здесь дать более точную версию.
Имхо, в первой версии Java не было шаблонов потому, что шаблоны только-только появились в C++ и еще не были такой важной частью языка, какой они являются сейчас. Поэтому авторы Java просто не оценили вовремя всего потенциала шаблонов. Ведь очень серьезный толчок массовому использованию шаблонов дала библиотека STL, появившаяся (если не ошибаюсь) где-то в 93-м. Как раз тогда, когда основной дизайн Java уже был оформлен.
E>> Но вернемся к Java/C#. Эти языки сделали программирование в стиле C++ более простым, логичным и безопасным.
VD>Я бы сказал, что они создали стиль программирования отличный от С++. Это скорее стиль Дельфи.
На Дельфи не программировал. Не берусь судить.
VD> С++ это все же сначало С, потом шаблоны, и уж потом ООП, а можно и безнего.
И это говорит человек, который утверждает, что хорошо знал C++! (... и эти люди запрещают мне ковыряться в носу! (анекдот)).
До того, как в C++ появились нормальные шаблоны, в С++ прежде всего было ООП, а затем уже C. Имхо, множество бед C++ происходит из-за того, что его пытаются использовать как "улучшенный C", в лучшем случае, как "С с классами".
Пора бы уже осознать, что C++ -- это другой язык, нежели C. Он просто вырос из C и долгое время поддерживал совместимость с C. Поэтому и программировать на нем нужно, не так, как на C. Тогда и не придется в очередной раз жалиться, какой же он дырявый, сколько в нем проблем, и сколько лично ты шышек набил, ступая по его граблям.
VD> А Java/C# — это сначало ООП, потом обобщенное программирование, а потом все что угодно, но не С.
Обобщенное программирование на Java Это забавно.
Ну тогда расскажи мне, как на Java (либо C#) реализовать такое:
где классы deliver_sm_t и data_sm_t организуют такую иерархию:
pdu_parser_t
/ \
/ \
/ \
deliver_sm_t data_sm_t
(т.е. не имеют общего интерфейса, который бы описывал методы, присутсвующие как в deliver_sm_t, так и в data_sm_t, но отсутствующие в pdu_parser_t).
А функции handle_delivery_receipt и handle_deliver_pdu -- это шаблонные функции:
которые в своем коде вызывают методы deliver_sm_t и data_sm_t (методы с одинаковыми именами и прототипами, присутствующие в обоих классах).
Или может я под обобщенным программированием понимаю что-то другое.
E>> Избавившись в конце-концов от совместимости с языком C удалось сделать более строгий синтаксис, что привело к упрощению синтаксического и семантического анализа кода на Java/C#. А это уже сделало возможным создание современных продвинутых IDE с навороченным рефакторингом.
VD>Думаю, что эти языки специально разрабатывались в рассчете на создание для них продвинутых IDE.
Ага, Грослинг в проекте Green как раз думал про IDEA для Oak.
VD> Они принципиально компонентные, модульные, динамические и ООП. А отказ произошел не просто от совместимости с С (C# в ансэфе очень близок к С), а от всего что затрудняет реализацию главных концепций. А в С++ таких вещей оказалось куда больше. С как раз был содран в C#-е очень близко. Отказались только от макросов и инклюдов. Даже препроцессор частично остался.
Опять-таки, С# многое взял от C, а C++ вообще побоку остался. Ну да ладно, ты C# знаешь, тебе виднее.
E>> А отказ от принципа "ты платишь только за то, что используешь" позволил сохранять в программе массу дополнительной метаинформации.
VD>Это вообще не ясное утверждение. Метоинформация я имел еще в 95-ом году в виде TLB от COM-объектов. И как не странно создавал эти СОМ-объекты я на С++.
И имел эту информацию только для того, что было связано с COM. Если же у тебя была в коде какая-нибудь структурка Point, не имеющая к COM-у никакого отношения, то и метаинформации для нее у тебя не было. А в Java для любого класса/интерфейса сохраняется метаинформация. Нужна она тебе будет, не нужна она тебе будет -- она у тебя все равно будет. Хочешь ты того, или нет.
E>> Что сделало возможным такие вещи, как рефлекшен.
VD>Чууушь!
Попробуй доказать, что рефлекшен возможен без метаинформации.
E>> А использование байт-кода и виртуальной машины в Java позволило применять такие механизмы, как динамическая загрузка кода и интанцирование объектов по имени класса.
VD>Опять берем КОМ и даже Корбу и понимаем, что все эти утверждения высасоны из пальца.
Опять берем КОМ или Корбу, или ручную загрузку DLL с GetProcAddress. И пытаемся создать экземпляр класса RECT по имени "RECT". Или WNDCLASS. Или POINT.
E>>Но почему же лично я не считаю, что Java/C# совершили прорыв в смене сознания, как это сделал в свое время C++?
VD>Видимо потому что незнашь этих языков.
E>> Все, что они сделали -- это создали новую, более эффективную (хотя это не бесспорно) технологию разработки ОО программ в духе C++.
VD>Ну, и тут тоже самое. ООП сам по себе нафиг не уперся. Главное, что С++ позволил упростить разработку ПО при этом не сильно проиграв в эффективности более низкоуровневым языкам вроде ассемблера и С.
Так ведь за счет чего произошло это упрощение? Смотрим в The C++ Programming Language 3rd, приложение B "C++ Code That Is Not C":
– Features primarily for notational convenience:
[1] // comments (§2.3); added to C99
[2] Support for restricted character sets (§C.3.1); partially added to C99
[3] Support for extended character sets (§C.3.3); added to C99
[4] Non-constant initializers for objects in static storage (§9.4.1)
[5] const in constant expressions (§5.4, §C.5)
[6] Declarations as statements (§6.3.1); added to C99
[7] Declarations in for-statement initializers (§6.3.3); added to C99
[8] Declarations in conditions (§6.3.2.1)
[9] Structure names need not be prefixed by struct (§5.7)
– Features primarily for strengthening the type system:
[1] Function argument type checking (§7.1); later added to C (§B.2.2)
[2] Type-safe linkage (§9.2, §9.2.3)
[3] Free store management using new and delete (§6.2.6, §10.4.5, §15.6) [4] const (§5.4, §5.4.1); later added to C
[5] The Boolean type bool (§4.2); partially added to C99
[6] New cast syntax (§6.2.7) – Facilities for user-defined types:
[1] Classes (Chapter 10)
[2] Member functions (§10.2.1) and member classes (§11.12)
[3] Constructors and destructors (§10.2.3, §10.4.1)
[4] Derived classes (Chapter 12, Chapter 15)
[5] virtual functions and abstract classes (§12.2.6, §12.3)
[6] Public/protected/private access control (§10.2.2, §15.3, §C.11)
[7] friends (§11.5)
[8] Pointers to members (§15.5, §C.12)
[9] static members (§10.2.4)
[10] mutable members (§10.2.7.2)
[11] Operator overloading (Chapter 11)
[12] References (§5.5)
– Features primarily for program organization (in addition to classes):
[1] Templates (Chapter 13, §C.13)
[2] Inline functions (§7.1.1); added to C99
[3] Default arguments (§7.5)
[4] Function overloading (§7.4)
[5] Namespaces (§8.2)
[6] Explicit scope qualification (operator::; §4.9.4)
[7] Exception handling (§8.3, Chapter 14)
[8] Run-time Type Identification (§15.4)
Выделенное курсивом является "улучшением" С, жирным -- ООП. Вот и подумай, намного ли проще стало программировать на "улучшеном С", если бы оттуда выбросили выделенные жирным возможности.
E>> Но дальше они не пошли. Ведь что мы имеем в C++: статическая типизация; иерархия классов; объекты, которые не могут изменить свой тип (класс) в процессе жизни; передача сообщений между объектов в виде синхронного вызова методов. То же самое происходит в Java/C# с некоторыми изменениями/дополнениями (вложенные и анонимные классы в Java или делегаты в C#).
VD>Ну, начать с того, что делегатов то в С++ мы как раз не имеем.
Научись читать написанное собеседником.
VD> Еще в С++ мы как раз не имеем той самой компонентной модели. За то мы имеем в нем целую кучу граблей, неудосбтв и грязи в синтаксисе. От всего этого и избавляют Java/C#.
В Java компонентность возможна только для Java и JVM. На C++ подобная компонентность доступна без проблем, если использовать один и тот же компилятор и не пытаться интегрироваться с чужим кодом через COM-подобные извращения. Но он этом я уже говорил: Re[30]: Что толку в Ада если Ариан 5 все равно упал
.
E>> Но здесь нет смены парадигмы.
VD>Да, есть. КОП > ООП.
Интересно.
VD>А C# еще и функциональный стиль привносит.
Так же как и C++ с STL и bind-ами/функторами.
E>> Понятно, что сменились некоторые приемы, где-то используется рефлекшен вместо шаблонов, где-то делегаты вместо указателей на методы.
VD>Да, не вместо. А вместо отуствия.
поднимать не будем.
E>> Но это не принципиально. Принципиальными изменениями, например, могли бы стать: E>>- асинхронная доставка сообщений;
VD>Да, есть она. Любой делегат можно вызвать асинхронно
Делегат и простой вызов метода, который на самом деле выполняется где-то асинхронно, это, имхо, разные вещи. Некоторые методы объекта могут расматриваться не как функции, возвращающие какой-то результат (для которого синхронность в том или ином виде необходима), а как сигналы. Например, start или shutdown. Представь себе, что в языке есть возможность:
class My_Process
{
public :
async start();
async shutdown();
};
My_Process * process = new My_Process();
process->start(); // А где и когда он будет работать, уже не важно.
E>>- изменение иерархии классов по ходу работы программы;
VD>Классов? А какие тогда они классы? А порождать новые классы и их экземпляры можно. Только это уже фрэймворк, а не язык.
Ну вот видишь, мы тут с Dyoma говорили о том, что следующий язык программирования потребует смены мышления. Я привожу один пример такого изменения -- считать, что классы -- это такие же переменные сущности, как и объекты. Поэтому они могут быть модифицированны во время работы программы. А ты в штыки сразу же.
Вот в Ruby, например, все классы являются открытыми. Это означает, что если мы в одном месте напишем:
class SomeClass
...
end # Думаешь, что определение класса SomeClass завершено?
то это не означает, что класс SomeClass окончательно пределен. Отнюдь. Где-нибудь дальше мы можем дополнить это описание:
class SomeClass
...
end
и новое содержимое SomeClass будет добавлено к сделанному ранее определению класса SomeClass. Более того, мы можем сделать так:
Файл test.rb
class Test
def hello
puts "Test#hello"
end
end
REQUIRE_REGEX = /require [\'\"]([^\'\"]+)[\'\"]/
CALL_METHOD_REGEX = /call ([[:alnum:]]+)/
EVAL_REGEX = /eval (.+)/
def exception_guard
begin
yield
rescue StandardError => x
puts x
end
end
t = Test.new
print "=>"
while line = gets.chop
if "quit" == line
break
elsif line =~ REQUIRE_REGEX
exception_guard do
require REQUIRE_REGEX.match( line )[ 1 ]
end
elsif line =~ CALL_METHOD_REGEX
exception_guard do
m = t.method( CALL_METHOD_REGEX.match( line )[ 1 ] )
m.call
end
elsif line =~ EVAL_REGEX
exception_guard do
eval EVAL_REGEX.match( line )[ 1 ]
end
end
print "=>"
end
Файл test_modification.rb
module Sample
def something; puts "Sample#something"; end
end
class Test
alias :old_hello :hello
def hello
puts "updated Test#hello"
old_hello
end
include Sample
end
Вначале вызываем метод hello у объекта t класса Test. Получаем то, что и было сразу реализовано в классе Test.
Затем через eval расширяем класс Test и добавляем метод bye. Вызваем его у уже существующего объекта t. Получаем ожидаемый результат -- вызов нового метода.
Затем через require подгружаем файл, в котором класс Test опять модифицируется. Причем мало того, что мы переопределяем метод hello, так еще и подмешиваем модуль Sample. В результате у давно существовавшего объекта t не только вызывается модифицированный метод hello, но и подмешанный метод something.
А если вспомнить, что подмешанные модули в Ruby становятся непосредственными суперклассами, то получаем модификацию иерархии наследования на этапе выполнения.
E>>- изменение типа (класса) объекта по ходу работы программы;
VD>Глупость это. Или это тип, или его можно изменять по ходу программы.
См. выше.
VD>
VD>a = "SomeMethodName"
VD>...
VD>b.a(x, y)
VD>
VD>за синтаксис не ручвюсь, но смысл думаю понятен. VD>Но это все из другой оперы. Это все для скриптов. А в нормальных ОО-программах типизация должна быть типзацией, а не утиными историями.
). Но он не смог стать популярным. Тому есть множество причин. Скажем, для меня способ написания программы в виде S-выражений не удобен (ни для написания, ни для чтения), хотя Лисп-программисты утверждают, что это не проблема.
VD>Дык и Смолтокщики тоже утверждают. Так вот ходят оба вместе с Лиспщиком и утверждают... рядом с толпами С++-ников, C#-щиков и других Дельфистов.
Имхо, тому виной необычный синтаксис и форма записи выражений в Lisp и Smalltalk. А если приблизить этот синтаксис к более распространенным нотациям (С-шной или Паскалевидной), то ситуация может измениться. Вот в Ruby такое приближение уже сделали.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Sinclair, Вы писали:
S>Smalltalk: идея с блоком кода, конечно, замечательна. Однако логика инициализации суммы скрыта. Если не читать документацию на метод inject:into:, то никакой связи между 0 и sum нет.
inject:into: — очень популярный метод. Для програмера на Smalltalk он так же близок как for для програмера на языка где for имеется.
S>ML: вот здесь действительно "другое мышление".
Речь шла о возможности думать на языке, на котором пишешь, а не переводить свои мысли с русского. Smalltalk как демонстрация императивного мышления, ML — функционального.
S>Вместо наивного представления о том, что сумма вычисляется путем сложения равноправных элементов, применяется вычисление суммы более короткого массива и значения первого элемента. На первый взгляд это одно и то же, но на самом деле есть две важные особенности: S>1. Если в С/Java/Smalltalk/Ruby мы декомпозировали массив на набор однородных элементов, то здесь мы делим на голову и хвост. При этом приведенный пример частично специализирует сумму только для пустого массива. Но можно предоставить, к примеру, и реализацию для одного элемента. Не знаю, как там насчет более сложных матчингов, но в любом случае это совсем другой способ декомпозиции. S>2. Важен порядок. Вот второй вариант записи той же функции: S>
S>Если результат одинаков, то почему запись разная?
Тут ты не совсем правильно понял идею функционального подхода. Список не делится на две части. То что ты написал не пройдет проверку типов. О системе типов в ML могу написать отдельно, ML — строго типизированный язык, но декларация типов не является обязательной (тип вычисляется из кода, если это сделать невозможно — выражение не корректо).
Тип "список" определяется рекурсивно с помощью двух конструкторов (конструкторы выделены жирным):
1. [] — является списком (пустой список).
2. если list — список, а e — того же типа, что и элементы list, то e::list — тоже список.
Соответственно, для того что бы определить фукнцию опреленную на всех списках, надо определить ее на всех конструкторах списков.
sum(head::tail) = <определение1>
Означает, если агрумент был создан с помощью конструктора :: то с ним поступить по определению1.
sum([]) = <определение2>
Это не специализация, а просто определение функции для случая, когда аргумент был создан другим конструктором. С точки зрения ML оба определения абсолютно равноправны. Знак | — разделитель между двумя определениями. Порядок в котором они записаны не важен, абсолютно аналогично порядок определения методов в классе не влияет на функциональность.
Эмуляция этого определения на структурном императивном квазиязыке выгляделабы так:
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Dyoma, Вы писали:
D>>Ксати есть есть один, всем известный, логический язык "прикладного уровня" — SQL и те кто на нем пытался хоть что-то сделать (речь, конечно, не о тривиальном запросе) очень быстро упираются в необходимость использовать императивные вставки типа PL/SQL, или получив результат запроса доработать его на на другом языке. D>>Можно конечно ждать озарений от теоретиков, которые найдут разрешимое исчисление, достаточное в большинстве прикладных задач, но... на сколько мне известно очень давно не было заметных подвижек в этом направлении
VD>Кстати, без особых проблем вычислял на SQL такие вещи как баланс по предприятию без единого гвоздя, тфу ты, без единого импереативного оператора.
Типа поймал на не точной формулировке. Вот точная, но абсолютно бесполезная
Мат. теорема: не существует алгоритма, который за конечное время для любого заданного алгоритма и входных значений даст ответ на вопрос завершается он или виснет. (Формальных определений алгоритма приводить не буду).
Факт: SQL запросы не виснут (хотя могут работать очень долго).
Следствие: существуют алгоритмы нереализуемые на SQL.
Важное замечание: среди них есть те которые не виснут, т.е. полезные. А есть они потому как иначе можно было бы представимость на SQL использовать как контрпример для теоремы, с которой я начал.
Здравствуйте, McSeem2, Вы писали:
MS>Java/C# не являются ни развитием, ни "осознанием ошибок" C++. Они взяли наихудшую парадигму из языка и возвели ее в степень догмы. А именно — идею наследования. Наследование — это самая большая провокация в индустрии. Ни в каком моделировании наследования не существует и в реальной жизни тоже — ни в электронике, ни в бухгалтерии, ни где бы то ни было еще. Есть одно — генеология. Но это не имеет ни малешего отношения к тому, что называется наследованием в программировании. Все эти многоэтажные иерархии классов только усложняют жизнь, вместо того, чтобы упрощать. И служат они одной единственной цели — раздувать и дальше этот мыльный пузырь и продолжать кормить миллиарды индусов. В результате этой идеи возникла дутая индустрия, не обеспеченная никакими реальными активами. А вся мировая практика говорит о том, что рано или поздно этот пузырь лопнет. Ни разу еще не было случая, чтоб не лопнуло. Как лопнули дот-комы — вот этого я и опасаюсь. И тогда все эти гигатонны кода просто станут никому не нужным мусором. Впрочем, они этим мусором и являются, просто время коллапса еще не пришло.
Ага. Согласен.
Наследование — это притянутая за уши парадигма, якобы способствующая созданию продуктов с повторно используемым кодом. Где вы видели повторное использование кода? Только в компонентно-ориентированном программировании, что, согласитесь, к наследованию имеет весьма отдалённое отношение, ибо код чаще АГРЕГИРУЕТСЯ и взаимоувязывается, нежели наследуется.
VD>>Ну, и тут тоже самое. ООП сам по себе нафиг не уперся. Главное, что С++ позволил упростить разработку ПО при этом не сильно проиграв в эффективности более низкоуровневым языкам вроде ассемблера и С. Тоже делают и Java/C#.
Я думаю, Страуструп поддался моде на набирающее обороты ООП (сначала с Си with Class'es и препроцессорами исходников, а затем с натурпродуктом — полным компилируемым C++). Но даже он не принял до конца идею наследования и полиморфизма из-за преднамеренной "оптимизации" на стадии компиляции C++ программы и сознательного отказа от поддержки информации о типах времени выполнения в пользу эффективности. Позднее был введён механизм VMT и RTTI в полном объёме только для того, что это уже было некритично по эффективности — быстродействию и памяти (железо становилось мощным). НО для работы этого нужно специально было указывать что функция (метод) является виртуальной — некий знак, указывающий, что в этом-то месте может быть зарыта собака и не одна, с этого момента забота об эффективности ложится на программиста.
Функции-друзья. Несколько нарушающие инкапсуляцию, я думаю, стали ответом на зашоренный взгляд мира ООП — оказывается, необязательно иметь только вертикальные связи (наследование и жёсткая иерархия), но можно работать и на горизонтали (функции-друзья), сосуществуя в p2p-пространстве. Не это ли некое отражение идеи mixins в C++?
MS>Во-первых, C++ не упростил, а только усложнил разработку ПО. Во-вторых, "не проиграл в эффективности" а выиграл. Проиграли в эффективности программы на C++, построенные на принципах наследования, но никак не сам C++. MS>Лично я использую C++ как более эффективное средство для оптимизации кода и для построения более компактных, быстрых и надежных программ (по сравнению с Си). И альтернативы не вижу, несмотря на весь этот "ужас-ужас" C++. При этом я фактически не использую наследование, оставаясь, тем не менее, в рамках парадигмы ООП. Вот такой вот парадокс.
Это не парадокс, это реалии сегодняшнего дня. Не только в C++, но и в J2ME, где эффективность==скорость, скорость==меньший размер кода. Наследование мало что может дать — скорее отнимет больше.