Skip to content

Commit eecb6a9

Browse files
committed
half way
1 parent 93cf063 commit eecb6a9

2 files changed

Lines changed: 355 additions & 0 deletions

File tree

content/guides/guides.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ ifdef::env-github,env-browser[:outfilesuffix: .adoc]
1212

1313
=== Language
1414

15+
* <<weird_characters#,The Weird and Wonderful Characters of Clojure>>
1516
* <<threading_macros#,Threading Macros>>
1617
* <<comparators#,Comparators>>
1718
* <<reader_conditionals#,Reader Conditionals>>
Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
= The Weird and Wonderful Characters of Clojure
2+
James Hughes
3+
2017-05-27
4+
:type: guides
5+
:toc: macro
6+
7+
ifdef::env-github,env-browser[:outfilesuffix: .adoc]
8+
9+
[]
10+
====
11+
This is a reference collection of characters used in Clojure that are difficult to "google".
12+
Descriptions are sourced from various blogs, https://stackoverflow.com[StackOverflow],
13+
http://en.wikibooks.org/wiki/Learning_Clojure[Learning Clojure], and the
14+
http://clojure.org/documentation[official Clojure docs] -- sources attributed
15+
where necessary. Sections are not in any particular order, but related items
16+
are grouped for ease. This guide is a copy of http://twitter.com/kouphax[James Hughes]
17+
brilliant https://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/[blog post] of the same name.
18+
====
19+
20+
== # - Dispatch macro
21+
22+
You'll see this macro character beside another e.g. `\#(` or `#"`.
23+
// " Comment needed for emacs to behave.
24+
This topic will act as a bit of a preamble before looking at your specific case.
25+
26+
`#` is the dispatch macro, a reader macro that tells the Clojure
27+
reader (the thing that takes a file of Clojure code and parses it for
28+
consumption by the compiler) to go and look at another *read table*
29+
for the definition of the next character - in essence this allows
30+
extending default reader behaviour.
31+
32+
Clojure doesn't provide support for creating reader macros, but it is possible
33+
through http://briancarper.net/blog/449/[a bit of hackery].
34+
35+
If you se `#` *at the end* of a symbol, then it is used to automatically
36+
generate a new symbol. This is useful inside macros to keep macro specifics
37+
from leaking into the userspace. A regulare `let` will fail in a macro definition
38+
39+
[source,clojure]
40+
----
41+
user=> (defmacro m [] `(let [x 1] x))
42+
#'user/m
43+
user=> (m)
44+
CompilerException java.lang.RuntimeException: Can't let qualified name: user/x, compiling:(NO_SOURCE_PATH:1)
45+
----
46+
47+
Instead you need to append `#` to the end of the variable name and let Clojure
48+
generate a unique symbol for it:
49+
50+
[source, clojure]
51+
----
52+
user=> (defmacro m [] `(let [x# 1] x#))
53+
#'user/m
54+
user=> (m)
55+
1
56+
user=>
57+
----
58+
59+
If we expand this macro, we can see the `gensym` 'd name:
60+
61+
[source, clojure]
62+
----
63+
user=> (macroexpand '(m))
64+
(let* [x__681__auto__ 1] x__681__auto__)
65+
----
66+
67+
Another place you'll see the `#` is in
68+
http://clojure.org/reader#The%20Reader--Tagged%20Literals[tagged literals].
69+
Most commonly you'll see this use in https://github.com/edn-format/edn[EDN]
70+
(extensible data notation - a rich data fromat that can be used in Clojure)
71+
and in ClojureScript (`#js`). Search for `#inst`, `#uuid`, or `#js` for some
72+
more info.
73+
74+
* http://clojure.org/reader[Clojure Documentation Reader]
75+
* http://briancarper.net/blog/449/[Clojure Reader Macros]
76+
* http://clojuredocs.org/clojure_core/clojure.core/gensym[ClojureDocs - gensyms]
77+
78+
== #{ - Set macro
79+
80+
See the dispatch (`\#`) macro for additional details.
81+
82+
`#{` defines a set (a collection of unique values) specifically a `hash-set`. The
83+
following are equivalent:
84+
85+
[source, clojure]
86+
----
87+
user=> #{1 2 3 4}
88+
#{1 2 3 4}
89+
user=> (hash-set 1 2 3 4)
90+
#{1 2 3 4}
91+
----
92+
93+
Attempting to create a `set` using this literal form will throw if there
94+
are duplicates. Instead the `hash-set` function should be used on a vector.
95+
96+
[source, clojure]
97+
----
98+
user=> #{1 2 3 4 1}
99+
100+
IllegalArgumentException Duplicate key: 1 clojure.lang.PersistentHashSet.createWithCheck (PersistentHashSet.java:68)
101+
user=> (set [1 2 3 4 1]) ; convert vector to set, removing duplicates
102+
#{1 2 3 4}
103+
----
104+
105+
* http://clojure.org/data_structures#Data%20Structures-Sets[Clojure Documentation: Sets]
106+
107+
== #_ - Discard macro
108+
109+
See the dispatch (`#`) macro for additional details.
110+
111+
`#_` tells the reader to ignore the next form completely.
112+
113+
[source,clojure]
114+
----
115+
user=> [1 2 3 #_ 4 5]
116+
[1 2 3 5]
117+
----
118+
The docs suggest that "The form following `#_` is completely skipped by the reader,
119+
(This is a more complete removal than the `comments` macro which yields `nil`).".
120+
This can prove useful for debugging situations or for multiline comments.
121+
122+
* http://clojure.org/reader[Clojure Documentation - Reader
123+
124+
== #" - Regular Expression macro
125+
// " for the pleasure of emacs.
126+
127+
See the dispatch (`#`) macro for additional details.
128+
129+
`#"` indicates the start of a regular expression
130+
// "
131+
[source,clojure]
132+
----
133+
user=> (re-matches #"^test$" "test")
134+
"test"
135+
----
136+
137+
This form is compiled at *read time* into a host-specific regex machinery.
138+
139+
* http://clojure.org/other_functions#Other%20Useful%20Functions%20and%20Macros-Regex%20Support[Clojure Documentation: Regex Support]
140+
141+
== #( - Function macro
142+
143+
See the dispatch (`#`) macro for additional details.
144+
145+
`#(` begins the short hand syntax for an inline function definition. The
146+
following two snippets of code are similar:
147+
148+
[source,clojure]
149+
----
150+
; anonymous function takin a single argument and printing it
151+
(fn [line] (println line)) ;
152+
153+
; anonymous function takin a single argument and printing it - shorthand
154+
#(println %)
155+
----
156+
157+
The macro expands the shorthand syntax into a function definition whose
158+
arity (the number of arguments it takes) is defined by how the `%` placeholders
159+
are declared. See the `%` character for discussion around arity.
160+
161+
[source,clojure]
162+
----
163+
user=> (macroexpand `#(println %))
164+
(fn* [arg] (clojure.core/println arg)) ; argument names shortened for clarity
165+
----
166+
167+
== #' - Var macro
168+
169+
`#'` is the var quote. It is the same as the `var` function:
170+
171+
[source,clojure]
172+
----
173+
user=> (def nine 9)
174+
#'user/nine
175+
user=> nine
176+
9
177+
user=> (var nine)
178+
#'user/nine
179+
user=> #'nine
180+
#'user/nine
181+
----
182+
When used it will attempt to return the referenced var. This is useful when
183+
you want to talk ab out the reference/declaration instead of teh value it represents.
184+
See the use of `meta` int the metadata (`^`) discussion.
185+
186+
* http://clojure.org/special_forms#var[Clojure Official Documentation: Special Forms]
187+
188+
== #inst, #uuid, and #js etc. - tagged literals
189+
190+
Commonly found in EDN and ClojureScript this use of `#` is called the _tagged literal_.
191+
Look at this example:
192+
[source,clojure]
193+
----
194+
user=> (java.util.Date.)
195+
#inst "2014-05-19T19:12:37.925-00:00"
196+
----
197+
198+
When we create a new date it is represented as a tagged literal, or in this case,
199+
a tagged string. We can use Clojures `read-string` to read this back (or use it directly):
200+
[source,clojure]
201+
----
202+
user=> (type #inst "2014-05-19T19:12:37.925-00:00")
203+
java.util.Date
204+
(read-string "#inst \"2014-05-19T19:12:37.925-00:00\"")
205+
#inst "2014-05-19T19:12:37.925-00:00"
206+
user=> (type (read-string "#inst \"2014-05-19T19:12:37.925-00:00\""))
207+
java.util.Date
208+
----
209+
210+
A tagged literal tells the reader how to parse the literal value. Other common
211+
uses include `#uuid` for generating UUIDs and in the ClojureScript world an
212+
extremely common use of tagged literals is `#js` which can be used to convert
213+
ClojureScript data structures into JavaScript structures directly. Note that
214+
`#js` doesn't convert recursivly, so if you have a nested data-structure, use
215+
`cjs->js`.
216+
217+
* https://github.com/edn-format/edn#tagged-elements[EDN Tagged Elements]
218+
219+
== % - Argument placeholder
220+
221+
`%` is not a macro, but a placeholder for use in the `#(` macro. It represents
222+
an argument that will be passed into the function when it is expanded.
223+
[source,clojure]
224+
----
225+
user=> (macroexpand `#(println %))
226+
(fn* [arg] (clojure.core/println arg)) ; takes a single arg, uses it once
227+
228+
user=> (macroexpand `#(println % %))
229+
(fn* [arg] (clojure.core/println arg arg)) ; takes a single arg, uses it twice
230+
----
231+
Numbers can be placed directly after the `%` to indicate the arguments position.
232+
Numbers are also used by the `#(` macro to determine the number of arguments
233+
to pass in.
234+
[source,clojure]
235+
----
236+
user=> (macroexpand `#(println %1 %2))
237+
(fn* [arg1 arg2] (clojure.core/println arg1 arg2)) ; takes 2 args
238+
239+
user=> (macroexpand `#(println %4))
240+
(fn* [arg1 arg2 arg3 arg4] (clojure.core/println arg4)) ; takes 4 args doesn't use 3
241+
----
242+
243+
You don't have to use the arguments, but you do need to declare them in the order
244+
you'd expect an external caller to pass them in.
245+
246+
`%` and `%1` can be used interchangably:
247+
[source,clojure]
248+
----
249+
user=> (macroexpand `#(println % %1)) ; use both % and %1
250+
(fn* [arg1] (clojure.core/println arg1 arg1)) ; still only takes 1 argument
251+
----
252+
253+
== @ - Deref macro
254+
255+
`@` is the deref macro, it is the shorthand equivalent of the `deref` function so
256+
these two forms are the same:
257+
[source,clojure]
258+
----
259+
user=> (def x (atom 1))
260+
#'user/x
261+
user=> @x
262+
1
263+
user=> (deref x)
264+
1
265+
user=>
266+
----
267+
`@` is used to get the current value of a reference. The above example uses
268+
`@` to get the current value of an http://clojure.org/atoms[atom], but `@` can
269+
be applied to other things such as `future` s, `delay` s, `promises` s etc. to
270+
force computation and potentially block.
271+
272+
== ^ - Metadata
273+
274+
`^` is the metadata marker. Metadata is a map of values (with shorthand option)
275+
that can be attached to various forms in Clojure. This provides extra information
276+
for these forms and can b e used for documentation, compilation warnings,
277+
typehints, and other features.
278+
[source,clojure]
279+
----
280+
user=> (def ^{ :debug true } five 5) ; meta map with single boolean value
281+
#'user/five
282+
----
283+
284+
We can access the metadata by the `meta` function which should be executed
285+
against the declaration itself (rather than the returned value):
286+
[source,clojure]
287+
----
288+
user=> (def ^{ :debug true } five 5)
289+
#'user/five
290+
user=> (meta #'five)
291+
{:ns #<Namespace user>, :name five, :column 1, :debug true, :line 1, :file "NO_SOURCE_PATH"}
292+
----
293+
As we have a single value here, we can use a shorthand notation for declaring
294+
the metadata `^:name` which is useful for flags, as the value will be set to true.
295+
[source,clojure]
296+
----
297+
user=> (def ^:debug five 5)
298+
#'user/five
299+
user=> (meta #'five)
300+
{:ns #<Namespace user>, :name five, :column 1, :debug true, :line 1, :file "NO_SOURCE_PATH"}
301+
----
302+
Another use of `^` is for type hints. These are used to tell the compiler what
303+
type the value will be and allow it to perform type specific optimiztions
304+
thus potentially making resultant code faster:
305+
[source,clojure]
306+
----
307+
user=> (def ^Integer five 5)
308+
#'user/five
309+
user=> (meta #'five)
310+
{:ns #<Namespace user>, :name five, :column 1, :line 1, :file "NO_SOURCE_PATH", :tag java.lang.Integer}
311+
----
312+
We can see in that example the `:tag` property is set.
313+
314+
You can also stak the shorthand notations:
315+
[source,clojure]
316+
----
317+
user=> (def ^Integer ^:debug ^:private five 5)
318+
#'user/five
319+
user=> (meta #'five)
320+
{:ns #<Namespace user>, :name five, :column 1, :private true, :debug true, :line 1, :file "NO_SOURCE_PATH", :tag java.lang.Integer}
321+
----
322+
323+
* http://clojure.org/metadata[Clojure Official Documentation: Metadata]
324+
* http://en.wikibooks.org/wiki/Learning_Clojure/Meta_Data[Learning Clojure: Meta Data]
325+
326+
== ' - Quote macro
327+
328+
Can be used against symbols as part of a dispatch macro (see `#'`). Also
329+
used to quote forms and prevent their evalutation as with the quote function.
330+
[source,clojure]
331+
----
332+
user=> (1 3 4) ; fails as it tries to evaluate 1 as a function
333+
334+
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/eval925 (NO_SOURCE_FILE:1)
335+
user=> '(1 3 4) ; quote
336+
(1 3 4)
337+
user=> (quote (1 2 3)) ; using the longer quote method
338+
(1 2 3)
339+
user=>
340+
----
341+
342+
* http://clojure.org/special_forms#quote[Clojure Official Documentation]
343+
344+
== ; - Comment
345+
346+
`;` is a comment. In fact it's a comment *macro* that takes all input from its
347+
starting point to the end of the line and ensures that the reader ignores it.
348+
[source,clojure]
349+
----
350+
user=> (def x "x") ; this is a comment
351+
#'user/x
352+
user=> ; this is a comment too
353+
<returns nothing>
354+
----

0 commit comments

Comments
 (0)