@ProLua

Страница 181 из 307
Elias
28.09.2017
17:00:15
Есть

Philipp
28.09.2017
17:02:55
Я чего-то подвис на __index

tree.__mt = { __index = function(self, key) return self.__data[key] or self[key] or tree[key] end, __newindex = function(self, key, value) self.__data[key] = value end }

При вызове какого-нибудь метода созданного объекта, переполнение стака

Google
Philipp
28.09.2017
17:03:40
И я в упор не вижу ошибку переопределения __index

Elias
28.09.2017
17:04:01
Потому что tree.__index вызывается, а там tree[key], который не существует, поэтому снова вызывается __index

Philipp
28.09.2017
17:04:30
Так tree[key] существует, вот

Elias
28.09.2017
17:05:30
__index в итоге вызывается когда-нибудь или нет? Наверное из-за него stack overflow?

Philipp
28.09.2017
17:06:29
В __index

Именно в нем переполнение

Elias
28.09.2017
17:07:00
local tree = { f = function() print("HELLO") end } tree.__mt = { __index = function(self, key) return self.__data[key] or self[key] or tree[key] end, __newindex = function(self, key, value) self.__data[key] = value end } print(tree:f()) Вот это работает

Philipp
28.09.2017
17:07:02
А, кажись, понял

Не

tree:f работает

А вот если вызывается не напрямую, а через объект

Щас полный код кину

https://pastebin.com/Q82Xtx2z

Google
Philipp
28.09.2017
17:08:06
Во. local tree_obj = tree:new() tree_obj:addChild() – stackoverflow

И я кажись понимаю. tree_obj вызывает свою метатабличку, которая ищет в self[key]. Я не уверен, но возможно он снова вызывает self.metatable.__index

Elias
28.09.2017
17:11:26
Просто тут нужно все функции таблицы tree копировать в obj, когда tree:new() вызывается

Иначе у создаваемого объекта не будет addChild ключа и функции

Philipp
28.09.2017
17:12:04
Да, я был прав

Как-то нужно избавиться от цикла в self[key], и оно будет работать

Saphire
28.09.2017
17:14:40
rawset

Или как оно там

Philipp
28.09.2017
17:14:45
Ага, уже тоже про него вспомнил

rawget, наверное

Вот так работает

Snusmumriken
29.09.2017
01:21:45
Иначе у создаваемого объекта не будет addChild ключа и функции
__index - это как раз такая штука, которая придумана "чтобы не копировать". Если плодятся тысячи и миллионы объектов, копии ссылок на каждый метод у каждого объекта занимают нехило памяти, и требуют время на копирование. Присобачить одну ссылку на метатаблицу быстрее, чем дублировать сразу много ссылок по списку. И сериализовать объекты исключительно с данными - проще. Хотя и доступ теоретически чуть быстрее (не вызывается __index). Поэтому у очень мелких объектов с одним-двумя методами (которые не надо сериализовать) эффективнее копировать методы, а у объектов с кучей методов которые не очень часто вызываются - эффективнее ставить метатаблицу с __index. Но это уже "низкоуровневые оптимизации", а тебе я советую изучить метатаблицы, отличная штука : )

Elias
29.09.2017
08:12:07
Да, что-то я забыл о том, как нормально реализовывать ООП после долгого использования библиотеки для этого. :D

Sergey
29.09.2017
08:18:45
а какую либу используешь?

Elias
29.09.2017
08:22:41
https://github.com/kikito/middleclass

Если кто-то раньше не встречал профиль этого парня, советую посмотреть на другие репозитории и его сайт. Тонны годноты.

Snusmumriken
29.09.2017
08:35:46
ClassFoo = {} ClassFoo.__index = ClassFoo function ClassFoo:new(a, b, c) local o = {} o.a, o.b, o.c = a, b, c return setmetatable(o, self) end function ClassFoo:plusTwo() self.a = self.a + 2 self.b = self.b + 2 self.c = self.c + 2 end obj = Class:new(10, 20, 30) obj:plusTwo() ClassBar = setmetatable({}, {__index = ClassFoo}) ...

Ну типа для такой мелочи как ООП - либы не нужны.

Ок. Вот тебе самая короткая реализация ООП с наследованием. Куча магии которая пашет. function Class(name, parent) local smt, gmt = setmetatable, getmetatable local parent = parent local mt, cl = {}, {} mt.__index = type(parent) == 'table' and parent or parent and error('Class inheritance error: table expected got '..type(parent), 2) or nil mt.__call = function(self, ...) return self.init and self.init(self, ...) or {} end -- average call method cl.__name = name or ('class id: %8d'):format(math.random(99999999)) -- name of class for getting cl.__index = cl cl.Inst = function(t) return smt(t, cl) end cl.Super = mt.__index cl.Type = function(self, obj) return type(obj) == 'table' and gmt(obj) == gmt(self) or self.__name end cl.IsObjectOf = function(self, class) return rawequal(class, gmt(self)) end return smt(cl, mt) end

Google
Elias
29.09.2017
08:38:53
Ага Просто у меня в игре и наследование есть, и статические переменные, что несколько усложняет всё К тому же хорошо скрывать детали реализации классов и писать в итоге только local SomeClass = class('SomeClass')

Snusmumriken
29.09.2017
08:40:07
А вот это ты зря, со статическими переменными : ) Попробуй древовидные архитектуры наследования. А если класс - вспомогательный к чему-то - давать ему ссылку на объект, которому он помогает.

Alexey
29.09.2017
08:41:43
Главная проблема при наследовании с приватными данными/методами Что если базовый класс имеет параметр _data и наследуемый класс также определит тот же Это пожно реализовать только через замыкания

Snusmumriken
29.09.2017
08:41:47


Зачем нужна приватность? Объективные причины, а не "ну типа кто-то узнает как оно на самом деле устроено".

Замыкания (и уж тем более - приватность через них) - в 99% случаев избыточная штукенция, которая только жрёт лишнюю память/требует лишнее процессорное время. Ну, это на моей практике.

Elias
29.09.2017
08:45:58
Статические переменные мне нужны, когда в другой части программы кто-то её хочет прочитать. Например, Person.MaxAgeAllowed или что-то типа такого Для приватности использую переменные с подчеркиванием в начале и не использую их потом. :D

Alexey
29.09.2017
08:46:20
Когда количество родителей в цепочке больше 4-5 и каждый из них имеет какие то методы/данные. Очень неприятно когда вдруг понимаешь что вдруг переопределтил какой-то приватный метод :)

Snusmumriken
29.09.2017
08:46:47
Когда количество родителей в цепочке больше 4-5 и каждый из них имеет какие то методы/данные. Очень неприятно когда вдруг понимаешь что вдруг переопределтил какой-то приватный метод :)
Если не хочется чтобы пользователь случайно обозвал кастомную переменную системной фигнёй - указываем свои вещи через "_". Ну, obj._system_var function class:_private_method. Наследование больше трёх означает, что тебе пора что-то декомпозировать. Ты представляешь, какая жопа для окружающих, выяснять, какой из методов ты дёрнул, в твоей бешеной цепочке? Ну, так же как с функциями, длиннее чем 25-30 строк.

Alexey
29.09.2017
08:48:57
так при наследовании в новом классе тоже нужны закрытые данные И класс родителя могу писать не я, а взять из сторонней библиотеки

Sergey
29.09.2017
08:55:53
https://github.com/kikito/middleclass
Спасибо, гляну ?

я у него активно inspect использую ))

Snusmumriken
29.09.2017
08:57:16


Так что если наследуетесь больше двух раз - уже что-то не то, и лучше уж базовый класс изменить.

Elias
29.09.2017
09:03:48
inspect - очень полезная штука для дебага, даа :)

