Author Archives: himself

Приезжали товарищи из ii-subs, намахали вместе 18 км по Москве.

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

Всё так близко.

Bachelor of Science

В Америке оканчивающие вуз получают степень Bachelor of Science, или “Бакалавр наук”, сокращённо BS. В разговоре это используется так:
“I just got my BS in philosophy and I’m looking for a work”
“Try Mac, they’re always hiring”

Удобно, что BS – это также известное сокращение для bullshit, что примерно значит “пустой трёп”, “чушь собачья”.

Bonus track. Также в английском языке популярно слово “major”, которое в качестве глагола значит “специализироваться” или “получать высшее образование в области”:
“I decided to major in literary arts… Am I going to have trouble finding work?”
“Yeah, all the burger seller positions are usually taken by philosophers”.

О паскале и объектах #2

Я написал предыдущий пост, и знакомый меня справедливо спросил, а какие же именно функции вызываются при создании объекта? Проверить несложно!
tmp := TObject.Create;
tmp.Destroy;

Оказывается, вот полный список всех вызовов при создании объекта: (далее)

Create
@ClassCreate
TObject.NewInstance
TObject.InstanceSize
@GetMem
TObject.InitInstance
@AfterConstruction
TObject.AfterConstruction

Из них TObject.InstanceSize и TObject.AfterConstruction не делают вообще ничего серьёзного, остальные не слишком много (20-30 инструкций).

Выглядит довольно безобидно! Как же на самом деле? Чтобы посмотреть, насколько быстро создаются объекты, я написал простенькую программу (pastebin). В ней в цикле создаётся и уничтожается 50 миллионов объектов и рекордов.
Для рекордов я использовал два варианта создания/удаления: GetMem/FreeMem и New/Dispose. Последний отличается тем, что Дельфи автоматически генерирует код, инициализирующий и очищающий так называемые “сложные” поля – строки и указатели на интерфейсы. Разумеется, Dispose не может быть быстрее FreeMem, поскольку в конечном счёте его же и вызывает!

Итак, пустой объект и пустой рекорд, результаты в миллисекундах:
Objects: 5469
Records through new/dispose: 344
Records through GetMem/FreeMem: 343

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

Теперь мы получаем:
Objects: 5453
Records through new/dispose: 1094
Records through GetMem/FreeMem: 1109

Откуда такой прирост у рекордов? Дело в том, что размер рекорда в прошлом эксперименте был равен нулю. GetMem/FreeMem просто игнорировала эти пустые запросы. У объекта же существуют скрытые поля. Если мы запросим размер объекта

tmp := TObject.Create;
writeln(‘Size: ‘+IntToStr(tmp.InstanceSize));

То получим:
Size: 4
Как только мы добавили поле и в рекорд, оптимизация GetMem перестала работать, и время создания записи подскочило в три раза. Но это ещё не всё! Добавим в рекорд поле типа string, чтобы проиллюстрировать разницу между New и Dispose.

Получаем:
Objects: 6188
Records through new/dispose: 3687
Records through GetMem/FreeMem: 1094

“Корректное” создание рекордов уже всего в два раза медленней объектов! Рекорды через GetMem/FreeMem работают с прежней скоростью, поскольку размер объекта не изменился: переменная типа string занимает те же четыре байта, что и integer.

Примерно то же получится, если добавить в рекорд динамический массив: он тоже требует финализации. А вот статические массивы не требуют: память для них выделяется за один запрос, вместе с памятью записи:
FField: array[0..40] of integer;
Objects: 6844
Records through new/dispose: 1188
Records through GetMem/FreeMem: 1187

Казалось бы, я совершенно напрасно ругал объекты! Ведь любой сколь-либо сложный набор данных в рекорде создаётся всего в два раза быстрее объекта. Ну, два раза для таких быстрых операций – это ерунда. Я уже готов был придти к такому выводу, как решил посмотреть, сколько занимает сложение строк:
s := s + ‘test’;
if Length(s) > 10000 then s := ”; //Чтобы не разбухала

1500 микросекунд! А разница между New и GetMem в примере со строкой была 2500!
Иными словами, расширение места под строку и копирование слова “test” занимает меньше времени, чем инициализация/финализация пустого поля типа string! Да как такое может быть?
Оказывается, вот как. Оказывается, для инициализации и финализации полей Дельфи вставляет не сам код, а вызов внутренних функций @New/@Dispose с параметром, в котором зашифровано, что именно удалять. Внутри этих функций довольно громоздкий процесс разборы параметра на части.

Попробуем сделать всё вручную! Напишем:
GetMem(rec, SizeOf(rec^))
pointer(rec.FField) := 0; //инициализация строки
rec.FField := ”; //финализация строки
FreeMem(rec);

Во-первых, дельфи могла бы догадаться, что на момент присваивания пустой строки rec.FField и так пустой. Но Дельфи этого, слава богу, не делает, и честно проверяет “if rec.FField<>nil then @LStrClr”, образно говоря. Таким образом, мы выполняем все операции, необходимые для создания/очистки рекорда со строковым полем.
Время? ~1300. Меньше, чем на 100 миллисекунд отличается от простого GetMem/FreeMem. Остальные 2400 микросекунд уходят на шатания по функциям @New/@Dispose с выяснением в рантайме вещей, которые и так известны на момент компиляции.

Теперь сделать решительный вывод опять стало сложно. Получается, если делать всё действительно оптимально – то есть, вручную – то рекорды примерно в шесть раз быстрее объектов – и этот разрыв будет расти с ростом сложности! Шестикратное замедление – это уже вполне значительная разница.
С другой стороны, если пользоваться для инициализации рекордов средствами Delphi (New/Dispose), то разница всего лишь в два раза, и она будет уменьшаться с ростом сложности! Ведь чем сложнее объект, тем большую часть создания занимает инициализация, а она общая у объектов и у New/Dispose рекордов.

Во всяком случае, вывод надо сделать такой: с рекордами не стоит использовать New/Dispose, это убивает весь их выигрыш в скорости. Если же вы используете New/Dispose, то уже не очень жалко превратить рекорды в объекты. Это уже мало (в пару раз) замедлит дело. Совершенно неожиданный вывод, поскольку я всегда считал New/Dispose быстрыми обёртками над GetMem/FreeMem.

Вообще же говоря, чтобы оценить порядок временных затрат: время на создание пустого TObject примерно равно одной десятитысячной микросекунды. В общем, я скорее всё же был неправ, обвиняя объекты в медлительности. Разумеется, было бы лучше, чтобы объекты создавались без дополнительной суеты, но её не так много, чтобы это делало их использование при большой нагрузке непрактичным.

О паскале и объектах

Знаю, что программистов тут мало, но хочется куда-то написать. Я вдруг понял, какой полезной возможности нет в Delphi, которая давно есть во всех компиляторах.

В ней нет объектов.

Конечно, есть классы, которые (далее)

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

Но это неправда.
Копейки очень быстро собираются в рубль. Классами нельзя играть с такой же лёгкостью, как рекордами. Их не жалко в ситуациях, которые возникают редко: при создании приложения, открытии окна, загрузке файла. Но при обслуживании запроса по сети? Уже нет. Создавать класс на каждый запрос – слишком дорого. А если их будет тысяча в секунду? А десять тысяч?

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

Delphi очень нужны наследование и vtable рекордам. Ну или возможность сделать класс lightweight, чтобы он не вызывал всю эту борландовскую ерунду при инициализации. Чтобы стандартное Create было одним выделением памяти + занулениями, как с рекордом.

UPD: Эксперименты показали, что я в этом мнении более-менее неправ.

Ошибочно прочёл чей-то ник как "Анимешка Оккама"

Интересно, какая это была бы анимешка?

Жил-был обычный японский школьник. У него был злейший враг – он сам. Они учились в одной школе. И ещё школьник был тайно влюблён в одну девочку… это тоже был он сам. Но он не разделял своих чувств к себе. Хмм. И ещё был один школьник, в которого он сам был влюблён, и это тоже был он сам, получается целый любовный треугольник. Но этот последний школьник влюблён в карри…
Нет, к чёрту карри. Ни к чему плодить сущности. Этот последний школьник был эгоистом и любить не умел: кроме себя, его никто не интересовал. И вот 26 серий школьник бегает сам за собой, и тот тоже за собой, а последний на них плевать хотел и любит только себя. Иллюстрация:

Школьник —(любит)—> Школьник —(любит)—> Школьник <— (любит себя)

И тут появляется враг…

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

Но тут выясняется, что пока он плавал, в мире набрало силу великое зло. (В лице самого школьника). Оно непобедимо в принципе, и поэтому никто, кроме самого школьника, не может его победить. “Пока один из нас двоих не умрёт, эта битва не будет закончена!” – кричит школьник, убивает сам себя и умирает героем (an hero). Накама и любимая девушка рыдают над собственной могилой.

Идут титры.

В последний момент показывают руку главного злодея, она шевелится. Зло ещё не повержено до конца. Слава богу, добро тоже.

Про логику в речи

Похоже, в русском языке образовалась культура плохих переводов. Зрители и читатели не просто привыкли, они считают бессмыслицу нормой. Условностью, на которой сходятся и автор, и читатель. “Я напишу идиотский бессвязный текст, вы прочитаете идиотский бессвязный текст, никто ничего не поймёт, но вы сделаете вид, что всё поняли”.
“Отличная идея!”

