Немного о лунном.
Лунный примечателен тем что это очень простой язык. Несмотря на такие языковые возможности как анонимные функции и замыкания это очень традиционный процедурный язык. Языковые конструкции в нём означают примерно то чего от них и ждёшь. Его простота столь велика что определённым образом провоцирует беспечность программиста. В следствие этой беспечности столкновения со специфичными для языка вещами обычно бывают особенно болезненны и полны детской обиды. Здесь перечислено несколько элементарных моментов, столкновение с которыми у программиста не на лунном может вызвать недоумение и предварительное ознакомление с которыми должно упростить вхождение в язык тем кто так и не прочёл документацию1:
Массивы индексируются начиная с единицы2.
v = { 0, 1, 2, 3 } for i = 0, #v do print( v[i] ) end -- nil -- 0 -- 1 -- 2 -- 3
Все переменные глобальные, если не указано что они локальные3.
x = 1 y = 13 z = function() x = 0 local y = 0 end print( x, y ) z() print( x, y ) -- 1 13 -- 0 13
Захват переменных в область видимости (в том числе и в замыкания) осуществляется по ссылке или по имени4. Таким образом можно невозбранно модифицировать переменные из замыкания в которое они захвачены. Но при передаче значения в функцию в качестве аргумента создаётся новая локальная ссылка и изменения переменной во внешней области видимости происходить не будет5.
x = 1 y = 13 z = function( v ) v = 0 y = 0 end print( x, y ) z( x ) print( x, y ) -- 1 13 -- 1 0
Если инициализировать локальную переменную анонимной функцией, то она не будет доступна внутри области видимости анонимной функции. Таким образом мы вполне можем вызывать такую функцию рекурсивно6.
f = function( x ) f( x ) end -- Всё в порядке. Путь к переполнению стека открыт. local f1 = function( x ) f1( x ) end -- Всё плохо. local f2 f2 = function( x ) f2( x ) end -- А вот так, как не странно, всё хорошо.
В lua свои собственные особенные регулярные выражения7.
- Эскейпинг магических символов осуществляется при помощи ‘%’.
- Символы пунктуации нуждаются в эскейпинге.
- ‘-’ это такой ленивый ‘*’.
- Ну и расширений по мелочи.
Знак неравенства. Поскольку все современные промышленные языки программирования так или иначе произошли от C (Java и C#, например), у программиста нет сомнений относительно того как должен выглядеть оператор неравенства — !=. А между тем из числа арифметических операторов и условных операторов форма этого оператора пожалуй наиболее непостоянна: /= в Haskell, <> в Pascal и PHP. лунном неравенство это неожиданно ~=8.
print( 1 != 2 ) -- Ошибка компиляции print( 1 ~= 2 ) -- А вот так просто true
Форматированный вывод чисел. Поскольку в лунном языке нет целых чисел и вместо них используют числа с плавающей запятой двойной точности, то переполнение величины в 251 приводит к потере точности целой части. Однако при преобразование числа в строку, переход от целочисленной к экспоненциальной записи происходит раньше этого предела. Этот переход ошибочно воспринимается некоторыми как потеря точности в целой части, хотя это не так и чинится настройками форматирования.
print( 2 ^ 51 ) -- 2.2517998136852e+15 print( string.format( "%.0f", 2 ^ 51 ) ) -- 225179981368528
Nil не может быть последним элементом массива. Если последним элементом массива оказывается nil, массив укорачивается на этот элемент.
list = { 1, 2, 3 } list[2] = nil print( table.unpack( list ) ) -- 1 nil 3 list[3] = nil print( table.unpack( list ) ) -- 1 print( #{ nil, nil, nil } ) -- 0
Также если вы кондовый сишник, вам безусловно очень понравятся begin и end, но это уже совсем другая история.
P.S: Запись основана на реальных событиях. Каждым из пунктов прострелил себе колено я или кто-то из моих знакомых.
P.P.S: Продолжение следует.
Важно понимать, что никакой тайны из этих вещей не делается. Наоборот, все эти вещи описаны в официальной документации к языку. Она у него кстати довольно короткая. Просто все её читают в лучшем случае по диагонали.↩
Все глобальные переменные связываются по имени. Если точнее то все глобальные переменные просто элементы хэштаблицы _ENV и связывание с ними это поиск значения в этой таблице по имени. Факт этот настолько поразил меня, что не упомянуть о нём совсем я не мог, хотя он и выходит за рамки обсуждения.↩