суббота, 31 октября 2009 г.

[comp.prog.thoughts] Мои крамольные мысли о будущем языков программирования

Нижеследующий поток сознания навеян просмотром темы “Язык будущего. Какой он?” на сайте RSDN. Я не согласен с тем, что будущее языков программирование лежит где-то в области хардкорного функционального программирования с зависимыми типами (там дали ссылку на почти 50-страничный документ Dependent Types At Work, в котором нет (на первый взгляд) ни одной практически-значимой задачи, типичный академизм). Так же далекое будущее не связано с освоением multi/manycores платформ – по сути, это уже идет сейчас. Так что же требуется от языка программирования будущего?

Начну, согласно литературным канонам, издалека. С апреля месяца я работал над серией проектов (не очень связанных между собой), практически в авральном режиме. Требовалось делать все очень быстро, поскольку сроки были буквально “вчера”. И мне приходилось постоянно сообщать свои прогнозы руководству. Естественно, первые прогнозы никогда не оправдывались. В лучшем случае я ошибался в 1.5-2 раза. Т.е. заявлял срок в один месяц или в 10 дней, на практике же получалось два месяца или 15 дней.

Поскольку мне еще не приходилось так часто ошибаться в своих прогнозах (да еще за такое короткое время), то я попытался проанализировать, чем же такие ошибки были вызваны. Мне кажется (именно кажется, это не подтверждено никакими статистическими экспериментами), что основных причин две:

  • невозможность представить себе всю задачу в деталях и
  • необходимость записывать собственные мысли в программный код даже для самых мелких деталей задачи.

Продемонстрирую это на примере. Стоит задача написать приложение, которое будет подключаться к POP3-серверу, забирать письма, фильтровать уже обработанные, выдергивать из необработанных писем нужную информацию и отсылать ее дальше. Предварительный прогноз (после того, как была написана тестовая программка для проверки возможностей класса POP3ClientSession из библиотеки POCO) – три-четыре дня. Но ушло почти шесть дней. Поскольку первые мысли были приблизительно такие: большой цикл, в начале открытие POP3-сессии, получение списка писем, последовательный перебор писем, выделение или генерация для каждого письма Message-ID, проверка уникальности Message-ID по БД, выделение нужной информации из письма, передача получателю, фиксация Message-ID в БД, удаление письма с POP3-сервера, периодическая чистка БД, а если долго не было нормальных POP3-сессий или ответов от получателя, то завершение работы.

В принципе, ничего сложного. Вот, скажем, последний пункт: если долго не было нормальных POP3-сессий или ответов от получателя, то завершение работы. Казалось бы, что в этом сложного. Делается за 15-минут, ну за полчаса. Но во что все это реально выливается на практике?

Во-первых, ограничение времени отсутствия нормальной работы должно конфигурироваться. Значит, в структуру cfg_t вносится еще одно поле, m_max_time_without_successful_receive. С комментариями, с объяснением назначения этого поля и определением его значения по умолчанию.

Далее, это значение должно задаваться в конфигурационном файле. Значит, нужно расширить разбор конфигурационного файла получением этого значения и контролем за его корректностью.

Далее, если разбор конфигурационного файла контролируется unit-тестами (а по хорошему должен контролироваться), то следует прописать в unit-тестах несколько test case для проверки обработки этого значения.

Далее, в классе агента-читателя почты нужно завести метку времени последнего успешного чтения почты, в виде атрибута m_last_receive_timestamp. С комментариями, с объяснением назначения этого атрибута.

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

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

Далее, нужно решить, как именно будет логироваться факт завершения работы программы из-за превышения времени. Сообщение лога должно быть специальным образом описано и задокументированно.

Далее, пользователь с помощью удаленного мониторинга должен видеть, какой результат был у последней операции чтения почты. А так же сколько времени прошло с момента последнего успешного чтения почты (тут еще нужно выяснить, может быть пользователя больше интересует сколько времени еще осталось до принудительного завершения работы, а может пользователь хочет видеть и то, и другое?). В соответствующие структуры добавляются специальные мониторы m_last_pop3_session_result и m_time_from_last_receive. С комментариями.

Далее, в код агента добавляется обновление мониторов m_last_pop3_session_result и m_time_from_last_receive.

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

Вот теперь все. На практике эта работа у меня заняла что-то около 2.5-3 часов рабочего времени. 3 часа рабочего времени – это практически половина рабочего дня (даже больше, если брать в расчет разные производственные и непроизводственные разговоры с коллегами). Т.е. за полдня удается сделать одну не очень значительную детальку не очень сложной программки. А таких деталек… И ведь никогда не известно их точное количество – всегда по ходу разработки на свет божий выбираются такие невероятные детали, о которых изначально даже не задумывались. А время идет.

Какое отношение все это имеет к будущим языкам программирования? Прямое :)

