Thursday, December 28, 2006

Иерархия тру программистов

И как это я проглядел этот замечательный пост в августе... :)


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

Это, конечно, все шуточки, реальная картина вот тут:


Wednesday, December 20, 2006

Replay Debugger

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

ocaml debugger


Причем оно реально работает. Даже в случае когда, например, читаем из файла массив — после stepback/step forward функция чтения прочитывает то же самое значение.

За это я даже готов простить окемлу использование big-endian в самых неожиданных местах и то что там == используется для сравнения physical equality (сравнение указателей, проще говоря, если x == 0.0 и y == 0.0 то (x == y) вернет false).

Путем недолгих поисков в гугле обнаружилось что это также называется красивым словосочетанием omniscient debugging, статья о том как это работает, а также replay debugger для java, позволяющий даже многопоточные приложения отлаживать в обе стороны.

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

Ссылки: UPD: А вот некоторый давно не обновляющийся проект, претендующий на звание реплей дебаггера для C++: Lizard


Tuesday, December 12, 2006

Функциональные языки разрушают мозг

Why learning Haskell/Python makes you a worse programmer
Отлично написано, читаю и просто таки узнаю себя в каждой строчке (ну разве что C++ вместо C#) -- с некоторых пор пишу на C++ и натурально плачу, плачу и пишу..


Thursday, December 07, 2006

Haskell In Action

Написание на хаскеле не миниатюрных экспериментальных примеров, а чего-нить более-менее серьезного и в конкретные сроки оказалось не таким уж простым процессом. Кто бы мог подумать :)

Открытия:

  • typechecker не спасает от семантических ошибок :) Черт, я в глубине души надеялся что если прога компилится, значит она работает правильно..
  • возникновение косяков с размерностью типов в битовых операциях. Мне на интуитивном таком уровне казалось, что это проблема возникает в С из-за автоматических преобразований типов -- ан нет :)
  • mutable массивы в хаскеле, языке без side effects и со строгой типизацией -- это такой космический хайтек.. :)
  • "ленивость" вычислений все еще неиссякаемый источник сюрпризов для меня и в плане производительности, и в плане сообщений которые выводятся с помощью Debug.trace :)
  • unit тесты это просто таки жизненная необходимость в хаскеле, и писать их намного легче и приятнее чем в C++.

to be continued, как говорится..


Tuesday, November 14, 2006

PhysX и NVidia G80

AGEIA со своим хардверным ускорителем физики для игр, имхо, должна щас плакать  горючими слезами: с выходом новой замечательной железки от NVidia (и SDK для вычислений на GPU разных неграфических задач) их шансы успешно торговать своим девайсом, кажется, сократились еще сильнее.

Вообще не очень понятно на что они рассчитывали, и аналогия с графическими ускорителями тут не очень уместна: когда появился 3DFX, продавец мог просто показать клиенту наглядно: смотри, дескать, какие тут гладкие текстурки, а тут в квадратиках..

С PPU ничего показать толком нельзя. Выигрыш небольшой, у юзера есть всегда вариант купить более мощный многоядерный процессор или пару видеокарт. Ageia, похоже, думала что процессоры упрутся-таки в потолок производительности, а производители GPU будут гоняться за количеством треугольников в секунду, а не делать архитектуру видеокарт более обобщенной.

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

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

Характерна кстати перемена взглядов технического директора Epic Games (а Unreal Tournament 2007 -- главный козырь PhysX) Тима нашего Свини, который очень любит делать разные прогнозы :)
Это март 2005 link:
GameSpot: How did you react when you first saw the Ageia PPU? Would you say that the PhysX chip will bring on a new physics revolution in gaming similar to the 3D revolution sparked by 3dfx in the 1990s?

Tim Sweeney: It's very clearly an idea whose time has come. In games, software-based rigid body dynamics physics has been in use for about five years. It also took about five years from the release of the first realistic 3D games (Wolfenstein 3D and Doom) to the first truly great 3D accelerator, the 3dfx Voodoo1. This is about the time that an industry-changing idea takes from first implementation to industrywide change including hardware adoption. Physics and graphics are both areas where dedicated hardware can exploit the problem domain's underlying parallelism to deliver far more performance than a sequential CPU.


