The URL points to my shoddy attempt at getting a not-so-useless REPL. This thread will attempt to explain my opinions on the state of REPLs in IDE.
My REPL fever started from a rather quaint encounter with VSCode wherein I realized that you can have a global split for an REPL which was damn cool because I did not have to fumble with opening powershell/bash in a separate window to treat scripting languages Python as a compiled language by repeatedly running the file in a different window. But the pain did not go away. It was difficult to rapidly prototype functions and still use the editor. Enter emacs and vim and their term-mode equivalents. As I was getting into learning elisp, I realized that I can use a global hash-table to track terminals mapped to their buffers. Then came the second annoyance of not having a global shell as a split window. I was stuck with 20 terminals for 20 buffers which became a pain in the ass so naturally I mapped major-modes/filetypes and voila! It solved the headache for a few years of my learning phase in programming and I was having a really good workflow of using vim/emacs and sending input to the terminals.
Fast forward to few years later where I was tired of writing nested table functions for my favorite scripting languages aka ruby, lua and Python (at that time). What was the solution? Make a library. Now this library was naturally in line with package structures which is a flat structure - source files are usually stored in subdirectories. A global REPL fails here because of constant chdir() in all REPLs causing a mess in workspace buffers. The solution? Need an REPL that automatically chdirs into workspace root so all imports work like they are supposed to with the only other solution using lua's loadfile() which is then required to be changed into a qualified import name manually. This has the additionally overwriting global namespaces over and over, so stateful APIs break while testing. Second thing to remember is that if there is not a workspace based REPL, it becomes practically useless as none of the evaled functions can be tested in the presence of other functions. This circles back to the stone age method of using two windows - one editor and another for doing the retardation of typing the same command or spamming Ctrl-n, Ctrl-p to run the same shit over and over again.
Lastly, we also need buffer-local REPLs and CWD-local REPLs if in base we are not operating in a workspace. The URL is my solution which provides everything that I mentioned. The nvim-lua equivalent is here - https://github.com/caligian/nvim-utils/blob/master/nvim-util...
I have begun to liken elisp more after spinning some of my own utils.el. I am currently replicating my libraries from https://github.com/caligian/nvimconfig (only adding URLs for code examples)
The godforsaken perrenial problem of not having functions to deal with nested structures which are the bread and butter of stateful configurations, I was able to solve using nested table functions like I did in lua which made writing coherent configs much easier.
Apart from learning to use cl-labels for recursive lambdas and let-binding efficiently, I was able to quickly get productive with a custom API for stuff that does not have general-define-key and add-hook littered around. These features alongside emacs's more accessible API and baked in list and hash-table operators has made life easier. I can effectively throw around hash tables in place of alists which is what used to put me off emacs lisp but ht.el and some functions of my own greatly made me happy. Furthermore the fact that every last statement returns some value is just too good to make emacs a lisp REPL. That used to be the biggest annoyance in testing lua code for neovim functions. So I am super happy with that. The cherry on the cake for finally making a worthwhile REPL library that respects the project workspace. Now it feels right at home with a generic REPL library to use REPLs with any language as long as it has an REPL command. Similarly in contrast to neovim, emacs is lacking a code formatter plugin, similarly a vim-dispatch style plugin to quickly run predefined compile commands. After getting a grip on macros and making a use-package style macro, life became easier as now I could define formatters, compile commands all in the same place like use-package. After fiddling with gensym, I managed to make hygenic which made life easier for making future DSLs to map to objects or hash tables.
The best thing about macros is code generation in a specified way. In lua while making the API for neovim, table DSLs became a pain to write especially with all function definitions lying around and they barely looked like DSLs but deeply nested tables as they grew in depth. With macros, I can send around symbols without worrying about syntax errors. That makes things so much better when you can store code so easily instead of writing one dozen closures to store state. The biggest learning curve was the macros although I cannot proclaim that I am an intermediate at this, still a rookie but learning macros will make life with easier code generation when you can always pass around code in lists, manipulate the code and also eval them even in a function than a macro. Emacs lisp is enough competent with lua for configuration despite the lack of modules. Once you make clean functions and decide on handling only global state then it is as good as a lua module plus the able to grep all functions quickly.
So my question is this. Why are people still shitting on emacs lisp?it is a perfectly good language given lexical binding is completely useable? I suppose people look at nested alists and nested tables and for the latter. A-lists are not difficult to deal with but the constant cadr to get a value becomes quickly annoying
When you register local variables, they are merely defined as register locations and have a default value of nil which is absence and hence memory saved. They would have to mark nil explicity as a new data structure which is probably wastage as they would have to allocate memory for every variable declaration that may or may not be used.
It is just nil, nil at a literal level with the exception being local variables which are handled differently as offsets to register locations than other dynamic languages without such 'local' qualifiers.
That should explain why variables can be nil but not ta les. You can hash nils but it would take up memory. I don't think it's logical to use memory for something you are already marking as absent. Why not use false instead?
As far as security is concerned, consider this example. I want to use erlang with lua. Those two are miles apart but not really when you boil everything down to a lua table. All containers are tagged tables such as having a metatable key saying 'tuple' or 'struct'. Then you serialize them back and forth via BIFs. Any value having a function will reject entire query. Furthermore a simple hash code can be forwarded after sending the data. The attacker would have to sync the client and server and make hash changes on both ends but since he cannot fuck with the server none of his tampering would work because it will be outright rejected. As far as transformer modules (aka configs) are concerned, they will be carried out AFTER the hash.
If lua is used only as an adapter, that is an intermediary between the client and host converting objects to table and vice versa. You cannot dump function definitions (hence only serializable) except in bytecode. Who'd pass that around? You can store code as pure function strings and eval them as a module to provide a transformer module. Certainly a hash can be embedded in the code or sent over the server to prevent tampering with no security headaches
Let's take another example. Consider structs as tagged tables with a metatable key that distinguishes it from ordinary tables. You can implement inheritance as chained __index closures for parent tables or simply chained tables. Or you can use the struct as is by defining a global table and creating a simple lookup. Theoretically the lookup will work faster because you can store the hierarchy as an list, run a simple index() to get the needed parent and call the method in the associated table. This is much faster than going to multiple chained tables thus slowing down lookup.
Another example is python iterators which requires a separate instance with __next__ method. It is not generic because now you can create n instances for n dicts just to use it in for syntax. Whereas in lua it is a simple closure returning the next value until nil
Far from defending the lang's honour. There are many noteworthy things about lua. Firstly it encourages you to use query-able data structures. Lack of first class objects makes marshalling extremely easy. This is similar to using elixir which only as dicts, lists, tuples and structs. Arguably elixir is even simpler than lua when it comes to describing data because of lack of ANY OOP features that makes the object opaque with getters and setters
The former uses the latter for nvim. And the latter makes lua perl with structs. We all loved perl for its lispy functions to deal with lists - grep, map, push, shift, unshift, etc. Nested ops are inspired by elixir.
While attempting to teach callbacks to a room full of C# devs i figured lua was the easiest for creating readable examples. The language has very good teachable aspects. I'd pick lua over python as a teacher to teach data structures
Using a table is still simpler because people literally use dicts everywhere without actually thinking of them as containers but only as 'lookup containers'
This is one of the things i was talking about. You cannot map nil to a key because nil means absence. The compiler can only infer such absence at a control flow level aka passing arguments to functions or checking nil-variables. You are supposed to use false in such a case here
My REPL fever started from a rather quaint encounter with VSCode wherein I realized that you can have a global split for an REPL which was damn cool because I did not have to fumble with opening powershell/bash in a separate window to treat scripting languages Python as a compiled language by repeatedly running the file in a different window. But the pain did not go away. It was difficult to rapidly prototype functions and still use the editor. Enter emacs and vim and their term-mode equivalents. As I was getting into learning elisp, I realized that I can use a global hash-table to track terminals mapped to their buffers. Then came the second annoyance of not having a global shell as a split window. I was stuck with 20 terminals for 20 buffers which became a pain in the ass so naturally I mapped major-modes/filetypes and voila! It solved the headache for a few years of my learning phase in programming and I was having a really good workflow of using vim/emacs and sending input to the terminals.
Fast forward to few years later where I was tired of writing nested table functions for my favorite scripting languages aka ruby, lua and Python (at that time). What was the solution? Make a library. Now this library was naturally in line with package structures which is a flat structure - source files are usually stored in subdirectories. A global REPL fails here because of constant chdir() in all REPLs causing a mess in workspace buffers. The solution? Need an REPL that automatically chdirs into workspace root so all imports work like they are supposed to with the only other solution using lua's loadfile() which is then required to be changed into a qualified import name manually. This has the additionally overwriting global namespaces over and over, so stateful APIs break while testing. Second thing to remember is that if there is not a workspace based REPL, it becomes practically useless as none of the evaled functions can be tested in the presence of other functions. This circles back to the stone age method of using two windows - one editor and another for doing the retardation of typing the same command or spamming Ctrl-n, Ctrl-p to run the same shit over and over again.
Lastly, we also need buffer-local REPLs and CWD-local REPLs if in base we are not operating in a workspace. The URL is my solution which provides everything that I mentioned. The nvim-lua equivalent is here - https://github.com/caligian/nvim-utils/blob/master/nvim-util...