Думаете, преувеличиваю?
Попробуйте, когда смотрите очередной ситком или американский фильм в дабе, задавать себе вопросы каждые три фразы: о чём только что сказали? Как это связано со сказанным раньше? Что я узнал из последней фразы?
Вы удивитесь, каким дебильным внезапно окажется фильм. Выяснится, что половина реплик не несут никакого смысла, и вообще непонятно, к чему относятся и зачем сказаны. Однако зрители так привыкли к этому дебилизму, что считают его нормой. Считают, что это художественная необходимость.

Да нет же!
Откройте любую хорошую книгу…

Откройте любую хорошую книгу на русском, откройте любой нормальный перевод. Откройте свой рот, в конце концов, и попробуйте произнести, что получилось! Вы подавитесь этими фразами! Они тупые! Их написал переводчик-дегенерат. Невероятный сюрприз: в оригинале никогда не бывает дебилизма. Это почти закон мироздания. Книга может быть скучной, банальной, невыразительной, у автора может быть бедный язык, но он никогда не напишет бессвязного текста. Так устроены наши мозги, что даже человек с IQ 50 мыслит связно и последовательно.
Там, где получилось несвязно и непоследовательно – это не художественный приём, а безмозглый перевод.

Это беда не только русского. Меня просто тошнит от некоторых бака-цуки переводов Харухи. Полюбуйтесь:
From what I’ve heard, even though wild bears have yet to appear, there were sightings of a wild boar once, in this area. But if that was true, why hadn’t I heard about it before?
“Я слышал, что, хотя медведей здесь ещё не было, видели кабана. Но если так, почему я об этом не слышал?”
Вопрос: каким надо быть клиническим идиотом, чтобы родить эту фразу? Переводчика не смутило, что он сам себе противоречит в подряд идущих предложениях? Это же не просто красная лампа, это сирена долбанной ядерной угрозы! Тут нужно просто абзацами удалять текст и заново переводить!
Но всем пофигу.

“He’s stopping at the same place again.”
I quickly turned to the dog. He had all four of his paws planted firmly into the ground, and no matter how hard Sakanaka-san tried to pull him along, he wouldn’t budge an inch.
Aww~ was what his owner said, apparently disappointed. I believe everyone present felt the same too.

Всё чисто, да? Ага, щаз. Предыстория такая: собака боится некоторых мест в округе. Толпа людей из любопытства пошла посмотреть, что это за места. Взяли с собой собаку. Нашли место. Собака остановилась. Какая, чёрт переводчика дери, может быть реакция у людей, которые хотела, чтобы собака остановилась, когда она остановилась?! Разочарование? Мозги на месте вообще?
А люди читают.

Sometimes I wonder if dogs have genetic mutations or weird sicknesses that make them like to go for walks.
Я не понимаю, как у переводчика, написавшего это, в голове не завыла сирена? Какого чёрта собакам нужна болезнь, чтобы любить прогулки?! Разве не очевидно, что это ошибка? Но нет, всем пофигу.

All of us followed behind, as if taking a relaxed stroll.
“Which way should we go? Can’t you go faster, JJ? Hurry, hurry!”
Haruhi, who was standing right beside Rousseau, ushered him on with her words of encouragement.

Каким боком Харухи оказалась standing?! Ну минуту назад же было stroll. Ну глаза же откройте. Пофигу, да?
Пофигу.

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

Нет!
Авторы никогда не пишут бессвязного текста. Это может сделать только переводчик. Чтобы доказать это, я только что наугад привёл три примера идиотского текста. Сейчас я открою японский оригинал, и посмотрю, что там написано в этих местах.

Итак:
From what I’ve heard, even though wild bears have yet to appear, there were sightings of a wild boar once, in this area. But if that was true, why hadn’t I heard about it before? I had frequented the riverbank often, and to top it off, this place was situated near the train station. If wild boars were really sighted, wouldn’t it have caused some sort of ruckus? Why didn’t I know anything about it till now?
“ここいらに熊はいないが猪ならたまに降りて来るという話を聞いたことがある。しかしそれにしたってこんな駅近くの市街地までとなると相当規模で珍しく、そんなニュースには未だお目にかかったことはない。”
“Медведей здесь не водится, но вот дикие кабаны, говорят, временами спускаются с гор. Странно, впрочем, что хотя появление кабана в жилом районе неподалёку от станции стало бы целым событием, я ещё не слышал об этом по телевизору”.
Всё. Точка.

