lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


hi all! :)

Egor Skriptunoff:
> merge Lua tables and Lua functions in a single data structure

you are searching for the same flexibility that ive found to be an awesome thing to have! :)

1st, note that its not really a suggestion from my side, but a nice topic that im also interested in. however im also not strictly against a language change in a well constructed and widely accepted case, while im afraid that its kinda radical to be a healthy change from the perspective of the community and ecosystem. maybe a fork? in that case i would like to see a luajit fork alongside this :D

[now some related considerations will just come, scroll down to "my current approach:" in the lack of patience...]

actually i use a similar thing as a fund for my universal graph handler, and that i wanna use for an universal parser just as well (and maybe others) but i think its not really needed for everything, so it would bloat the rest of the codebase, while its also somewhat harder to follow...

i even thought about html could be represented as lua tables like the tags and their attributes could take the hash part, and the contents can take the array part

ive thought that it would be a nice idea to make something like an ast to make complex expressions like the conditions of `if` or whatever else, but when ive tried to give it a shape to see how it would look like, it became a huge brainkiller mess from a relatively short but complex _expression_, so i gave up that idea, or better said, kept that for a theoretical need of the future... :D

ive also checked out languages like smalltalk, lisp and whatever more homogeneous and accessible languages, but i think they wont ever be as tasty and good as lua is...

ive thought about text snippet based functions, where i can juggle with arbitrary snippets, concat and eval, but i didnt go farer with that approach, cuz ive found my current base friendlier, while it is still a valid path that may worth a try, and it can have optimal results. maybe one day i will find myself taking this path, but actually this whole topic requires kinda much well-filled "brain-ram" as coding complex stuffs in brainf*ck :D (well, thats just a Turing machine with io, so it does worth the fun (and the died brain cells) and can take one to the next level of codefoo :D ) ... so i mean it has really much important considerations to keep in mind at once to find the ideal funds for such a thing to do it the right way, and probably i had valid considerations against this path, but currently i dunno any, and maybe this would be the right path performance-wise...

actually its not a new idea, one of my relatives recently told me that he did something similar in nodes (it was previously called to be lotus if im right; and its an ibm toy) with insert points that can also skip the hardwired variants of the same tasks, and i think even simple callbacks are a form of playing the same game...

the flexibility of self-modifying code is a thing that ive thought much before, but actually keeping around some state and having a code with branches is sufficient if the codes wont be created in runtime (either programmatically, or as a result of live-coding; and luajit can take good care of cleaning up). if they will be created, then i think live-patching is sufficient, but its totally not necessary to make that happen below the level of functions, but changing a function requires only some planning, to avoid making a mess by localized outdated functions

my current approach:

so my actual implementation have been made with a supervisor/assembler or call it as u like it, i call it `toDo()`, thats just calling a list of functions with a table as a shared state, where the functions are components, and actually its limited to a single "scope" . the real functions are named (yep, they are in the hash part, therefore unordered) and there are the "assembler" tables (for different options, but they could be the same) that will be an array of their names (or anon functions, that i dont use just like that).

so it can take a table and call itself on its components, a string to look up the related function, or a function to call (other things and "lonely" strings are ignored, but can be printed for debugging, or could stop the process, but who cares, when live-coding will result in kinda well-tested codes :D ), and for sure, it gets the shared state and the lookup table with the actual functions.

i wanted to make it more complex, like the ast approach above, and i wanted to share the state for multiple levels, and let it control its own flow, but actually the shared state can contain anything to force returning immediately from functions that arent necessary (yuck, suboptimal, but its already complex enough, so i didnt mess with it), "scopes" can communicate via the shared state, and they are just a matter of calling `toDo()` again from a function.

manipulating hard-to-touch things like conditions, that ive mentioned above is just a matter of a whole alternative function, so i can decide to pick either of them without messing an ast. this way components can be added, removed, reordered and exchanged, but its already somewhat more complicated and bloated than what i would like to see, so i only did it cuz this way i can have a common ground for multiple complicated stuffs, that can have really various use cases an needs, so its about flexibility and against repetition, instead of speed, but actually i have sufficient performance (on a single thread of an i3 with 1.4ghz) for using my graph handler for serializing data to save before run things in live-coding, as well as to dump `_G` (with tekui inside) without time issues, so it can also handle reasonably much elements without pain... (btw "batteries and python": lol, i started my app in python, i can remember how slow and complicated it was while i was much nearer to the "hello world" level of complexity X'D i think the rationale of the whole existence of python is to keep bloatware-makers away, thx Guido &co! :V (i really liked python before ive found lua ... out of need that python failed to suffice... :D  (sorry for being rude)))

back to the topic, i have much ideas around this that i dunno if they would bring joy or pain, but currently i think its best if the need will guide me forward into more complicated stuffs... one thing that im still thinking about more seriously is to make return values that can control the traversation of those assembler tables, but probably its still faster to return from some functions early based on the state than checking return values everywhere, and an another is that the lookup tables for the real functions arent really much flexible, and sometimes i would need to access the same "pool" from different places with different lookup tables, but currently i just address those instead of writing pretty strings, while merging the whole "pool" together would make some mess...

and finally, on the one hand, i hope i could share some valuable mental food, and on the other hand, i hope that you, folks, will come up with even more crazy ideas, as manipulating the internals of "functions" is really much of an interesting topic! :)

all the bests to all of u, especially to Dirk, who isnt even that far from here as some would think! :) (we dont _have_ souls, we have bodies! ;) )



Sent with ProtonMail Secure Email.

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On 2020. January 18., Saturday 8:43, Egor Skriptunoff <egor.skriptunoff@gmail.com> wrote:

On Wed, Jan 15, 2020 at 11:44 PM Dibyendu Majumdar wrote:
Mixing arrays and maps in a single data structure was a big mistake in my view!


Merging arrays with dictionaries is a step toward making Lua
both compact and powerful.
It has brought some minor problems to the language;
but IMO the step looks correct.

It seems that there is a possibility to make next step in that direction:
to merge Lua tables and Lua functions in a single data structure.
You may have noticed that there is a similarity between how we
construct an array and how we define a function:
   arr = {11; 22; 33}
   function func() local x=42; x=x*x; return x; end
In both cases, it looks like we store a sequence of elements in a container:
in the first line we store numbers, in the second line - Lua statements.
Assuming we have new basic data type "statement",
a function definition may be treated as an array constructor.
So, "func[2]" would be the statement "x=x*x"

Dictionary seems to be a right structure to store
a set of local variables defined inside a function.
For example, we could use _expression_ "func.x" to access
internal variable x which equals to nil before invocation of the function
and equals to 42^2 after invocation.
Actually, these variables would not be "local" anymore
as they could be accessed from outside of the function.
Nested statements, such as "if a then b=b+1 else print(c) end",
are similar to nested tables.
We should consider "b=b+1" as a nested function inside the outer function.
Assuming "func[5]" is the statement "if a then b=b+1 else print(c) end",
we could obtain "b=b+1" by "func[5][1]".



In other words, a function contains its statements (in form of AST)
in its "array part" (in positive integer indices)
and contains its local variables in its "dictionary part" (in fields).

A bonus:
1) A function could modify its own code on-the-fly
by writing to its own "array part".
2) By indexing an inner block "func[2][3][4]" we could obtain access to
its local variable "func[2][3][4].z" which is usually inaccessible
due to lexical scope rules.
(thanks for reading this crazy idea)