Как стать автором
Обновить

Комментарии 57

НЛО прилетело и опубликовало эту надпись здесь
Вот черт, я уже следую части этих советов :(
Я думаю, практически все следуют каким-то из них, хотя в большинстве своем и не нарочно. Я сама периодически нахожу свои же устаревшие комментарии и криво названные переменные (по первой части).
помните, маньяк уже наточил нож, и ищет ваш адрес…
Несправедливо( по его мнению ) уволенный админ или программист страшнее маньяка :)
Вобще непонятно почему забыли обфускатор :) переменный с именами вида md5 выглядят намного веселее, а главное читабельнее
Научите на свою голову, а потом еще недоумевать будете: «где такому учат?». Шучу =) Большое спасибо Вам за перевод; первая часть хорошо так посмешила, вторую пожалуй оставлю на завтра.
12. Перегружайте операторы
…В конце концов, если Страуструп использует операторы сдвига (>> и <<) для потокового ввода-вывода, чем вы хуже?


Воистину, чем плохо? Я как-то у себя в блоге описал класс (правда, на Python-е), позволяющий делать композицию функций красиво и компактно:

izip_fillwith0 = partial(izip_longest, fillvalue = "\x00")
convert_string_to_byte_list = partial(imap, ord)
xor_values = partial(reduce, operator.xor)

xor_strings = compose >> \
              (apply, izip_fillwith0) >> \
              (imap, convert_string_to_byte_list) >> \
              (imap, xor_values) >> \
              (imap, chr) >> \
              "".join

ARG = ("abcdef", "ABCDEF", "5678900")
Для композиции функций оператор может быть понятен.
Перегрузка, скажем, += для добавления заказа в корзину, тоже понятна.

А вот перегрузка * для того, чтобы получить результат какой-нибудь некоммутативной операции над элементами в двух корзинах в виде строки, разделенной запятыми — это уже странно.
% — вполне очевидный оператор, да? Либо (наиболее популярное значение) остаток от деления, либо, в какой-нибудь бухгалтерии, «посчитать процент».
Вспоминаем тот же самый Python: print "Day %s of %s" % (index, total)

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

Рекордсмен с этой точки зрения, по-моему, J, в котором символы функций не имеют ничего общего с их смыслом. Ну не может нормальный человек угадать, что %: — это корень, а %~ — деление! Запомнить — может, а принять и смириться — нет :-)
Да-да, мы с вами, вроде, про J уже общались :)

И я не сказал бы, что там всё уж так плохо. Если помнить, что все функции идут группами по три, т.е., функции «<что-то>», «<что-то>.» и «<что-то>:» всегда как-то связаны, то… с этим вполне можно жить.
А, ну да, ну да :-) Просто J нанес мне такую глубокую моральную травму, что я до сих пор не могу оправиться, взять себя в руки и разобраться, как на нем решается квадратное уравнение, не говоря уже о том, чтобы его не вспоминать по каждому поводу :-)
Прекрасно понимаю. J, киношно выражаясь, как вино. Он ощущается лучше со временем.

Когда я первый раз его увидел, я немножко почитал про него, посчитал его Perl-ом в степени Perl-а, и перестал о нём думать.
Где-то через пару лет я (не перечитывая книг, не вращаясь в среде J-программистов, просто помня про него) неожиданно осознал, что на данный момент J (и прочие языки его семейства) — это фактически лучший способ описания параллельных вычислений.

Ему не хватает мелочи. Наподобие libpcre, библиотечки навроде libjlang, чтобы его можно было (аналогично тем же перловым регекспам) интегрировать в любой другой язык и писать на нём маленькие производительные вычислительные фрагменты.
% — не совсем. %s — сложно назвать оператором, это больше подстановочный символ, который мы так определили. Изначально, я не знаю математического смысла в унарном проценте.

Но есть базовые привычки, вроде транзитивности и аддитивности плюса, которые очень сложно «переопределить» в мозгу.

