Как я нашел лучший в мире язык программирования. Часть 1
Поскольку дальше я буду жестко провоцировать троллей на тему языков программирования, и тем более назову лучший в мире (на данный момент) язык программирования (абсолютно лучший, то есть без всяких оговорок), от чего, обычно, у троллей срывает башню, рекомендую им и всем остальным ознакомиться с моим постом почти трех летней давности «О выборе языка программирования», все написаное там актуально и повторяться я не хочу.Прочитали? Дальше будет про лучший в мире язык программирования, который я назову ближе к концу. Да, да, еще три дня назад я и не думал что единороги существуют — ведь каждый язык так или иначе сосет, и каждый сосет по-своему (хотя нет, есть и такие которые сосут всегда и везде, но о них не будем). Как инженер, я прекрасно понимал что в вопросе языка не возможно без разнообразных trade offs, начиная с garbage collected vs manual memory management, хотя Rust пытается съесть рыбку не присев на палку в этом вопросе, и так далее. Хоть мы и говорим о языках общего назначения, все они так или иначе позиционируют себя, фокусируясь на каких-то идеях, принципах, и целях, в которых они хороши, оставляя все не согласованное с такими принципами в лучшем случае возможными, но не эффективными и/или не удобными. Одним словом нецелесообразными. Однако язык, сочетающий в себе несочетаемое, есть.
Как я уже писал в прошлом, проблема выбора языка программирования в моей жизни появилась только в зрелом возрасте, лет так 7 назад, когда я понял что Java уже не торт. Тогда же, в поисках продуктивности и наивном желании сделать Scala основным конторским языком на следующие 10 лет, мы купили early access (некоторые главы) еще не вышедшей книжки Odersky et al. Так что и Scala я для себя открыл, за годы до того как она появилась в резюмах и головах кандидатов приходящих на собеседование, а некоторые из вас еще в школе учились. Опять же будучи в компании, которая более 10 лет делает IDE на заказ, я видел столько языкового гумна и жемчужин среди него, что прошу капитанов очевидность немного подумать, прежде чем отсылать автора к какой-нибудь языковой истории — неужели вы думаете, что чувак который 7 лет ищет и не может найти язык не знает про вашу капитанскую историю.
В последние годы проблема выбора языка только обострилась: нам надо начинать новый технологический виток в Xored, и есть некоторые идеи «изысканных» технологий, позволяющих делать всяческий Magic, но я не был готов стартовать что-либо очень долгое время. Ответ, на вопрос почему, меня до сих пор удивляет, так как если бы я получил подобный ответ на собеседовании — сразу бы записал чуваку минус в пацанскую книжку. Ответ действительно звучит глупо и по-детски: я не знал на каком языке программирования мне бы хотелось видеть стек наших восхитительных технологий. Единственное оправдание: я действительно нацелен на длинный путь — и это не один отдельно взятый проект, это то, во что хочется вложить лучшие годы жизни, и цена вопроса для меня очень велика.
Отправляясь в долгое и сложное путешествие в выборе транспортного средства опасно ошибиться. И все последние годы я искал (ждал?) язык программирования (платформу), который не вызывал бы у меня отторжения по тому или иному поводу. Имея в планах довольно грандиозные задачи, к такому языку программирования я выдвигал разные функциональные и не функциональные требования.
ТребованияЯ хочу высокопроизводительный код в браузере, и я хочу возможность затолкать свой код в unikernel/cloud os. Я хочу высокопроизводительный сервер-сайд с большими объемами обрабатываемой информации. Я хочу iOS и Android (естественно тоже высокопроизводительный). И я хочу все это программировать без геморроя. Не парится с кодогенрацией, не работать с памятью напрямую через узкую калитку sun.misc.Unsafe, и не програмиировать большие массивы как математик на Фортране.
Я хочу писать очень low-level код (close to bare metal), и иметь производительность сравнимую с нативным C/C++. Я хочу GC когда надо, и не хочу GC когда не надо. Я хочу писать в OO стиле, и в функциональном. Я хочу переопределения операций, HOF и замыкания. Я хочу generics, возможно я хочу темплейты и/или макросы, для релизации каких то будущих концепций. Я хочу понимать как все это реализовано в языке, начиная с memory и concurrency models, и иметь возможность управлять этими вещами так, как я хочу.
Я хочу всего на низком уровне, и хочу всей мощи на высоком уровне сравнимой со Scala. Я хочу писать код быстро и просто, спинным мозгом (я хочу чтобы компилятор думал за меня), а не я за компилятор (как это происходит при программировании на Scala или С++). Я хочу быть продуктивным как программист и писать программы в разы быстрее чем, например, на Java или JavaScript.
Это такой быстрый дамп хотелок из головы (специально я никогда их не записывал). Но понятно что, хочется всего и сразу, и я первый кто бы сказал что все сразу: такого языка нет — идите с пляжа. Но он есть.
Кросс-платформенность и Close to Bare Metal Я хочу кросс-платформенность с обязательной компиляцией в JavaScript. И не просто компиляции в JavaScript, а высокопроизводительный код в браузере. Помимо всех фич языка дающих мне возможность программировать UI и и клиент-серверное взаимодействие, мне нужен серьезный number crunching на клиенте, и перемолачивать миллион-другой кортежей за доли секунды — очень желательное требование. Возможно, что клиентский код будет в том числе полноценной P2P сети, и так далее. Короче требований к коду на стороне браузера, не меньше, чем к решениям на стороне серверов.
Писать что-то высокопроизводительное над большим количеством данных, что на Java что на JavaScript можно. Такие вещи более-менее решаются активным использованием off-heap data structures, что предполагает либо кучу сгенерированного (со всем вытекающим из этого геморроем) кода, либо жалкое подобие программирования — технически вы программируете на Java, но это уже не Java вашей мамы, а жалкий subset языка. В мире браузеров — та же самая история с typed arrays и asm.js (оставьте при себе всякие NaCl/PNaCl и прочее — не интересует).
Теоретически я могу взять для своих задач много чего: scala — scalajs, go — gopherjs, да и большинство JVM-based вещей (горячо любимый мной Fantom, Kotlin, Ceylon) с компиляцией в JavaScript, при условии что я могу элегантно использовать off-heap данные в случае компиляции в байткод, и, соответственно, typed arrays в случае компиляции в JavaScript.
Собственно я и шел по этому пути, но, возвращаясь к теме статьи — это путь против языка. Я программировал против языка, вернее платформы JVM, которая по сути ортогональна решаемой задаче и для решения моих задач мне нужно все то же, что дает платформа, но по-другому и сделай-сам. Мне нужен off-heap менеджемент памяти, собственная система value типов, и, кроме того чтобы все это работало эффективно мне нужна генерация кода (compile-time и/или run-time). Короче возникает вопрос — зачем мне все эти языки и платформы (JVM, браузер), если они мне не помогают, а только мешают?
JVM Off-Heap Data Structures Конечно же, в мире есть много достойных проектов идущих «против платформы», тем кто интересуется в контексте Java могу порекомендовать разные источники, но можно начать с блога Mechanical Sympathy. Вообще эти ребята сделали и делают множество интересных вещей с JVM. Что же касается производительности — в последнем посте показывают как они уделывают ProtoBuf в 15–35 раз, что же касается Off-Heap data structures, вот в этом посте показан пример показывающий рост производительности в 40 раз по сравнению с использованием языка (Java) как говорится as designed.
Пользуясь случаем хочу отметить очень понравившийся мне малоизвестный (я бы сказал совсем неизвестный проект): landz. В котором автор фактически предлагает новую платформу поверх JVM c lock-free/garbage-free off-heap memory allocator, lock-free collections, async-await, channels, off-heap collections и тому подобное. Очень круто… Можно упомянуть objectlayout.org и много еще чего, но все это очень неудобно, и делается вопреки, а не благодаря дизайну платформы.
Браузеры, asm.js и emscripten В браузерах emscripten делает чудеса. Для тех, кто не в курсе emscripten — можете сыграть в например в Quake3, список портированных игр (и пр.) тут. Насколько я понимаю, Unity и high-end игровые движки как раз сейчас занимаются тем что тащат себя в браузер именно этим способом. Unity вообще компилирует всю свою заморочку включая .NET (Mono) рантайм в JavaScript (asm.js) с помощью emscripten, но конечно это не тот JavaScript который вы пишете руками — такой JavaScript — может быть только результатом компиляции. У меня есть серьезные сомнения что программа на JavaScript (as designed) будет где то рядом по сравнению с asm.js (имеется в виду number crunching и большие объемы данных), а если так, то я хочу генерации asm.js (и, соответственно, другую memory model) там где надо.
Более подходящий язык? (low level) Думающий читатель предположит, что для комфортного решения подобных низкоуровневых задач нужны совершенно другие языки (а от себя я добавлю: и платформы), и будет прав. Я тоже так думал, и даже порывался написать свой язычок — подобие LLJS, который бы компилировался и в JavaScript и JVM байткод, гоняя байты туда-сюда по off-heap memory / typed arrays. К слову, если бы такой язык существовал (а LLJS требует еще много работы), то скорее всего я бы его взял и закрыл вопрос. Но тогда бы не было данной статьи, и, возможно, я бы так и не нашел лучший в мире язык программирования.
В дополнение к более подходящим под задачу языкам, большие надежды я возлагал на go, который pass by value в отличии от JVM-based, да и memory model в нем попроще и попрозрачнее. Но вот когда мы начинаем компилировать в «традиционный» JavaScript (gopherjs), который как бы недалеко от JVM в частично интересующих меня низкоуровневых вопросах — производительность проседает раз в 20 (ради интереса можно глянуть на печаль наивного чувака из конторы, которая решила что сделает аналог React.js только очень быстрый, потому что go, и будет писать классный UI)…
Что-то я уже начал сливать горячо любимый мной JVM, а пока рано. Сначала нужно разобраться высоким уровнем: Scala и прочими друзьями, но это уже в следущей части.