Aww~ was what his owner said, apparently disappointed. I believe everyone present felt the same too.
くーん、と悲しげな声を出されては飼い主のみならずこれ以上は、という気分になる。
Окей, это действительно сложная фраза, что не отменяет, однако, неправильного перевода! Сложно найти правильный, но несложно заметить ошибочный!
Рискну предположить следующее:
– Ууу – стало казаться, что собака жалобно скулит уже не только на свою хозяйку.
Хотя тут знакомые специалисты утверждают, что наиболее вероятная версия: “собака скулила, и стало ясно, что они обе с хозяйкой застряли на месте” по смыслу.
Правка от 2013. “У-у-у! – услышав этот жалобный скулёж, уже не только хозяйка, но и все остальные почувствовали: всё, предел, дальше [собаку тянуть нельзя].”

Sometimes I wonder if dogs have genetic mutations or weird sicknesses that make them like to go for walks.
Ага! Как же!
“犬という動物はよほどの偏屈か病を患ってでもいない限り散歩が大好きであり、その血脈的趣向はルソーにも受け継がれていた。”
“Не знаю, от большого упрямства это, или что, но так уж устроены собаки, что, пока их вконец не свалит болезнь, они рвутся на прогулку”.
Какие генетические мутации? Какие диковинные болезни? О чём переводчик вообще?

Пока искал, нашёл ещё. Коидзуми предлагает пригласить Мори-сан на помощь. Герой отказывается, поскольку не доверяет Мори-сан. Коидзуми говорит:
That’s a pity then. And after all the trouble I went of asking Mori-san for help. It seems that I’m going to be a laughingstock at the office again.
“Жалко. А я-то старался, просил Мори-сан помочь. Надо мной снова все в офисе будут смеяться”.
Всё здорово, да?

Вы не представляете, что было в оригинале:
森さんにそうお伝えしておきますよ。おそらく苦笑されるでしょうね
“Я передам твой ответ Мори-сан. Боюсь, это её расстроит”.

Да, бака-цуки! Да! Почти угадали! Над вами снова все в офисе будут смеяться. Боюсь, это вас не расстроит.

Obligatory move

В любом деле и безделье есть приёмы, которые пробуют всюду. Сначала их пробуют, потому, что это клёвые идеи. Такие клёвые, что их можно пихать куда угодно, и они там всё везде улучшат раза в два. Это, например, идея совместной работы, лежащая в основе вики.
Любая идея, однако, со временем исчерпывает себя.

Однажды кто-то замечает что идея больше не работает, объявляет вслух – и покатилась лавина. Люди видят, что идеи слишком много, а пользы уже мало, начинают издеваться и пересмеивать, как было с отражениями, градиентами и “Beta!” в веб2.0.

Но есть промежуток, когда идея уже исчерпала себя, хотя большинство ещё не обратило на это внимания. Конечно, люди не дураки, и неудачные примеры по-прежнему кажутся им неудачными, однако они не видят системы. В это время бывшая хорошая идея существует как obligatory move. Она обречена появляться везде, и всюду обречена на провал. Идея всем уже надоела, но никто этого ещё не понял.

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

А вот у кого-то, по-моему, у Крапивина, была такая сцена, где отец жёг личную переписку умершей жены. А ребёнок сидел рядом и смотрел. Ему было интересно, о чём в письмах, и он спросил: как же так, ведь обидно, что письма сгорят, а мы так и не узнаем. Неужели нельзя посмотреть? На это отец ответил что-то в духе “нельзя, ведь это чужие письма”.
В книге всё это было к тому, что чужие письма нельзя читать. Но это прекрасная сцена, которая по-разному читается в разном возрасте, и всегда трогает. Однажды представляешь себе не ребёнка, которому было просто любопытно, не абстрактную обиду от пропавших тайн, а отца, бросающего в печку письма, написанные любимой рукой, содержащие последние клочки сознания любимого человека, его мысли, его характер. Всё, что от него осталось – не читая.
Потому, что нельзя читать.

Ох лол

До меня только дошло, что у нас в команде, как в том анекдоте, один знает русский, другой японский, третий – английский, а четвёртый нужен, чтобы присматривать за всеми этими умниками :)

Auto-updater

This is the automatic updater notice.

Current version of TortoiseSVN is: TortoiseSVN 1.4.8.0.
You’re using: TortoiseSVN 1.6.4.0.

Your version is forward-outdated, please downdate it immediately as the prolonged usage of the yet-to-be-developed product can lead to irrevocable temporal paradoxes and make you lose your data.

Features removed in TortoiseSVN 1.4.8.0:
– Option to specify temporal plane of the SVN server on the connection configuration page.
– Support for distributed-in-time version storage.
– Support for rolling edits back onto your computer, creating conflicts and untyping the conflicting changes (only for reverse quantum law architectures)