Программист делает двойную работу. Первая часть его работы – составление детального плана реализации какой-то возможности. Что-то вроде приведенного выше перечня абзацев, начинавшихся со слова “Далее”. Это очень трудоемкая работа, поскольку здесь идет прокручивание в голове разработчика какой-то мысленной модели решаемой задачи. По возможности полной модели. С учетом различных тонкостей и нюансов.

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

В результате, перевод плана в исходный код не проще, а наверное, намного сложнее, чем составление исходного плана. И сложнее как раз потому, что есть очень большой разрыв между изложением мыслей в виде естественного текста и между их записью в виде программы.

Так вот мне кажется, что языки будущего должны максимально близко подбираться к выразительности естественного языка, но при этом допускать только однозначное толкование написанного. В идеале, разработчик описывает что-то вроде простого текста, а из этого текста генерируется работающая программа.

Произойдет ли это когда-нибудь? Я не знаю, да и не уверен в этом.

PS. Все вышесказанное является моим субъективным имхом. Причем сегодняшним. Завтра все может поменяться и я буду думать по другому :)

PPS. Мое скептическое отношение к функциональщине (и зависимым типам как к одному из ее проявлений) основывается на том, что в функциональном подходе разрыв между планом действий и программой еще больше. Ведь в процессе кодирования разработчику нужно не только думать о коде, но нужно еще и формулировать правила доказательства корректности этого кода. И после этого все равно нужно проводить функциональные тесты.

пятница, 30 октября 2009 г.

[comp.prog.flame] Неожиданные следы MPS от JetBrains в новой системе YouTrack от той же JetBrains

Вышел новый продукт от JetBrains – баг-трекинг под названием YouTrack. Но интересно не это. Интересно то, что в разработке YouTrack использовалась Meta Programming System (MPS) от того же JetBrains (прямая ссылка на сам инструмент MPS). Об этой системе в RSDN Magazine когда-то публиковали статью “Языково-ориентированное программирование: следующая парадигма”. А потом эту тему долго обсасывали RSDN-овские монстры функционального программирования (например, в лице Сергея Зефирова aka thesz) – мол, ламеры эту штуку делают, мол не хотят на “правильные” инструменты посмотреть, мол ерунду какую-то строят. Да только сильно все это сейчас смахивает на “собака лает, караван идет”. Посмотрит не шибко подкованный в комбинаторных парсерах народ на то, как DSL-и можно не выходя из IDEA на той же самой Java делать… И завалят всех своими, пускай не кошерными, но работающими и использующимися в реальных проектах DSL-ями.

Таки есть computer science, а есть software development. И это две большие разницы. А нельзя применить только то, чего нет. Вот MPS есть, и будут ее применять. (Прошу прощения за резкость, это во мне природа патологического велосипедостроителя взыграла).

[comp.prog.cpp] SCARY assignments: очередной акроним для C++

Прочитал статью Б.Страуструпа и Co Minimizing Dependencies within Generic Classes for Faster and Smaller Programs. Статья большая. В лучших традициях – с введением, подробным описанием, примерами программ, статистическими выкладками и графиками. И, как мне показалось, написанная обычным для Страуструпа стилем – после первого прочтения не понятно, что к чему. А через несколько прочтений не только все понятно, но и удивительно, почему так хорошо написанный текст не воспринимался в первый раз.

Итак, SCARY assignments. Что это за зверь? Оставляю общую формулировку так, как она приведена в стать, ибо переводить эту штуку на русский не возьмусь:

The acronym SCARY describes assignments and initializations that are Seemingly erroneous (appearing Constraibed by conflicting generic parameters), but Actually work with Right implementation (unconstrained bY the conflict due to minimized dependencies).

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

Предположим, что у нас есть некоторый set<int, C1, A1> и похожий на него set<int, C2, A2>. Различаются они только типами компараторов и аллокаторов. Поскольку итераторы для этих типов так же зависят от шаблонных параметров, то, по первому предположению, эти итераторы будут не совместимы между собой по типам:

set< int, C1, A1 >::iterator a;
set< int, C2, A2 >::iterator b;
a = b; // Разве это легально?

Вот такое присваивание a = b и является SCARY assignment. На первый взгляд, оно нелегально, поскольку итераторы принадлежат разным типам. Но, оказывается, причин для препятствования такому присваиванию, с технической точки зрения, не много. Ведь итераторы нужны только для обхода дерева. В процессе обхода дерево не модифицируется, поэтому ни компараторы, ни аллокаторы в этом процессе не задействованы. Следовательно, можно пропробовать “отвязать” тип итератора от шаблонных параметров C и A. Например, так:

template< class T >
class non_const_tree_iterator
  { ... };
template< class T, class Comparator, class Allocator >
class set
  {
  public :
    typedef non_const_tree_iterator< T > iterator;
    ...
  };

Или так:

template< class T >
class basic_search_tree
  {
  public :
    class iterator
      { ... };
  };
template< class T, class Comparator, class Allocator >
class set : public basic_search_tree< T >
  { ... };

В этом случае оказывается, что итераторы для разных set<T> будут совместимы между собой даже если эти set<T> будут использовать разные параметры C и A.