В конце концов, country_name — тоже некоторые символы. Что мешает нам хранить в них текущую корзину клиента? :)
с #define TRUE (random()>0.5) ничто не сравнится.
НЛО прилетело и опубликовало эту надпись здесь
Смотря в какой предметной области. У меня — финансы (одна из), там вечно проблемы «в валюте или в эквиваленте», «в рублях или в копейках (той валюты, о которой идет речь)» и «проценты или доли» — хочешь не хочешь, научишься либо комментировать, либо называть однообразно.
Читал недавно статью про язык F#. Наверное, единственный язык общего назначения, в котором при его проектировании озаботились этим и ввели на уровне языка понятие «единицы измерения». Так что 10<m> + 15<m> = 25<m>, 10<m> + 15<s> выдаёт ошибку типизации, а 15<m> / 5<s> = 3<m/s>

А потом кто-то ещё говорит, что функциональные языки — странные, непонятные и неудобные :)
А там поддерживается какой-нибудь 1 * 1 / 1<s*s> = 1?
Блин,
1<kg> * 1<m> / 1<s * s> = 1<N>
Я эт, ссылку вообще-то дал…
Вот даже ещё более хорошую ссылку дам: msdn.microsoft.com/ru-ru/library/dd233243.aspx — цитирую красивое прямо оттуда:

// Выразить одну единицу измерения через другие
[<Measure>] type N = kg m / s 

// Указать соотношения одной единицы измерения с однотипными ей:
let mlPerCubicCentimeter : float<ml/cm^3> = 1.0<ml/cm^3>
let mlPerLiter : float<ml/L> = 1000.0<ml/L>

// Температуры и единицебезопасные функции перевода:
[<Measure>] type degC // temperature, Celsius/Centigrade
[<Measure>] type degF // temperature, Fahrenheit

let convertCtoF ( temp: float<degC> ) = 9.0<degF> / 5.0<degC> * temp + 32.0<degF>
let convertFtoC ( temp: float<degF> ) = 5.0vdegC> / 9.0<degF> * ( temp - 32.0<degF>)