Tverd
29.09.2017
09:21:19
Alexey
29.09.2017
09:24:12
Приватные методы/поля которые нельзя изменить/прочитать в наследуемом классе достаточно необходимая вещь

C++ overload vs override

и правила видимости для членов классов

Snusmumriken
29.09.2017
09:25:20
"Достаточно необходимая" - это фигня, я хотел конкретных примеров с доказательством, почему имеенно так надо, а не иначе. Ну и, желательно, примеров, где НЕОБХОДИМО использовать цепочки из более чем трёх наследований.

Google
Tverd
29.09.2017
09:28:47
как говорил сам Роберто, хотите приватных методов - делайте локальные функции в модуле

Snusmumriken
29.09.2017
09:33:07
Нене, тут имеются ввиду приватные поля, например: ClassFoo = {} ClassFoo.__index = ClassFoo function ClassFoo:new(a, b, c) local o = {} local private = {} o.a, o.b, o.c = a, b, c function o.getPrivate(key) return private[key] end function o.setPrivate(key, value) private[key] = value end return setmetatable(o, self) end И типа табличка private - "скрыта от глаз", вся фигня, и только парой методов его можно достать. Но я всё ещё не вижу объективной необходимости так делать :< Складывается впечатление, будто программисты - параноики, которые такие: "Ха! Он больше не узнает что это за метод даже если попробует пройтись по всем полям таблицы! Какой я молодец, скрыл реализацию! Больше никто-о-о-о-о не узнает как оно работает!". Ну ёпт, пользователь либы в любом случае найдёт способ всё сломать. Пущай читает доки, там написано как использовать.



Tverd
29.09.2017
09:40:07
Понятно что можно и так, я говорил про то, что Роберто в книге написал. Типа пользуйтесь вот так.

Snusmumriken
29.09.2017
09:40:14
Угу : ) Благо логично и достаточно просто.

Group Butler [beta]
29.09.2017
15:30:14
Добро пожаловать в чат pro.lua, Alexey! Ознакомься с правилами чата (в описании и прикрепленном сообщении), и присоединяйся к обсуждению.

Добро пожаловать в чат pro.lua, Андрей! Ознакомься с правилами чата (в описании и прикрепленном сообщении), и присоединяйся к обсуждению.

Ixtis
29.09.2017
18:04:58
https://mihacooper.github.io/effil/lua/2017/09/28/effil/

annelin
29.09.2017
18:31:08
а чем это лучше coroutines?

Ixtis
29.09.2017
18:31:34
Самому интересно

Snusmumriken
29.09.2017
18:35:35
Это похоже на настоящие потоки с расшаренными таблицами.

Влад
30.09.2017
20:18:49
а как мне получить данные внутри программы, если я хочу сделать echo "test" | program.lua?

Snusmumriken
30.09.2017
20:21:33
Смотря в какой период исполнения. Как именно запускаешь? Что происходит при выполнении команды 'echo "text" | program.lua'?

Потому что ты можешь сделать, например, логирование, которое сбросит абсолютно всё что тебя интересует в файлик. Или ты можешь влепить debug.debug() в нужную точку, и вывести то что нужно самостоятельно ручками, поставив программу "на паузу" (продолжить исполнение - cont).

Elias
30.09.2017
20:25:00
Что-то типа того, нет? #/bin/usr/lua local args = { ... }

Snusmumriken
30.09.2017
20:25:13
Там уже есть табличка arg со всем, что передали при запуске.

Влад
30.09.2017
20:27:07
не

Я хотел получить данные через linux pipe. Вот так работает: for line in io.lines() do result = line end

echo "text" у меня выдает в stdout некие данные, а я хотел их получить в скрипте lua

Snusmumriken
30.09.2017
20:28:27
Для linux pipe подключай posix.

Google
Влад
30.09.2017
20:28:53
да зачем, у меня уже работает через io.lines()

Snusmumriken
30.09.2017
20:31:27
Ок. Тогда делай print.

annelin
01.10.2017
00:07:33
тогда делай print ⓒ

Страница 181 из 307