Что же это дает? Уменьшение кода, получаемого в результате инстанциирования шаблонов и ускорение его работы. В статье приводится пример простой реализации ассоциативного контейнера, который позволяет хранить информацию, упорядоченную по нескольким ключам (что-то вроде boost.multi_index). Замеры производительности показывают, что реализованные в стиле SCARY итераторы работают от 1.2 до 2.1 быстрее “обычных” STL итераторов.

Для исследования того, насколько можно уменьшить объем результирующего объектного кода, авторы статьи использовали технику template hoisting. Ее суть в том, что если у нас есть set<T, C, A>, то часть методов этого класса вообще не будут зависеть от шаблонных параметров (например, метод size()). Часть методов будут зависеть только от T, часть от T и C, часть от T и A, а часть от всех трех. Поэтому класс set можно выразить через несколько классов путем наследования.

Так, авторы статьи модифицировали класс Rb_tree из GCC STL для проверки своей идеи, и получили:

  • базовые классы Rb_base<T> и Rb_alloc<T, A>;
  • класс Rb_cmp<T, C>, производный от Rb_base<T>;
  • класс Rb_tree<T, C, A>, производный от Rb_cmp<T, C> и Rb_alloc<T, A>.

Такое разбиение приводит к тому, что для множества различных std<int> в приложении будет всего одна реализация Rb_base<int>. Для множества std<int, less_than> в приложении будет всего одна реализация Rb_cmp<int, less_than> и т.д. Что может приводить к очень существенному (до 25-кратного в некоторых тестах) сокращению объектного кода.

В заключении статьи авторы говорят о том, что подобные техники могут оказаться полезными не только для C++, но и для других языков программирования, поддерживающих обобщенное программирование. Например, для C# и D.

PS. Мне в статье понравилось еще вот что. Говоря про SCARY и соответствующие итераторы авторы приводят пример их использования в реальном приложении. Это приложение является имитатором диспетчера задач для суперкомпьтеров (типа IBM BlueGene). Для имитации используются логи загрузки задач с реальных суперкомпьютеров. Т.е., как начинал Страуструп использовать C++ для имитационного моделирования, так и продолжает делать это до сих пор.

четверг, 29 октября 2009 г.

[comp.prog.flame] Прикольный прогноз про будущее программирования

Высказал один из отцов-основателей RSDN, VladD2:

Ближайшая задача — освоение кучи ядер. У меня на компьютере их уже 4. На горизонте 6 и 8. Лет через 5 будет, скорее всего 16. Писать параллельный код на С++ или Яве с использованием мьютексов и нетерлоков — это маразм.

С учетом недавнего анонса 100-ядерного процессора, рискну предположить, что через пять лет 16-ти ядерные машины будут считаться старьем (коим сейчас считается Pentium M, на котором я начал работать как раз пять лет назад).

И, что самое важное, через пять лет люди все равно будут продолжать писать параллельный код на C++ и Java. И даже с использованием все тех же мутексов. Потому что a) за пять лет революции в софтостроении не происходят (уж слишком маленький срок) и b) никуда legacy-код не денется, не перепишет его никто.

[comp.prog.d] Еще один фрагмент книги А.Александреску “The D Programming Language”

Chapter 4: Arrays, Associative Arrays, and Strings

PS. Ранее Александреску уже выкладывал в свободный доступ одну из глав.

[comp] DROID от Motorola – еще одна штуковина под Android

Motorola выпускает очередной телефон под Android: DROID. Распространяться будет за $200 с двухгодичным контрактом американским оператором Verizon Wireless.

Меня, как бывшего Palm-овода такие новости всегда цепляют.  В свое время мне казалось, что Tungsten T3 от Palm-а с разрешением 320x480 – это прорыв. Может так оно и было, тем более, что вскоре после этого MS задавила Palm своими Pocket-ами, для которых долгое время штатным разрешением являлось 240x320. Однако теперь, при наличии Nokia N900 (с разрешением 800x480), HTC Touch HD (800x480), Sony XPERIA X1 (800x480) и вот этого DROID-а (854x480) это кажется уже смешным.

Себе я такую штуку бы не купил. Все таки телефон должен быть телефоном. Чтобы можно было номер набирать даже грязными, мокрыми руками :)

И еще мне интересно, вся эта маркетинговая шумиха вокруг Android, Windows Mobile, Symbian OS, Maemo – она действительно что-то значит? Как по мне, так большинству простых пользователей совершенно фиолетово, что крутится в их смартфоне. Лишь бы не глючило и не тормозило.

[comp.prog.flame] Все таки я против автоматического вывода типов

В современных языках программирования стало модно использовать автоматический вывод типов (type inference). Веяние сие даже до C++ добралось – в C++0x ключевое слово auto при декларации переменной будет означать автоматический вывод типа:

auto result = std::shared_ptr< MyType >( new MyType() );