А это октябрь 2006 link:
Talk of "adding physics features to GPUs" and so on misses the larger trend, that the past 12 years of dedicated GPU hardware will end abruptly at some point, and thereafter all interesting features -- graphics, physics, sound, AI -- will be software problems exclusively.


Wednesday, October 25, 2006

Тру книжки



Добыл пару килограмм сокровенных знаний, будем вникать... :)


Tuesday, October 17, 2006

Хороший линк

Блог чувака по имени Zhanyong Wan' -- он был разработчиком в Visual Studio .net setup team, сейчас в гугле работает. (Неожиданно оказался еще и разработчиком FRP, для тех кто в теме :) Рекомендую, типа.

Улыбнуло: вот у него здоровый, со вкусом к C++ написанный пост, а-ля Александреску-Саттер "как грамотно получить размер массива в C++". Во, думаю, отличная иллюстрация к тезису о том что C++-разработчик играется с языком вместо того чтоб писать программы.

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

I cannot believe it’s so difficult to get such a simple job (getting the number of array elements) done in C++.
What a broken language it is.

Очень понравилось :)


Monday, October 16, 2006

Динамическая оптимизация.

Узнал, что у замечательной компании Transmeta совсем плохи дела -- они уже от нечего делать подают в суд на Intel за нарушение патентов в линейке процессоров начиная с Pentium Pro. Акции за пять лет упали более чем в 10 раз..

Жалко -- компания очень интересная. Их технологии трансляции на лету команд x86 в систему команд процессора Transmeta Crusoe и динамической оптимизации кода в свое время на меня произвели большое впечатление -- в плане производительности интерпретируемых языков.

До того как я почитал про HP Dynamo, я смеялся над тестами в которых C# рвал C++ и думал что это невозможно в принципе. (TM наняла кучу народа, работавшего над этим проектом). Однако Dynamo впечатлило -- софтверный интерпретатор команд (виртуальная машина) для процессора PA-8000, работающий на этом же самом процессоре -- обгоняет в тестах нативный код сгенеренный мощным компилятором C++.

Вот что называется just-in-time compilng и динамическая оптимизация, которая может ускорять вещи, в принципе недоступные классическому компилятору.

В качестве примера -- оптимизация виртуальных вызовов. Классический пример -- CObject с чисто виртуальной функцией draw и унаследованные от него CPoint и CLine, реализующие эту функцию.

Как известно, в C++ для реализации этого у объекта есть указатель на vtable в которой лежат указатели на виртуальные функции. Соответственно чтоб вызвать draw() имея указатель на CObject, надо залезть в vtable по указателю, взять из vtable адрес функции и сделать переход туда (либо на CPoint::draw либо на CLine::draw).
..что довольно хреново с точки зрения процессора: он заранее не может понять, куда мы собираемся сделать переход, и поэтому не может сделать prefetch в кэш для кода. Но если мы используем JIT(компиляцию на лету, как в C#), то JIT-компилятор способен определить, что в 99% случаев реальный тип объекта один и тот же (допустим CPoint), и адрес функции практически всегда один и тот же(CPoint::draw), он сгенерит следующий код:

если (тип_объекта == CPoint)
    переход на CPoint::draw
иначе
   разруливаем дела с vtable

Соответственно вызовы CPoint::draw будут замечательно соптимизированы, процессор сможет сделать заранее прочитать начало функции из памяти1.

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

Возвращаясь к истории с Transmeta -- у них в процессорах Crusoe подобные вещи использовались для исполнения x86-кода. Оптимизирующий интерпретатор прошит в специальной памяти (типа флэша в биосе, кажется), но реально -- он 100% софтверный. Судя по прессе, к этим вещам также имели непосредственное отношение разработчики "Эльбруса", в котором также широко используются подобные вещи. Зарулить intel по скорости не очень удалось, но зато по потреблению мощности -- чуть ли не в десятки раз, поскольку сам процессор получился намного проще, транзисторов меньше.

1.Реально тут есть еще много тонкостей, связанных с наличием reflection, случаев, когда мы сначала много вызываем CPoint::draw а потом много CLine::draw и пр. Интересная дискуссия на эту тему тут.


Thursday, October 05, 2006

call/cc

Единственный оператор языка программирования, который вполне заслуживает звания "культового" -- это замечательный оператор call/cc, впервые появившийся в диалекте лиспа, scheme в середине 80-х годов. call/cc -- это call with current continuation. То бишь вызов функции (обычно -- лямбда-функции) с параметром, содержащим как бы контекст выполнения программы в точке вызова, который называется словом continuation. Проще показать :) Пример на ruby, где тоже есть call/cc:

def foo
for i = 1..100
    c = nil #сюда мы будем сохранять continuation
    callcc {def |x| c = x} # (**) 
                           # в фигурных скобках -
                           # лямбда-функция 
                           # сохраняет переданный 
                           # ей continuation в 
                           # переменную c
    puts i 
    return c if (i % 3) == 0 # прерываем выполнение 
                             # функции и возвращаем 
                             # continuation каждые 
                             # три итерации
end
end
Это обычная функция, печатающая числа от 1 до 100, но каждые три итерации она возвращает управление тому кто ее вызвал, а потом может продолжать работу с места где ее остановили. т.е. работает это вот так:
> t = foo()
1
2
3
> t.call # вызываем continuation, и выполнение 
         # продолжается с (**)
4
5
6
> t.call # еще разок
7
8
9
Если есть call/cc, то можно легко реализовать выходы из середины циклов, исключения, да и сами циклы. Еще стоит упомянуть про Continuation Passing Style, когда функции в качестве аргумента передается некоторый continuation в который она должна по завершении передать результат. Если функциональные языки вам не очень близки, то call/cc это суть coroutines, то бишь функции, которые возвращают значение много раз по ходу выполнения. А coroutines сейчас есть в большинстве мейнстримных языков: итераторы в C# (см. оператор yield), coroutines в lua и python. (А с точки зрения computer science оператор call/cc тесно связан с такой фундаментальной вещью как рекурсивные функции, точнее, с понятнием fixed point combinator). Линки по теме:


Wednesday, September 27, 2006

Aspect-oriented Programming

Вернулся из отпуска, почитал LtU про Aspect-oriented Programming и дотянул наконец руки до AOP. (стыдно, что только сейчас, да :) Впечатления странные -- с одной стороны да, интересно, смысл в таких вещах очевидно есть. Действительно, в жизни встречается дофига этих самых crosscutting roles, т.е. общие.. эээ.. поведения различных объектов. Там классический пример -- куча объектов должны писать лог своих действий -- так вот неплохо когда вся логика писания в лог выносится куда-то отдельно, а объекты сами ничего про него не знают. С другой стороны, основной поинт критиков AOP сразу очевиден -- логика растаскивается по кускам, и отслеживать-поддерживать все это хозяйство сложно. Локальность логики теряется. Да и статья, про которую и был пост на LtU, во многом очень убедительно звучит -- такие системы не особо помогают в декомпозиции самой задачи, т.е. это не к дизайну программ (в высокоуровневом смысле), это решение каких-то сиюминутных программерских проблем.. Будем курить дальше, в AOP должны же быть какие-нить убийственные плюсы, раз все с ним так носятся ;)


Friday, September 01, 2006

www.brainbench.com

Индустрия дешевых1 экзаменов и тестирований -- отличный пример денег из воздуха. То есть людям-то понятно, приятно красивый сертификат на стенке иметь, но когда HR окончательно перестанет на него внимание обращать?? :) Вот, опять халявные тесты на brainbench'е, я теперь еще и C# Master. В добавление к Microsoft Certified Professional в области developing windows application with C#. И то и другое -- на 80% умение пользоваться гуглом и совсем немножко здравого смысла. На C# я в жизни, наверное, тыщи строк не написал :) Короче говоря, кто еще не успел добыть себе такой симпатичный баннер, вперед, особых знаний не надо :) P.S. Да, даже HR майкрософта от недостатка кадров лезет на стенку: несколько месяцев назад мне от них приходило письмо, дескать, мы тут у брейнбенча базу данных купили, там написано что вы Master in C++ Fundamentals, мы скоро опять будем из России людей угонять на работы в Редмонд, присылайте нам резюме.. Так что нельзя назвать брейнбенч совсем уж бесполезной тратой времени :)
1. вообще-то насчет всяких оракловских тестирований меня убеждали что там все не так просто, так что сильно обобщать не буду :)


