Just spent a good half hour pulling my hair out trying to figure out why one of the #elisp functions I had just written was always returning nil
when I tested it. Turns out, my test was mistakenly passing its inputs to the wrong (but similarly named) function (pivot-table-get-columns
instead of pivot-table-get-body
).
#Haskell's type system would've caught this. 🙃
@Alessio Vanni Yeah, it's just very magic number-ey.
Ah well, such is the way it is with legacy code sometimes. No way to change it without breaking about a billion other things.
Currently there are two options which help for the underlying problem:
gnu.org/software/emacs/manual/…
gnu.org/software/emacs/manual/…
I use both here:
codeberg.org/harald/eglot-supp…
For the shorthands, check the last few lines of the file.
But, no doubt, some real namespace with an export/import convention would be great.
eglot-supplements/eglot-selran.el at main
eglot-supplements - Supplements for Emacs Eglot.Codeberg.org
@The ol' tealeg 🐡 I'm thinking something a little more robust involving using a symbol's property list to store everything contained within that namespace.
I'm probably biting off more than I can chew at this point in my understanding of elisp, but I'm sure this idea will stick around in my brain until I have enough of an understanding to pull it (or something comparable) off.
...or I find some already existing thing that does what I want (which is more likely).
@tealeg
Just a sidenote, but `in-package' and Co. are Common Lisp things, not just SBCL's.
And `*package*' is mainly used by the reader.
@vnikolov the specific macro expansion can differ though, right?
Really I was just quickly checking by doing `(macroexpand ‘(in-package foo))`, I never really thought much about the implementation before now.
@tealeg
tealeg@mastodon.online> the specific macro expansion can differ though, right?
Yes, and it often does (and it may well contain implementation-specific items, of course).
And `macroexpand' is certainly a good way to explore things; just consult the specification as well (in this case the excellent Hyperspec, CLHS).
Ok, here's a working(?) proof-of-concept for
#emacs namespaces: git.sr.ht/~thuna/namespace-el
In order to use it, go to your scratch buffer (or just any elisp
buffer), do M-x enable-namespace. Then, define a namespace via
(define-namespace :foo
(:use nil)
(:export my-symbols...))
where (:use nil) serves the same purpose as (:use :cl) in Common Lisp.
Afterwards, you can either do
(in-namespace :foo)
...
or
(with-namespace :foo
...)
You should also be able to file-locally set `buffer-namespace', but I
haven't tried it.
Here's a working snippet:
(define-namespace :foo
(:use nil)
(:export bar setq nil))
(define-namespace :baz
(:use :foo)
(:export bar))
(with-namespace :foo
(setq foo 2))
foo:bar ;; => 2
(with-namespace :baz
(setq bar 5)
(setq quux 10))
foo:bar ;; => 5
baz:bar ;; => 5
baz:quux ;; => 10
although you'll need to patch elisp--preceding-sexp for C-x C-e to see
the individual values. Here's the code you need to evaluate (at least
on my version, I suggest trying this in a fresh emacs in case
something goes wrong): 0x0.st/84sj.txt
I have fleshed it out more (or rather, ported
over CL's packages): git.sr.ht/~thuna/cl-package (this is
still the same repo, but I've changed the name).
The demo is:
- require cl-package / load cl-package.el
- require cl-package-reader / load cl-package-reader.el
- go to a new buffer (or the scratch buffer)
- M-x cl-package-activate-reader RET
- Insert the snippet
- Do eval-buffer, or after applying the same patch as before (replace `(read...)' with `(funcall load-read-function...)' in `elisp--preceding-sexp') go through each form (you can skip cl-in-package) one by one with C-x C-e
- Have fun
The snippet is:
(cl-defpackage test
(:use :global)
(:shadow baz)
(:export baz))
(cl-in-package :test)
(setq test:baz 10)
(message "%S" test:baz) ;; => 10
(intern-soft "test:baz") ;; => nil
Where the second nil means that no symbol with the literal name
"test:baz" exists in emacs, and that the symbol we're referring to
with test:baz is something else entirely, which you can also see with:
(eq (intern "test:baz") 'test:baz) => nil
There are probably a lot of problems, some of which are:
- defpackage does not play nice with redefinitions (or rather, you can't do it at all), just pop cl-package-registry (but not completely, always leave the last item, if you want to fully reset it set it to (list obarray)) and redefine it again
- I have the elisp runtime in the pseudo-package :global, but trying to use :global in your own package will force it to check all (tens of thousands of!) symbols for conflicts, so it'll take a couple seconds during the defpackage in the snippet. I will later define packages containing the various elisp packages for proper modularity, so it should get better
- Once you evaluate cl-in-package, eval-buffer starts with cl-in-package, which it probably shouldn't be doing, but I don't know
and who knows how many more!
@galdor
@screwtape
Oh come on you understand the situation perfectly ;) You can write hacks to make it look like there are namespaces, but at the end of the day, they are just hacks.
There has been multiple discussions about it on emacs-devel, and there is no way to get elisp out of the dark ages until the usual suspects are replaced. Which is not happening any time soon.
You know I like to set an extremely low bar for quality personally. And after all, everyone eats at your sushi place every week...!
It's also interesting to everyone to get opinions on common lisp from the outside or somewhat recent arrivals. I think you and jeremy_list are both interesting as sort of Haskell/MOO/emacs/common lispers.
Counterpointing the "golang for serious business" long-time lisp-heads like @galdor
Jonathan Lamothe likes this.
This website uses cookies. If you continue browsing this website, you agree to the usage of cookies.
Omar Antolín
in reply to Jonathan Lamothe • • •Oriel Jutty
in reply to Jonathan Lamothe • • •This is why C89 wisely limits external symbols to 6 significant characters.
/s
Jonathan Lamothe
in reply to Oriel Jutty • •@Oriel Jutty
*twitch*
Kazinator
in reply to Jonathan Lamothe • • •C's type system would also have caught it, and it isn't worth a hill of beans.
By caught it what do we mean? This is not a case of some undetected error escaping your attention due to dynamic typing. You know you got a nil which is unexpected and wrong. It's in a test case which catches it.
The only thing a type system would change is that you would instead waste a half hour not understanding how your obviously correct function call can possibly have the wrong return type.
Jonathan Lamothe
in reply to Kazinator • •nil
is about the least useful failure state there is.