Очень неоднозначно я к этой штуке отношусь. Был у  меня опыт изучения чужих исходников на D и Scala, где эти фичи использовались в полный рос – мрак. Документации приходится перелопачивать гораздо больше, чем в случае с аннотациями типов. Особенно в случаях, когда переменной присваивается неизвестно что:

auto writer = getDevice().getConduit();

Что за Device возвращается, что потом за Conduit оказывается во writer-е – без поллитры не разберешься.

А вот свежий пример: потребовалось мне в старом исходнике обнаружить места использования некоторой структуры. Нет проблем – контекстным поиском по файлу все эти места обнаруживаются на раз. В простом FAR-овском просмоторщике файлов. А если бы я использовал вывод типов? Да застрелиться бы можно было бы, если бы под рукой не было мощной IDE, в которой должна была бы быть возможность найти все использования конкретного типа.

Так что, наверное, где-то вывод типов хорош (скажем, чтобы принять результат boost::bind или анонимный тип в LINQ). Но чем меньше, тем лучше. Имхо, конечно.

среда, 28 октября 2009 г.

[comp.prog] Amazon RDS: реляционная БД для облака

Если кто-то ходил по ссылкам в моих заметках про ООБД и CouchDB, тот мог увидеть, что и сторонники ООБД, и приверженец CouchDB в качестве большого недостатка реляционных СУБД указывали, что РСУБД якобы плохо приспособлены к использованию в облачных вычислениях (could computing).

И вот, в пику этим утверждениям, Amazon запускает реляционную БД для использования в своем Amazon Web Services: Amazon Relational Database Service (Amazon RDS). В качестве БД там, насколько я понимаю, крутится MySQL.

Disclaimer: мне лично глубоко фиолетовы и облачные вычисления, и используемые в них СУБД. Но вот такие маркетинговые войны выглядят забавно.

[comp.prog.flame] Практически реклама CouchDB

В RSS-ленте проскочила новость о блог-посте под названием “Massive CouchDB Brain Dump”, который представляет из себя что-то вроде сборника фактов (предположений) о базе данных CouchDB.

Это не реляционная, и не объектная БД. Ее называют документо-ориентированной. Хотя обозвать сопоставление одному ключу серии пар имя-значение документом… Что тогда говорить об объектных СУБД? Они, наверное, мега-документо-ориентированные :)

С внешним миром общается черед HTTP, результаты выдает в виде JSON. При этом утверждается, что она очень быстрая. (Опять же у меня некоторое непонимание: HTTP и быстрое разве могут употребляться вместе? Но, видимо, здесь имеется в виду, что CouchDB не тратит время на join-ы, которые вынуждена выполнять РСУБД).

Используется lock-free design. Типа читатели не ждут писателей и других читателей. Неужели там есть версионность данных?

Утверждается, что CouchDB очень и очень здорово масштабируется. Типа, на ранних тестах было показано, что БД может обслуживать 20000 конкурентных подключений. И такой легкий выпад в сторону C++: мол, по словам главного разработчика, на традиционной многопоточной модели в C++ вряд ли удалось справиться с 500. Тут чувствуется какой-то маркетинговый bullshit. 20K параллельных соединений на одной машине выдержать можно, AFAIK, только при использовании очень эффективных I/O демультиплексоров (см. The C10K problem). И ни о какой модели “одно соединение – одна нить” здесь не может идти речи в принципе, а создать в C++ приложении 20K агентов, которые будут дергаться демультиплексором – как нефиг делать.

Говорится, что CouchDB сейчас набирает популярность, внимание к ней растет. Есть куча интерфесов к ней из разных языков программирования (собственно, что в этом странного – общение-то тупо через HTTP идет и результат в JSON приходит).

В общем, хороший образчик рекламы программного продукта (на мой взгляд). Нужно будет принять на вооружение ;)

[comp.prog.thoughts] В очередной раз захотелось иммутабельности и сборщика мусора

(практически в продолжение предыдущей заметки)

С некоторых пор использование new в многопоточных C++ программах вызывает у меня некоторый озноб. Как только пишешь вызов new или делаешь копирование объектов, за которыми прячутся new, так сразу в мозгу щелкает: “здесь будет синхронизация между потоками”. В большинстве случаев на это забивашь, руководствуясь тем, что сначала нужно сделать корректную программу, а уже потом превратить ее в быструю. Но иногда приходится сожалеть о том, что в C++ чего-то не хватает. Вот как в этом случае.

Итак, есть некоторый софт, который берет на входе некоторый пакет данных, проводит его через цепочку обработчиков, каждый из которых генерирует какой-то новый пакет и т.д. – эдакий data-flow получается. На некоторых стадиях пакет может пойти по сразу нескольким обработчикам параллельно. Это важно.

Сам пакет можно условно представить в виде C++ структуры с большим количеством полей типа std::string:

struct data_package_t
  {
    std::string m_field_01;
    std::string m_field_02;
    ...
    std::string m_field_NN;
  };