Tuesday, August 29, 2006

А мужики-то не знают ©

Оказывается, C/С++ Users Journal успешно загнулся полгода назад. Я только что из танка, да :)


Thursday, August 24, 2006

J

Настоящий гуру должен освоить три известных коммерческих языка программирования:
1. Haskell (варианты: ML/Caml/O'Caml/F#)
2. Lisp (варианты: Common lisp,scheme..)
3. APL (варианты J, K, A+)

Первый пункт я начал выполнять уже давно, второй тоже очень медленно идет в фоне, а вот до третьего руки никак не дотягивались.

Сегодня, кажется, дотянулись до J.  Во многом благодаря тому факту, что APL-like языки -- это кажется единственное, на чем можно писать из-под Pocket PC.

Вообще на PPC существуют компиляторы C, lisp, python, есть даже портированый gcc. Но после набирания первых двух строчек на python с помощью экранной клавы стилусом весь энтузиазм пропадает. А посмотрите, как красиво выглядит пересечение множеств (списков) на J:

    setintersect =: e. # [
(1 2 3) setintersect (3 4 5)
3


Monday, August 21, 2006

Декларативное программирование

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

Почему программы не работают? Очень просто. В программах есть баги. Баги доставляют программистам много-много увлекательных минут работы с отладчиком и кучу веселья (ну мне лично, по крайней мере ;), но баги все-таки юзеров очень раздражают, и багов поэтому должно быть поменьше и исправляться они должны побыстрее.

Что является основным источником багов? Нет, не программисты, поскольку программисты тоже люди, они совершают ошибки всегда. Однако ошибки совершать намного сложнее, когда работаешь с простой и насквозь понятной системой. А непонятной и запутанной системой software становится, когда в нем появляются разного рода побочные эффекты. То есть один раз нажимаем пимпу на диалоге -- все хорошо, второй раз нажимаем --программа падает. И, главное, программисту совершенно неясно, почему -- код тот же, данные входные те же(нажатие на кнопку) -- очевидный вывод: что-то где-то изменилось и все пошло не так. Что-то -- это какая-то глобальная переменная, состояние какого-то объекта и т.п. Вникать, что именно, программист будет доолго.

Знакомая ситуация?

Посмотрим теперь на другой аспект, процесс отладки в целом. Что происходит: тестер баг наш нашел, пожаловался и сидит радуется. Что должен сделать программист: повторить баг, под отладчиком, понять, куда ставить брейкпоинт, 250 тыщ раз нажать Step Over/Step Into, следя за тем, что и куда записалось, состояние какой переменной изменилось, и че из этого вышло. Причем связи все эти "что и куда", в программе, написаной на C#/Delphi/C++/Java, нифига не очевидны и хорошо просматриваются только в динамике, когда программа запущена. Программист тратит кучу времени.

А решение этих проблем -- это декларативные, а особенно функциональные языки. Когда все логические связи очевидны, по возможности статичны и строго типизированы. Это позволяет отловить огромную часть ошибок на этапе компиляции. Более того, в таких языках по сути отсутствует понятие порядка выполнения программы. Мы просто описываем связи между данными, преобразования, а интерпретатор вычисляет ответ. Поэтому не надо дебаггером проходить всю программу. Выяснить, какая именно связь не в порядке -- в декларативном языке в разы легче, и связь эту, как правило, можно очень просто отдельно протестировать (unit тесты как будто специально придуманы для ФЯ). 

Проблемы -- во-первых, не очень высокая производительность. Но это неважно в большинстве случаев, да и есть ФЯ Ocaml который может  поспорить по скорости с C++. Во-вторых -- и это главное -- learning curve тут намного круче. Особенно для программиста, не привыкшего к такому способу мышления. Сейчас, правда, они становятся все популярнее. C# 3.0 заимствует фичи из ФЯ,  функциональный язык Nemerle становится, кажется, самой модной темой на рсдн.ру.. 

Хотя я лично в то, что "скоро не будет ни кино, ни театров, а будут сплошные ФЯ" не верю. Мейнстрим это все-таки промышленный дешевый процесс разработки software руками тысяч гастарбайтеров -- индусов, китайцев, и, может быть, русских. :) Индустриализация, промышленный переворот, от кустарного производства -- к заводам и фабрикам ПО :)
Тем не менее, сложные задачи решать на ФЯ намного удобнее. И самая большая з/п (спускаясь на землю :) -- есть и будет у людей с редкими навыками в специфических областях индустрии. Примеры успешного применения ФЯ покажу потом :)


Friday, August 18, 2006

Самый большой недостаток C++

То, что C++ -- это язык с кучей недоразумений, хаков, хаков
над хаками и т.п., я осознал уже довольно-таки давно. Но 
больше всего меня расстраивает одна вещь -- вот когда падает 
виндовс, можно ругать разработчиков. Когда интернета нету, 
я с чистой душой материть админов.

Но вот когда в C++ натыкаешься на очередные грабли, винить
вроде как некого. Страуструп, обычно, не виноват -- он писал
объектно-ориентированную обертку (читай -- "костыли") к
высокоуровневому ассемблеру под названием "C", причем это
было логично, поскольку C был сильно популярен и народ
требовал. А Дениса Ричи обвинять тоже глупо -- ну что можно
взять с ассемблера? Он создавал язык чтоб юникс писать,
низкоуровневое программирование -- порты-регистры, тут ему
просто хотелось что-то чуточку поудобнее, вот и лепил туда,
что в голову взбредет. И у него получился нормальный язык
для своей области.

Я вполне понимаю, почему C++ стал таким, какой он есть, но
вместе с этим эта вот круговая порука -- "никто не виноват" --
больше всего меня раздражает.

Нету, к сожалению, человека, чей портрет я мог бы повесить 
на рабочем месте и метать в него зубочистки ;)


Thursday, August 17, 2006

Знаете ли вы, что...

C++ очень странный язык. В нем если порыться, всегда 
можно найти миллион бесполезных фич.

struct A
{
    char d :6; // ну это всем понятно
    unsigned :4; // опечатки нету ;)
    char c :10; // чему равно (x = a.c = 256) ?
    unsigned :0; // и еще фокус-покус
} a;


Pure ISO C++ :)

Отличный вопрос для собеседований, по-моему. По
крайней мере по уровню идиотизма -- самое то.

Если хотите быть language lawyer'ом, вот правильные ответы:
unsigned : 4; // просто 4 unused бита в структуре
char c : 10;  // char все равно 8 битный,
              // а два бита сверху -- просто так :)
unsigned : 0; // тут произойдет выравнивание
              // размера структуры до размера,
              // кратного allocation unit.
              // В конце структуры, правда,
              // бессмысленно это вставлять. :)


Tuesday, August 15, 2006

И еще немного о программистах

Я вдруг подумал, что во втором посте неплохо б объяснить,  что ж такое, по моему мнению, тру программер. Многие считают, что тру программеры выглядят как три гика на той заезженой фотке про вечеринку в IT стиле.
Так вот, имхо -- ничего подобного. Знакомьтесь, тру программер  John Meacham. Автор проекта jhc, компилятора языка Haskell, кто не знает -- Haskell это само по себе очень тру, нереально  круто, его знание поднимает самооценку до уровня "гуру" и  позволяет обоснованно смотреть на остальных, непосвещенных  свысока... :) (ну эту тему я думаю раскрыть в дальнейшем более подробно). 

Этот человек написал оптимизирующий компилятор языка  Haskell, что подразумевает очень глубокие познания в computer  science, теории типов, всяких там системах term rewriting и т.п. Действительно мега-программер. Действительно тру.


О программистах

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

Потом (пропустим тут несколько лет чтения андеграундных хакерских журналов, попыток написания игр, кряков, вирусов, баз данных, отладчиков и полиморфных движков..), так вот, потом, в какой-то момент, я понял, что ПОНЯЛ. Понял, что там внутри, как регистры-счетчики переключаются, конденсаторы заряжаются, конвейер-кэш-фон неймановская архитектура-ассемблер-машина Тьюринга-бейсик-паскаль-сиплюсплюс... Все довольно просто, на самом деле...

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