caligian
caligian on Hacker News
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...
Posted by
caligian on Thursday October 24, 2024 @07:52AM
from the self-post dept.
I have always felt that doom-emacs and doom-nvim are imcomplete frameworks. Both of them have an obsession with lazy-loading and deferring packages which always goes wrong. I got horribly annoyed with nvim-surround's inability to set the keybindings after directly opening a file rather than just nvim and doom emacs kept breaking after small workflow changes. As an experiment, I tried...
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
Posted by
caligian on Monday October 21, 2024 @11:59AM
from the github.com dept.
My bad. What i meant is that code execution is alright rather than dealing with macro magic in yaml or excessively verbose nesting like in toml
There is no 'corruption' happening anywhere.
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.
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
Posted by
caligian on Saturday November 04, 2023 @07:43AM
from the self-post dept.
So json parsing comes in all sizes - from being implemented in the host lang or being in C - from being blazingly fast™ to simply being slow. What is indeed comical is that json is just half arsed js with none of the benefits of the host language. Every time a new lang is invented, someone reinvents the wheel in both c and the host lang.I think lua's portability is great over here. I think that...
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
function mod0(x, y)
return (x % y) + 1
end
Something like this? You replace % with mod0()
It is constantly called one of the worst programming languages. Coders i know want to touch lua with a 10-feet pole.
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
I agree with your criticism. I could not properly use lua without creating my own set of table utils and structs (they are faster than classes)
Yes. My point is that it should not matter because you can stick to table indexing with +-1 or create a function for the same
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
Posted by
caligian on Thursday October 26, 2023 @08:53AM
from the self-post dept.
1 based syntax - it is easy to define functions that are index-agnostic or correct off by 1 errors. Looks like people don't want to define a single trivial function. I like how erlang handles indices - by not really relying on them much2. nil-handling - no dynamic language has good nil handling. The proper solution is having optional types. People cannot grasp the fact that nils in control flow...