Из-за того, что пакет может одновременно обрабатываться несколькими обработчиками, каждый обработчик получает ссылку на пакет в виде константного shared_ptr-а:

void some_handler_t::handle_package(
  const shared_ptr< data_package_t > package )
  {
    ... // Соотвественно, внутри обработчика есть только
        // константная ссылка на data_package_t.
  }

Так вот, иногда в handle_package нужно заменить значения одного или двух полей. Из-за того, что исходный пакет доступен как константа, то для замены значения одного поля приходится делать копию всего пакета. Например, вот как часто бывает:

void some_handler_t::handle_package(
  const shared_ptr< data_package_t > package )
  {
    mutable_copy_on_demand_t< data_package_t > obj( *package );
    if( need_for_new_fields_value(...) )
      {
        obj.changeable().m_field_01 = new_value_01();
        obj.changeable().m_field_02 = new_value_02();
      }

    process_package( obj.immutable() );
  }

Т.е., чтобы заменить одно-два поля, приходится копировать весь пакет. А значит, будут скопированы все поля в нем. Что не есть хорошо.

Вероятно, для C++ найдется несколько способов, которые будут способны снизить накладные расходы в этом случае. Но их нужно придумывать. Тогда как при наличии сборки мусора эта ситуация разрешилась бы автоматически. Допустим, есть некоторый язык типа D2, у которого все сложные объекты ссылочные. И есть какая-то хорошая форма иммутабельности (константности). Тогда можно сделать так:

struct data_package_t
  {
    // Это все ссылки.
    immutable string m_field_01;
    immutable string m_field_02;
    ...
    immutable string m_field_NN;

    // Поверхностное копирование.
    data_package_t
    shallow_copy() immutable
      {
        data_package_t result = new data_package_t();
        result.m_field_01 = m_field_01;
        result.m_field_02 = m_field_02;
        ...
        result.m_field_NN = m_field_NN;

        return result;
      }
  };
...
void some_handler_t::handle_package(
  immutable data_package_t package )
  {
    shallow_copy_on_demand_t< data_package_t > obj( package );
    if( need_for_new_fields_value(...) )
      {
        obj.changeable().m_field_01 = new_value_01();
        obj.changeable().m_field_02 = new_value_02();
      }

    process_package( obj.readonly() );
  }

В таком случае вместо копирования всех полей были бы просто продублированы ссылки для N полей + накладные расходы на создание нового экземпляра пакета.

Сборка мусора сейчас есть практически во всех мейнстримовых (или около того) языках. А вот иммутабельности данных – практически нет. В D2 есть, в OCaml (если не ошибаюсь) тоже. В C++ нет ни того, ни другого – абыдно, да.

вторник, 27 октября 2009 г.

[comp.prog.cpp] Очередной маленький C++ велосипедик: mutable_copy_on_demand

Сделал недавно простой шаблонный класс для упрощения решения маленькой задачи: есть константный объект, нужно выполнить над ним несколько шагов обработки, на каждом шаге возможна модификация части объекта. После всех шагов объект должен быть отослан другому агенту. Получалось что-то вроде:

void process_object( const some_object_t & original )
  {
    // Делаем копию, которая может модифицироваться.
    some_object_t copy( original );
    // На последующую обработку уходит уже копия объекта.
    do_first_step_then_others( copy );
  }

void do_first_step_then_other( some_object_t & obj )
  {
    // Обработка заключается в замене одного из полей,
    // если его текущее значение не удовлетворяет
    // некоторым условиям.
    if( need_change_field_1( obj ) )
      obj.set_field_1( value_for_field_1() );

    do_second_step_then_others( obj );
  }
...
void do_N_step_then_send( some_object_t & obj )
  {
    if( need_change_field_N( obj ) )
      obj.set_field_N( value_for_field_N() );

    send( obj );
  }

При всей своей простоте это решение мне не нравилось тем, что копия объекта создается всегда. Даже если в 90% случаев объект вообще не модифицировался. А исходный объект был не очень маленьким – с десятком строковых полей + еще несколькими полями со сложной структурой.

Т.е. задача была в том, чтобы создавать копию объекта только при первой модификации. Но, если модификация произошла, чтобы именно копия объекта рассматривалась как актуальное значение. Для этого я написал очень простой класс (его шаблонный вариант приведен здесь). С его использованием преобразование объекта стало выглядеть приблизительно так:

void process_object( const some_object_t & original )
  {
    // Делаем "ленивую" копию, которая может модифицироваться.
    mutable_copy_on_demand_t< some_object_t > copy( original );
    // На последующую обработку уходит уже копия объекта.
    do_first_step_then_others( copy );
  }

void do_first_step_then_others(
  mutable_copy_on_demand_t< some_object_t > & obj )
  {
    // Обработка заключается в замене одного из полей,
    // если его текущее значение не удовлетворяет
    // некоторым условиям.
    if( need_change_field_1( obj.immutable() ) )
      obj.changeable().set_field_1( value_for_field_1() );

    do_second_step_then_others( obj );
  }