// И можно даже наложить ограничение на единицы измерения аргументов функций,
// при этом не указывая их явно
let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y
Наличие этого монстрика в языке говорит о невозможности писать на нём удобные библиотеки. Или они (дизайнеры F#) считают, что единицы измерения необходимы во всех случаях, для которых предназначен язык?
Интересная логика. Вы ведь проясните, что вы имеете в виду?
Единицы измерений нужны в решении далеко не всех задач. Не стоит ради domain-specific фичи усложнять синтаксис и семантику всего языка, если только он не предназначен как раз для решения задач с единицами измерений.

Сложный синтаксис приводит к невозможности реализации систем метапрограммирования, а семантика — к усложнению средств анализа кода.
Единицы измерений нужны в решении далеко не всех задач.

Вполне очевидным решением является неиспользование их в тех задачах, где они не требуются, разве не так?

Сложный синтаксис приводит к невозможности реализации систем метапрограммирования

Начиная с какого уровня сложности плавное повышение сложности синтаксиса приводит к скачкообразному изменению «возможности реализации систем метапрограммирования» на «невозможность реализации систем метапрограммирования»?
И что вы имеете в виду под «системами метапрограммирования»? Особенно с учётом того, что F# сам по себе является функциональным языком, следовательно, с изначально доступными достаточно высокими уровнями абстракций.
Достаточно высокими на данный момент. Common Lisp, Tcl и, с сомнительным успехом, C++ держатся на плаву за счёт метапрограммирования (AST макросов, текстовых макросов и текстового препроцессора соответственно), а абстракции F# просто устареют и ничего с этим не поделаешь. Высокоуровневый язык без возможности расширения самого языка — это смешно.
Так всё-таки (помимо двух других вопросов) вы расскажете, что вы имеете в виду под «системами метапрограммирования», какие вы видите у них плюсы и по сравнению с чем? Common Lisp — это понятно, тамошнее понятие макросов не является, по сути, даже «метапрограммированием» по отношению к «обычному программированию» на нём же, это просто равноправное средство языка. Tcl — аналогично, это «Lisp без скобок». А вот C++… Под метапрограммированием на нём вы имеете в виду тамошние страшненькие макросы (которые спокойно повторяются под любым другим языком, будь то хоть Python, хоть F#, с помощью, например, GPP), или, допустим, темплейты, находящиеся вполне на дефолтном уровне абстракции любого нормального функционального языка?

И ещё, если вдруг для вас препроцессоры — это полезная «система метапрограммирования», то как сложный синтаксис может помешать использовать тот же GPP?

(Если ответите, но сами про F# не почитаете — вас ждёт интересный и приятный сюрприз).
В этом и сомнительность успеха C++. :) Текстовый препроцессор — отличное средство удержать язык на плаву любой ценой, если это кому-то надо. Сложный синтаксис им никак не мешает, но и пользы от GPP немного.

У меня вопрос. Почему макросы CL — это средство языка? Макросы вычисляются при компиляции и выдают программу, которую компилятор преобразует в машинный код или байткод, т.е. макросы пишут готовую программу. Это ли не определение метапрограммирования? Вот в Tcl это просто средство языка.

Про плюсы и по сравнению с чем уже рассказано: habrahabr.ru/blogs/arbeit/99146/#comment_3061341 Примеров куча в On Lisp Пола Грема и Let Over Lambda Дуга Хойта. Особенно советую последнюю почитать. Там немало полезного даже если Вы не пишете и не собираетесь писать на Лиспе.
У меня другой вопрос: а не overrated ли это метапрограммирование макросами, какого бы вида они ни были?

В CL они являются вполне родным средством языка в том плане, что там нет принципиальных синтаксических различий между данными, кодом и кодогенерирующим кодом (макрами). Если мне не изменяет память, из любого из трёх уровней можно обращаться к любому из трёх уровней — ну, там, в макросе использовать определённую в основной области видимости функцию, и т.п.

В C++, напротив, фактически три языка в одном: базовый функционально-объектный, шаблоны для генерирования базового функционально-объектного кода, и препроцессор для генерирования первых двух. Нижележащий уровень можно генерировать в вышележащем, но нельзя нормально использовать для модификации процесса генерации. Из-за слабости и разобщённости всех трёх «подъязыков» нормального метапрограммирования и не получается; причём, пожалуй, держится на плаву он всё-таки не из-за макросового подъязыка, а в первую очередь из-за достаточно мощного темплейтного подъязыка, с помощью которого и пытаются добиться мощи, хоть сколь либо приближающейся к CL-ным макрам.

Но… А в функциональных языках? Там просто другая идея. Высокоуровневость семантики, ленивость, first-class функции и прочие радости позволяют переложить генерацию достаточно сложных конструкций на уровень компилятора — при этом сохраняя прозрачность кода, поддерживая строгую типизацию, обеспечивая его корректность. Те же самые ленивые вычисления — это не скрытая кодогенерация? Банальная композиция функций (которую, за счёт функциональной чистоты аргументов, среда может быть способна прекомпилировать и оптимизировать), не говоря уже про более сложные комбинаторные библиотеки — это не кодогенерация? Функции более высоких порядков, чем первого (вот, например, прелюбопытная статья, зачем кому-либо на практике может пригодиться функция шестого порядка) — чем это не лисповое макро, если учесть, что, опять же благодаря «чистоте» используемых функций, какие-то порядки из этой функции могут вычисляться компилятором? Чем это слабее, чем CL-ные макры?

А, да, о сюрпризе. Впрочем, описанном даже в той статье по F#. В нём есть так называемые quotations, позволяющие получить доступ к синтаксическому дереву F#-овых конструкций. Ну да, вы уже представляете, какие возможности открываются. Да и примеры там шикарные: автоматическая переделка кода для запуска его на GPU.
В ответ на все вопросы предпоследнего абзаца вынужден ещё раз направить на Let Over Lambda. Ленивость, функции высших порядков в чистом языке, слабее CL-ных макр. Они находятся примерно на одном уровне со средствами Tcl.
Как минимум странный вывод
НЛО прилетело и опубликовало эту надпись здесь
А зачем это всё? Можно мне дураку объяснить?
Можно.
— от души посмеяться, представляя процесс разработки кода в соответствии с этими правилами.
— узнать себя, ужаснуться и сделать выводы (больше так не делать или срочно поправить уже сделанное).
— узнать коллегу, разгневаться и побежать его убивать.
— поиграться с фокусами, которые можно изобразить средствами #define, или задуматься над тем, сколько таких фокусов вы можете придумать/применить для своего языка.
— да мало ли что еще.
А это принесёт пользу хоть кому-нибудь помимо мифических лулзов?
Это может принести пользу разработчику. Если так маскировать свой код, подобное делал Леонардо ДаВинчи со многими своими изобретениями, то никто кроме разработчика не сможет, по крайней мере оперативно, поддерживать такую разработку. А это значит незаменимость сотрудника, повышение ЗП и прочее вытекающее.
Это может привести к невозможности добавления новых идей без участия этого разработчика. Как думаешь, почему в Open Source просят писать код понятно? Чтобы любой достойный человек мог присоединиться к работе, не портя свою голову перед этим.

К тому же что может случиться, если вдруг тебя попросят через год заняться этим самым проектом вновь и добавить туда что-то серьёзное? Будет проще уничтожить путы, чем распределять нормально, и я не удивлюсь, если это решение будет принято.
Думаю, плохо забывать, что не всегда нужно быть единоличником.
Я лишь описал зачем это может быть нужно разработчику :)

Конечно так делать некорректно, но к сожалению так делают многие, и именно с целью быть «единоличником».
Я не раз сталкивался с таким кодом, как я думаю и многие.
>Это может привести к невозможности добавления новых идей без участия этого разработчика
Так это же просто отлично! Кто это там без меня собрался добавлять новые идеи? :)
«Узнать себя и сделать выводы» — однозначно, в порядке самосовершенствования (лично я уже удалила несколько здоровенных кусков закомментированного кода образца 2009 года).
«Поиграться с #define» — вообще полезно изучать свой язык в деталях — как для общего развития, так и для разбирательств в чужих кодах авторов, следующих приведенным правилам.
Пункт 6 из раздела о документации — просто огонь!
Уже надоело это петросянство
#define a=b a=0-b

