Как мои проблемы с памятью привели к созданию синтаксиса, который невозможно забыть
Около 10 лет назад у меня начались серьёзные проблемы в ментальной сфере, в том числе с памятью {впрочем, в этом есть и свои плюсы: например негативные эмоции [злость на кого-то, раздражение, обида] забываются так быстро, что практически полностью перестали меня беспокоить}. Я просто физически перестал понимать всякие сложные штуки вроде графических API или каких-то объёмных библиотек, а при выполнении рабочих задач столкнулся с такой проблемой что к концу прочтения текста какой-нибудь не самой короткой задачи я забывал начало этой задачи (так что мне приходилось перечитывать условие задачи много раз чтобы хоть как-то запомнить его).
Несмотря на то, что к этому моменту я уже закончил разработку графического движка для одного [впрочем не слишком коммерчески успешного] игрового проекта, на меня накатывала апатия и депрессия, и не удивительно — что толку быть разработчиком движка, код которого ты просто перестал понимать (а о возможностях его [графического движка] совершенствования и говорить нечего).
Вскоре так получилось, что компания Katauri, в которой я работал, фактически прекратила свою деятельность и я уволился. В результате, я совсем перестал программировать, что вгоняло в депрессию ещё сильнее. Более 2-х лет я вообще не работал и не искал работу (обстоятельства так сложились, что я жил далеко от всех своих родственников и у меня была достаточная финансовая подушка [лет на 5], что позволяло скрывать от всех своё положение), пока в начале 2016 не случилось событие [смерть моего отца], которое резко изменило мою отшельническую жизнь — я прилетел домой на похороны, и вскоре решился сказать родственникам, что я не работаю с 2014 года.
В это же время [в начале 2016] у меня стали появляться идеи для нового языка программирования, которые я просто складировал в отдельный текстовый файлик. Вначале я не придавал этому большого значения (в конце концов, мало кому нужен просто ещё один язык программирования, и я понимал это), но впоследствии оригинальных идей получилось достаточно много, так что я решил попробовать заняться этим всерьёз, сделав упор на продуманность синтаксиса языка.
По мнению многих программистов, синтаксис языка программирования не так важен, или даже более категорично:
youtu.be/Nlqv6NtBXcA? t=1m50s:Syntax is the least important aspect of programming language design.
Я подозреваю, это от того, что обычным программистам не составляет труда просто запомнить «как надо» и всё. А мне — составляет [причём порой очень большого труда]. Поэтому при разработке синтаксиса я вынужден был опираться не на память, а на логику. Так, практически все элементы синтаксиса нового языка имеют/получили рациональное обоснование их выбора. Остаток данной статьи я посвящу перечислению наиболее значимых обоснований выбора элементов синтаксиса, которые [эти обоснования] не встречаются в других статьях (таких как «Разработка когнитивно-эргономического синтаксиса для нового аппаратно-ориентированного языка программирования») и в документации к языку. [Про сам язык можно прочитать на его странице в Википедии.]
Почему аргументы функций по умолчанию константны, а переменные — нет, разве это не приводит к несогласованности, упомянутой в документации языка программирования D?
Ну переменные на то и переменные, что могут изменяться, а аргументы — это другое слово. Но самое главное почему допустима такая «несогласованность» — если при объявлении переменной абсолютно ясно что означает её изменяемость, то в случае аргументов функции такой ясности уже нет: возможно, что меняться будет копия переменной [передача по значению], а возможно, что меняться будет сама переменная, переданная в функцию [передача по ссылке]. Поэтому в 11l используются квалификаторы: =
для копирования значения, &
для передачи по ссылке, а в случае отсутствия квалификатора аргумент передаётся по константной ссылке (либо по константному значению, если размер аргумента не превышает размера указателя [например если аргумент целочисленного типа {т.к. использовать [константную] ссылку в данном случае менее эффективно}]).
Почему глобальные функции и типы не требуют префикса :
, а глобальные переменные требуют?
Потому что глобальные функции и типы — это нормально, а глобальные переменные — это не очень хорошо.
Почему a.len
/sum(a)
/a.map(f)
, а не len(a)
/a.sum()
/map(a, f)
?
В 11l используется кратчайшая запись:
a.len
len(a)
a.len()
sum(a)
a.sum()
a.map(f)
map(a, f)
И кроме того, функции вроде sum()
(any()
, all()
, product()
, min()
, max()
) всегда финальны [в отличие от map()
и filter()
].
Почему print()
в 11l не поддерживает запятую для вывода нескольких переменных как в Python?
В Python запятая полезна для вывода нестроковых переменных:
print(a, b)
Альтернативные записи (print(str(a) + ' ' + str(b))
или print(f'{a} {b}')
) более многословны.
Но в 11l можно писать так:
print(a‘ ’b)
И к тому же, в языках программирования нет консенсуса по символу разделителю — в некоторых языках (например Python, Swift, JavaScript (console.log()
)) используется пробел [по умолчанию], в других ({PHP (echo
), Ruby, Go (fmt.Print
), Pascal (write
), D (write
), Perl, Julia, Nim (echo
)}) — пустая строка, а в Lua и Basic вообще используется табуляция {а точнее в Basic используется print zone из 14 или 16 пробелов, и пробел или пустая строка при использовании разделителя ;
}.
Почему запись x, y = i, j
не поддерживается (и необходимо писать (x, y) = (i, j)
)?
Потому что её можно спутать с записью int x, y = i, j;
в Си [и её аналогом Int x, y = i, j
в 11l], которая обозначает совсем другое.
[В Python запись (x, y) = (i, j)
также корректна.]
Почему return a, b
не поддерживается (и необходимо писать return (a, b)
)?
return a, b
у меня ассоциируется с возвратом функцией множества значений, хотя в Python это не так — реально возвращается кортеж (одно значение типа tuple), в чём можно убедиться через print(type(f()))
. (Что я имею в виду под возвратом множества значений: ну, например, если функция bar()
возвращает 1, 2
, то вызов foo(bar())
означает foo(1, 2)
[так это работает например в языке Lua], а если возвращает (1, 2)
, то означает foo((1, 2))
.)
Почему write_bytes()
, а не просто перегруженная write()
?
Для симметрии с read_bytes()
.
А почему read_bytes()
?
Сделать как в Python {то есть, чтобы в зависимости от режима открытия файла (b
или t
) менялся тип возвращаемого значения функции read()
} в 11l не получится из-за статической типизации.
Почему null
, а не none
или nil
?
Потому что есть nullable-типы, а не noneable.
А нельзя было обойтись без префикса @
?
Можно, но я решил использовать префикс [ради эксперимента (улучшится с ним читаемость кода или наоборот)], так как отказаться от него в будущем в принципе вполне возможно, а вот добавить впоследствии — точно нет.
Почему для while-циклов используется ключевое слово loop
, а не for
как например в Go?
Для цикла while (while loop) логичным является либо while
, либо loop
, но никак не for
.
[А в Go, видимо, сделано по аналогии с Си с его универсальным for
(for (;;)
для бесконечного цикла и for (;condition;)
как синоним while (condition)
).]