...
void do_N_step_then_send(
  mutable_copy_on_demand_t< some_object_t > & obj )
  {
    if( need_change_field_N( obj.immutable() ) )
      obj.changeable().set_field_N( value_for_field_N() );

    send( obj.immutable() );
  }

Объект mutable_copy_on_demand_t хранит ссылку на исходный объект и указатель на копию. Изначально копии нет и метод immutable возвращает ссылку на исходную копию. При первом обращении к методу changeable создается копия, и метод immutable начинает возвращать ссылку на нее.

Вот такой частный случай Copy-On-Write, упрощенный за счет того, что ссылку на исходный объект не нужно контролировать – она в данном сценарии гарантированно остается неизменной.

понедельник, 26 октября 2009 г.

[comp.wow] 100 ядерный процессор от Tilera

Вот новость о том, что Tilera анонсировала 100 ядерный процессор.

Что это за зверь такой и как он может использоваться – я не знаю, не копенгаген. Но сам факт примечателен.

[comp.prog] Объектные базы живут! Вот Versant под .NET продукт выпускает

Компания Versant анонсировала выпуск продукта VOD .NET (Versant Object Database for .NET). Заявляется, что он будет совместим с LINQ и ADO.NET Entity Framework.

Собственно, говоря, .NET-овский продукт меня мало интересует. Гораздо интереснее, что объектные БД продолжают жить и развиваться. Что не может не радовать. Так уж получилось, что на последнем курсе универа мне довелось написать свою ООБД, которая даже некоторое время развивалась и была внедрена в паре проектов, над которыми я работал. В какой-то степени моя ObjESSty – это результат тех трудов.

Вообще, после работы с объектными БД пересаживаться на РСУБД очень тяжело. То, что раньше было просто и естественно, в РСУБД превращается в кучу совершенно левой работы. Особенно в C++, где все нужно делать ручками. Может продвинутые объектно-реляционные отображатели (ORM) в языках типа Java/C#/Python/Ruby серьезно облегчают жизнь разработчикам, не знаю точно. Хотя, по слухам, не так все ладно в Датском королевстве. Особенно, если приходится схему данных БД для производительности вручную подкручивать… Тогда как в ООБД ничего этого не было – есть у тебя граф сложных объектов, нужно их сохранить в БД – просто берешь и сохраняешь, делов-то!

Ну да всего в двух словах не расскажешь. У Versant-а на сайте есть несколько интересных презентаций рекламного характера, можно глянуть, при желании. Вот, например:

An Object Database for Large-Scale Simulations: Better Performance and More Powerful Algorithms

Objects End-to-End The ODBMS Advantage

Конечно, не все было здорово и с ООБД, не панацея это от всех бед. Для ряда задач они категорически не подходят. Например, хранить много простых сырых данных, которые потом используются для различных отчетов, статистических срезов и пр., в ООБД не выгодно. С этим РСУБД лучше справляются. А вот что-нибудь типа векторной графической картинки с дополнительными атрибутами для элементов изображения в ООБД самое место.

В общем, ООБД – хорошая для своих целей штука. И для управляемых языков/сред, наверное, даже лучше, чем для нативных. Не очень известная и популярная, правда. Но ведь живая и здравствующая! ;)

На эту же тему: A New Renaissance for ODBMSs?

Кстати, эта статья (которая представляет из себя интервью с несколькими производителями ООБД) наводит на интересную мысль. В свое время был принят стандарт объектных БД – ODMG-93, который, насколько мне известно, так полностью никем и не был реализован. В данном интервью вопросам стандартизации ООБД так же было уделено внимание. Большинство высказалось в том смысле, что пока стандартизировать нечего и незачем. Уж слишком разные продукты и каждый производитель берет пользователей своим собственным набором уникальных возможностей. Но, при этом, многие отмечают важность поддержки LINQ в своих разработках. Т.е. может получиться так, что LINQ как раз и станет работающим стандартом запросов к ООБД.


Различную информацию на тему ООБД можно найти на специализированном сайте http://www.odbms.org/

воскресенье, 25 октября 2009 г.

[life.cinema] Альтернативный сценарий Moon 2112 :)

После просмотра фильма Moon 2112 осталось двойственное чувство: с одной стороны, фильм весьма не плох – и идея хорошая, и воплощение отличное, и игра Сэма Рокуэлла заслуживает похвалы. Но, с другой стороны, во второй половине фильма возникает стойкое впечатление, что концы с концами не сходятся.

Если кто-то не смотрел еще этот фильм и не хочет портить себе впечатление моими рассуждениями, тот может прерваться на этом месте. Для остальных я продолжу.

Итак, суть в том, что на Луне работает практически автоматическая станция по сбору какого-то там вещества (гелия-3, кажется). За ней присматривает один человек – Сэм. Он заключил контракт на 3 года, вот-вот этот срок истечет и он отправится домой, на Землю, к жене и дочке, которая родилась уже после его отлета на Луну. Но тут случается ЧП – его машина, на которой он добирался до одного из сборщиков гелия-3, попадает в аварию и он сам чуть не погибает.

На станции в себя приходит новый Сэм. Он узнает, что попал в аварию, но сейчас с ним все в порядке. Ему дают время отдохнуть и говорят, что скоро прилетит аварийная команда, которая починит сломавшийся сборщик. Но Сэм чувствует в этом что-то подозрительное и делает так, что его помощник-робот-надсмотрщик, разрешил ему выйти наружу. Там он находит попавшую в аварию машину, а в ней – еще одного Сэма в бессознательном состоянии.

Далее герои объединяются и выясняют, что они оба клоны. Что вся система была простроена так – на станции находится изрядный запас тел клонов. Раз в три года предыдущего клона под предлогом отлета на Землю утилизируют, а нового – оживляют, вкладывают в него воспоминания о Земле, о жене, которая ждет ребенка. Этот новый клон живет себе три года, отправляет видеообращения на Землю (прямой связи с Землей нет из-за какой-то аварии, поэтому общение возможно только через видеопочту), получает ответные сообщения, работает, ожидает момента окончания контракта… Потом его так же утилизируют, а нового оживляют. И все повторяется снова и снова, уже лет пятнадцать. Но в данном случае в отлаженной схеме произошел сбой – попавший в аварию клон не умер, а был найден новым клоном.

Они придумывают, как им обмануть систему – нужно улететь на Землю в капсуле для гелия-3. Но им:

  • во-первых, нужно оставить какое-то тело в попавшей в аварию машине и
  • во-вторых, оставить какого-то клона вместо себя на станции.

И тут происходит очень удачное стечение обстоятельств. Попавший в аварию клон вдруг начинает стремительно терять здоровье. Его тошнит, у него выпадают зубы, его лихорадит и вообще становится понятно, что он не жилец. Поэтому он вызывается вернуться в аварийную машину, чтобы его там и нашли.

А робот-надсмотрщик ни с того, ни с сего начинает им помогать. То покажет видеозаписи предыдущих жильцов станции, чтобы герои увидели, что происходило с предшественниками (они все к истечению 3-х летнего срока чуть ли не разлагаются на ходу), то по их просьбе инициирует процесс оживления нового клона, то подскажет, что его нужно перезагрузить (иначе аварийная команда найдет в его памяти следы двух одновременно живых клонов).

Именно эти два обстоятельства и “портят всю малину”. Ну не верится мне, что клонов делают как-то так, чтобы они чуть ли не умирали от всех возможных болезней к концу 3-х летнего срока. Тем более, что эта болезнь вдруг начинает так быстро прогрессировать – еще вчера герой был как огурчик, занимался на тренажерах, а сегодня он отхаркивает свои внутренности вместе с зубами. Понятно, для чего этот сюжетный ход нужен – чтобы один из клонов пожертвовал собой и остался умирать на месте аварии. Но выглядит этот ход неправдоподобно.

Во-вторых, с чего бы вдруг робот-надсмотрщик стал таким добрым? Типа человечность искусственного разума? Не верю! :)

Так вот, вторую половину фильма (после того, как новый клон находит выжившего в аварии) я бы построил по другому:

Притаскивает “новый” Сэм спасенного “старого” Сэма на станцию и относит в медпункт. Но вместо того, чтобы помочь привести пострадавшего в чувство, робот-надсмотрщик вдруг вырубается и начинает перезагружаться. На это уходит какое-то время, после чего он опять видит двух живых Сэм-ов и опять вырубается. Когда перезагрузка завершается, робот видит всего одного Сэма в отсеке управления. Некоторое время они общаются, потом из медпункта выходит пришедший в себя “старый” Сэм. И робот опять вырубается.

В общем, наши герои понимают, что они очень смахивают на клонов, но не понимают, что именно здесь происходит. Потом они соображают, что робот вырубается не просто так, а именно тогда, когда видит их двоих. Значит, двое живых Сэмов – это нештатная ситуация, не заложенная в программу робота.

Они пытаются как-то реанимировать робота, но тот продолжает постоянные перезагрузки, как только обнаруживает двоих клонов сразу. Тут выясняется, что непосредственно перед перезагрузкой на одном из компьютеров появляется надпись: “Сбой системы, для перехода в ручной режим нажмите клавишу ‘M’, до автоматической перезагрузки осталось 5 секунд”. Потом начинается обратный отсчет и по истечении 5 секунд робот перезагружается. При очередном сбое они успевают нажать ‘M’ и получают управление над роботом и всей станцией.

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

Способ простой – одному из них следует забраться в капсулу для гелия-3 и улететь на Землю. Но кому? И что делать второму? В идеале, второму нужно вернуться в потерпевшую аварию машину и умереть там. Чтобы на станции начался процесс оживления нового клона и аварийная команда после прибытия ничего не заподозрила.

Легко сказать, но кому же хочется умирать? Они пытаются решить это силой, накинувшись друг на друга с кулаками. Но, изрядно набив друг другу морду, они понимают, что никто из них не может убить другого.

Поэтому остается один выбор – жребий. Который выпадает “старому” Сэму. Ему предстоит вернуться на место аварии и отключить кислород в своем скафандре. А отвезти его туда должен “новый” Сэм.

Так они и делают. Уезжают вдвоем. Потом сдержано, по-мужски, прощаются. “Старый” Сэм говорит “новому” что-нибудь такое, в меру слезоточивое. Типа “живи и за меня тоже” или “когда увидишь мою дочь – поцелуй ее за меня”. Потом “старый” Сэм остается, “новый” Сэм возвращается на станцию. “Старый” какое-то время рассматривает фотографию своей жены и дочки. Потом видит, что приближается корабль с аварийной командой и перекрывает себе кислород.

“Новый” Сэм возвращается на станцию, перепрограммирует маршруты движения сборщиков так, чтобы они разрушили антены-глушители, запускает рестарт робота-надсмотрщика, а сам улетает в капсуле для гелия-3.

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


Вот как-то так.

По-моему, так будет суровее и драматичнее.

[life.cinema] Очередной кинообзор

Нашлось время для очередного обзора просмотренных фильмов. Но, начитавшись в последнее время кучи рецензий от доморощенных критиков, пришел к выводу, что в подобных отзывах авторам важнее рассказать о том, что они в штанах со стразами, а не о фильме. Не хочу вставать в этот ряд, поэтому меняю схему обзора.

Когда мы спрашиваем мнение о фильме у знакомого, что нас интересует? Хороший фильм или нет (другими словами: стоит тратить на него свое время или нет). Вот именно так я и буду делать – говорить хорошим ли был фильм на мой взгляд. Ну может еще пару слов о том, что особенно понравилось или не понравилось.


Американский психопат (фильм 2000 года с Кристианом Бэйлом в главной роли). Суровый фильм, отличная игра Бэйла, очень неожиданный финал фильма.

99 франков. Гламурный поток сознания о тяготах жизни и душевных страданиях креативщиков от рекламы. С потугами на обличение бездуховности рекламы вообще. Ерунда, мне не понравился.

Черный ястреб. Вот так нужно снимать патриотические фильмы. При просмотре складывается впечатление, что против американцев воевали ну совсем уж тупые африканцы. И в финале абсолютно нелепая история, как генерал начал оттирать пятна крови с пола полевого госпиталя. И главное – во всем фильме сквозит уверенность: мы хорошие парни, и мы победим не смотря ни на что. Но сцены боев сделаны очень впечатляюще. В России бы сейчас парочку таких фильмов снять…

Петя по дороге в Царствие Небесное. Редкая хрень. О чем фильм, для чего был снят – ничего не понял.

Бойлерная. Хороший фильм. Не знаю, насколько там актуально содержание, но собеседования, которые проводил герой Бена Аффлека – просто классно сделаны. Особенно первое: “Вы заработаете свой первый миллион за три года работы в фирме JTMarlin. И вопрос не в том, заработаете вы его или нет. А в том – сколько раз вы это сделаете. Думаете я шучу? Нет, я не шучу. Я – миллионер!” Внушаить, вот так нужно вправлять молодым мозги.

Каникулы строгого режима. Хороший фильм. Говорят, что для ботающих по фене в этом фильме шуток и смешных моментов будет больше. Но мне и так понравилось.

Король Нью-Йорка (фильм 1990). Хороший фильм. Потрясающая харизма Кристофера Уокена и это еще мягко сказано (имхо, большая часть фильма именно на его таланте и строится). Интересно еще и то, что фильм не выглядит как ретро.

Опасные пассажиры поезда 123. Фигня, по ходу всего фильма преследует одна мысль: не верю. Некоторый сцены просто идиотские. Например, когда подруга по видеочату требует от пацана признания в любви, а он лежит на полу захваченного вагона поезда. Или когда герой Дензела Вашингтона разговаривает с женой по телефону перед тем, как отправиться на передачу денег – жена просит его по пути домой купить полпинты молока.

Простой план (фильм 1998 года). Отличный фильм. И очень неожиданный финал.

Большая игра (фильм 2009 года с Расселом Кроу). Смотреть большую часть было интересно. Но в финале авторы закрутили такую невероятную развязку, что испортили все впечатление о фильме. Так что – ерунда.

38-я параллель (Южная Корея). Отличный и жуткий фильм о войне в Корее. Война снята как, пожалуй, нигде раньше. Что еще поразило – в фильме не было ненависти к северокорейцам. Обе стороны показаны одинаково.

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

Идеальный побег. Нормальный фильм. Очень неожиданный поворот сюжета в середине фильма.

Луна 2112. Хорошая фантастика. Отличная игра главного героя, поскольку на ней все и держится – персонажей в фильме не много. Не “Район #9”, конечно, но уж точно один из лучших фантастических фильмов этого года.