Если я правильно понимаю, автор хотел сказать, что если где-то в коде будет присваиваться значение b переменной a, по факту присвоится -b. И попробуй разберись потом, почему результат прямо противоположный.
Он-то хотел, это понятно, но этот макрос сам по себе не работает, и мне не удалось за полчаса исправить его так, чтобы заработал.
9. Имена в коде vs имен в интерфейсе

Небольшое замечание к примеру этого пункта:

Всетаки zip и Postal Code имеют кое что общее ;)

пруф тут
Имеют, я знаю. Идея в том, чтобы заставить человека не тупо искать «postalcode» в коде, а думать, подбирать синонимы, фантазировать — в общем, максимизировать интеллектуальную нагрузку :-)
А потом не удивляйся, почему тебе в магазине не дадут «эту, ну как её, слева от правого края на половину трети ширины вашей ступни, ещё очень яркого, но не слишком заметного цвета». =)
Вот именно поэтому я предпочитаю магазины, в которых до всего могу дотянуться сама ;-)
> Не представляю, на какую среду разработки рассчитан этот метод

Знаю одного парня, который принципиально не пользуется подсветкой и отлично работает :)
Открывая статью думал, что напишут что-то интересное. Не написали.

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

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

Ну и да, #define TRUE <выражение> тоже имеет право на жизнь, правда лишь в том случае, если надо просто нагадить.
Вообще-то пока что переведены только 3 главы из 12. Первые главы многих книг описывают известные вещи для более плавного перехода к новым. Дальше будет интереснее, про многопоточность тоже есть.
Почитал оригинал. Забавно в целом, дальше — больше. И да, некоторые пакости, которые банальное code review не отловит нашлись. Правда, автор до совсем тяжелых гадостей не дошел, но, в принципе, если собрать все его советы и успеть их попользовать сразу, то нужный эффект будет достигнут.
«Успеть» — это в смысле пока маньяк, сопровождающий ваш код, не найдет ваш адрес? :-)
«За это время мы успеем добежать до канадской границы!»
Нет, по «успеть» подразумевалось время между написанием чудовища и просмотром кода вышестоящими товарищами. Вот в это время надо успеть уволиться и как раз двинуть к канадской границе =)
Иначе уволят так и так, только предварительно сделают такое, что глаза будут как у совы, натянутой на глобус =)
Используйте имена функций и переменных длинной от 20 символов в виде случайных последовательностей и код будет практически не читаемым. Хотя это и легко победить…
«Код не должен выглядеть неподдерживаемым, а только быть таким»
Иначе ваши безобразия быстро пресекут :-)
Ну тогда только левые длинные название с уклоном в комментарии ))
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории