]> code.delx.au - gnu-emacs-elpa/blob - packages/names/TheNittyGritty.org
Merge commit '0cda39255827f283e7578cd469ae42daad9556a2' from js2-mode
[gnu-emacs-elpa] / packages / names / TheNittyGritty.org
1 * The Nitty Gritty
2 In general, =define-namespace= should work as you expect it to. But if you
3 need to understand why something is or isn't being namespaced, here's
4 the nitty gritty of how it happens.
5
6 ** Quoted Lists
7 Quoted lists (be it with =quote= or =function=) are namespaced *only*
8 of the list is a =lambda= form (or a =macro= form). Arbitrary lists
9 are returned untouched (they are way too arbitrary to be handled
10 sanely). That is:
11 #+begin_src emacs-lisp
12 (define-namespace foo-
13 (defun infinite (y)
14 (mapcar
15 '(lambda (x) (infinite x))
16 '(not a lambda (infinite x))))
17 )
18 #+end_src
19 expands to
20 #+begin_src emacs-lisp
21 (defun foo-infinite (y)
22 (mapcar
23 '(lambda (x) (foo-infinite x))
24 '(not a lambda (infinite x))))
25 #+end_src
26
27 Note that = '(lambda ...)= is bad practice in Emacs, you should use
28 =(lambda ...)= instead (which is also namespaced just fine).
29
30 ** Symbols Quoted with Quote
31 A symbol quoted with =quote= (or = ' =) is never namespaced.
32 #+begin_src emacs-lisp
33 (define-namespace foo-
34 (defvar var nil)
35 (defvaralias 'varalias 'var)
36 (defun fun nil)
37 (defalias 'alias 'fun)
38 (defalias 'otheralias 'var)
39 )
40 #+end_src
41 expands to
42 #+begin_src emacs-lisp
43 (defvar foo-var nil)
44 (defvaralias 'varalias 'var)
45 (defun foo-fun nil)
46 (defalias 'alias 'fun)
47 ;;; foo-var is not a function, so:
48 (defalias 'otheralias 'var)
49 #+end_src
50
51 If you provide the =:assume-var-quote= keyword, quoted symbols will be
52 namespaced as variables instead.
53 ** Symbols Quoted with Function
54 A symbol quoted with =function= (or =#' =) is assumed to be the name of a
55 function, and will be namespaced as such if possible. You may provide
56 the =:dont-assume-function-quote= keyword to disable this behaviour,
57 =function= will then be treated like =quote=.
58
59 #+begin_src emacs-lisp
60 (define-namespace foo-
61 (defun fun (x) x)
62 (mapcar 'fun somelist)
63 (mapcar #'fun somelist)
64 )
65 #+end_src
66 expands to
67 #+begin_src emacs-lisp
68 (defun foo-fun (x) x)
69 (mapcar 'fun somelist)
70 (mapcar #'foo-fun somelist)
71 #+end_src
72
73 ** Backticks (quasi-quotes)
74 Backticks (or =`=) are handled as you would expect. Lists or simbles
75 quoted with a backtick are treated the same as those quoted with
76 regular quotes ([[#quoted-lists][see above]]), except anything prefixed by a comma (which
77 is effectively not quoted) is namespaced as usual.
78
79 ** Local Variables Take Precedence
80 Local variables take precedence over namespace variables.
81 For instance
82 #+begin_src emacs-lisp
83 (define-namespace foo-
84 (defvar bar "2")
85
86 (defun funca (bar)
87 (string-to-int bar))
88 )
89 #+end_src
90 expands to
91 #+begin_src emacs-lisp
92 (defvar foo-bar "2")
93
94 (defun funca (bar)
95 (string-to-int bar))
96 #+end_src
97
98 Note how the last =bar= isn't namespaced. That's because it is local
99 to the =funca= function, and takes precedence over the global
100 =foo-bar=. The argument list of functions, macros, and lambdas are
101 all local definitions.
102
103 By default, this does not happen with let bindings, they are
104 namespaced as usual (if the variable name in question has a global
105 definition). The reason is that let bindings are commonly used to
106 temporarily override global bindings.
107
108 You can customize this behaviour with the =:no-let-vars= keyword.
109 Then:
110 #+begin_src emacs-lisp
111 (define-namespace foo- :no-let-vars
112 (defvar bar "2")
113
114 (let ((bar "1"))
115 (string-to-int bar))
116 )
117 #+end_src
118 will expand to
119 #+begin_src emacs-lisp
120 (defvar foo-bar "2")
121
122 (let ((bar "1"))
123 (string-to-int bar))
124 #+end_src
125
126 ** Macros
127 Macros are handled in a very intelligent manner.
128
129 *Names* needs to know which parts of a macro's arguments are
130 evaluatable forms, and which are just arbitrary symbols. This presents
131 a challenge because macro arguments could be absolutely anything.
132 Fortunately, (good) macros already provide that information in their
133 =debug= declaration.
134
135 Thus, *Names* uses the macro's =edebug-spec-list= to find out which
136 arguments are evaluatable forms, and namespaces only those. Other
137 arguments are left untouched. Usually, this is not something you'll
138 need to worry about, it should just do what you expect from it.
139
140 This is only relevant if you write your own macros. If you do,
141 remember to add a debug declaration in them.
142
143 *** The theading macros (~->~ and ~-->~)
144
145 The threading macros would require special treatment to namespace
146 correctly. However, you can use the ~:functionlike-macros~ keyword to
147 tell *Names* to treat them as regular functions.
148
149 For example, in the following snippet:
150 #+BEGIN_SRC emacs-lisp
151 (require 'dash)
152 (define-namespace foo-
153 :functionlike-macros (-> ->>)
154
155 (defvar var nil)
156 (defun fun (x &optional y)
157 (concat x y))
158
159 (-> "some string"
160 (fun var)
161 fun)
162 )
163 #+END_SRC
164 the ~(fun var)~ part would be namespaced prefectly fine (~fun~ and
165 ~var~ will be identified as a function and variable respectively),
166 because it looks like a regular function call. However, the second use
167 of ~fun~ will not be correctly namespaced, because that ~fun~ looks
168 like a variable.
169
170 In other words, you should use these macros like this instead:
171 #+BEGIN_SRC emacs-lisp
172 (-> "some string"
173 (fun var)
174 (fun))
175 #+END_SRC
176
177 ** Accessing Global Symbols
178 If one of your definitions shadows a global definition, you can still
179 access it by prefixing it with =::=.
180
181 #+begin_src emacs-lisp
182 (define-namespace foo-
183 (defun message ()
184 (message)
185 (::message "Hi"))
186 )
187 #+end_src
188 expands to
189 #+begin_src emacs-lisp
190 (defun foo-message ()
191 (foo-message)
192 (message "Hi"))
193 #+end_src
194
195 When in doubt feel free to use =::=, it will always get removed (as
196 long as it's not inside a =quote=). You may also change this prefix to
197 something else with the =:prefix= keyword.