Fingercomp 4 409 Опубликовано: 3 сентября, 2016 Начнём сразу с кода. Пихнём в файл ./lib.lua local a = "Hi" local b = "World" return { a = a, b = b } Вполне себе нормальный, имеющий право на жизнь, код. Не то, что бы он делал что-то полезное, но как пример нашей дискусси вполне сгодится. Итак, этот небольшой файлик будет возвращает таблицу с двумя ключами. Подключим его (./test.lua): local test = require("test") print(test.a, test.b) Выведет это "Hi World" и успокоится. Вроде всё нормально. Допишем в этот файл ещё немного кода: test.a = "Goodbye" b = "Cruel World" test2 = require("lib") print(test2.a, test2.b) Выведет это, однако, Goodbye Cruel World. Упс. Если в таблице будет реализация бомбёжки ракетами по союзникам (а как же), изменять что-то не хотелось бы совсем. Вот об неизменяемости речь и пойдёт. Заметим, что в таблице либы ключам значение присваивается не напрямую, а через переменную. Локальную. Доступа к ним (проигнорим debug) ни у кого другого нет. С другой стороны, у Луа есть метатаблицы с метаметодом __index. Воспользуемся этим, прямолинейно: local a = "Hi" local b = "World" return setmetatable({}, { __index = function(self, k) if k == "a" then return a elseif k == "b" then return b end end }) Код ./test.lua можно даже не менять. Результат всё равно будет тот же. Ибо __index вызывается только для несуществующих значений основной таблицы. Когда мы присвоим какое-то значение, вызываться не будет уже метаметод. Ага, значит, давайте запретим заменять таблицу. При tbl.keyname = value вызывается метаметод __newindex. Окей: local a = "Hi" local b = "World" return setmetatable({}, { __index = function(self, k) if k == "a" then return a else return b end end, __newindex = function(self, k, v) print("No way!") end }) Теперь, если мы запустим код тот же, получим что-то вроде этого: Hi World No way! No way! Hi World Воооот, вроде бы цель достигнута. Как бы не так. Заменим файл ./test.lua этим: local test = require("test") print(test.a, test.b) rawset(test, "a", "Goodbye") rawset(test, "b", "Cruel World") test2 = require("lib") print(test2.a, test2.b) Угадайте, что получится. Конечно же, большой и длинный "ууупс". Hi World Goodbye Cruel World Более того, теперь эти значения сидят в обычной таблице и больше не вызывают __newindex. Вот печаль-то. Но тем не менее, именно такой код мы и оставим. Для решения проблемы нам потребуется переопределить rawget и rawset, добавив проверку на наши любимые таблицы и не давая ничего изменить. Получится это сделать только для систем с доступом к контролю над _G. Есть ещё вариант докопаться до сути: getmetatable и setmetatable. Их, как можно догадаться, тоже требуется переопределить. Туда же debug.getmetatable и debug.setmetatable. После этого можно будет, наконец, сказать. что мы полностью уверены, что наши таблицы константны. Как видно, Луа всеми силами пытается забрать право на забирание динамичности структур. Позволяя стандартно переопределять внутри VM стандартные функции для своих нужд, И просто так отплясаться не получится. Шмактус, однако. 3 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
SergOmarov 34 Опубликовано: 4 сентября, 2016 (изменено) Велосипед, кроме идей переопределить rawget и rawset, getmetatable и setmetatable: уже видел на форуме реализацию функции const для создания неизменяемых переменных по тому же принципу --- Нашел эту тему: http://computercraft.ru/topic/1645-oc-konstanty/?hl=const Изменено 4 сентября, 2016 пользователем SergOmarov Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fingercomp Автор темы 4 409 Опубликовано: 4 сентября, 2016 Одно дело — увидеть минифицированный код бещ комментариев или пояснений, а другое — получить само объяснение механизма, и в нужном разделе. Разные вещи, нет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
SergOmarov 34 Опубликовано: 4 сентября, 2016 Код нужно писать таким образом, чтобы комментарии не требовались. Однако документация к такому подходу все же должна быть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
NEO 542 Опубликовано: 4 сентября, 2016 Код нужно писать таким образом, чтобы комментарии не требовались. Однако документация к такому подходу все же должна быть. Комментарии не просто так придуманы. Они и есть документация. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Totoro 3 563 Опубликовано: 4 сентября, 2016 Комментарии не просто так придуманы. Они и есть документация. Разные подходы есть. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
SergOmarov 34 Опубликовано: 4 сентября, 2016 Комментарии не просто так придуманы. Они и есть документация. Документация в виде комментов нужна только возле определений полей(и многие ide юзают это для быстрой справки). Зачем их писать после каждого действия? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах