chiark / gitweb /
src/c-types-test.lisp, src/test-base.lisp: Force pretty-printing.
[sod] / STYLE
CommitLineData
1528431b
MW
1Notes on Lisp style
2
3* Language subset and extensions
4
5None of ANSI Common Lisp is off-limits.
6
828cb3b1
MW
7I think my Lisp style is rather more imperative in flavour than most
8modern Lisp programmers. It's probably closer to historical Lisp
9practice in that regard, even though I wasn't writing Lisp back then.
10
1528431b
MW
11I make extensive use of CLOS, and macros. On a couple of occasions I've
12made macros which use CLOS generic function dispatch to compute their
13expansions. The parser language is probably the best example of this in
828cb3b1
MW
14the codebase.
15
16I like hairy ~format~ strings.
1528431b
MW
17
18I've avoided hairy ~loop~ for the most part, not because I dislike it
19strongly but because others do and I don't find that it wins big enough
20for the fight to be worthwhile.
21
22I only use ~&aux~ lambda-list parameters in ~defstruct~ BOA
23constructors, for special effects.
24
25I use ~car~, not ~first~, and ~cdr~, not ~rest~. Similarly, I use
26~cadr~, not ~second~, and I'm not afraid to use ~cddr~ or ~cadar~.
27
28Similarly, I've not used ~elt~, preferring to know what kind of sequence
29I'm dealing with, or using the built-in sequence functions.
30
31I'm happy to use ~1+~, and I like the brevity of ~1-~ enough to use it
32despite its terrible name.
33
34There are no reader syntax extensions in the code. This is because I
35couldn't think of any way they'd be especially helpful, and not because
36I'm in any way opposed to them.
37
38The main translator, in the ~SOD~ package, tries to assume very little
39beyond ANSI Common Lisp and what's included in just about every serious
40implementation: specifically, MOP introspection, and Gray streams.
41There's intentionally no MOP intercession.
42
43The frontend additionally ~cl-launch~, but the dependency is actually
44quite weak, and it could be replaced with a different, maybe
45implementation-specific, mechanism fairly easily. I'm keen to take
46patches which improve frontend portability.
47
48I'm more tolerant of extensions and external dependencies in the test
49suite, which makes additional use of ~xlunit~. Running the test suite
50isn't essential to getting the translator built, so this isn't as much
51of a problem.
52
53
54* Layout
55
56I pretty much let Emacs indent my code for me, based on information
57collected by SLIME. Some exceptions:
58
59 + DSLs (e.g., the parser language) have their own space of macros
60 which Emacs doesn't understand and for the most part I haven't
61 bothered to teach it.
62
63 + Emacs sometimes does a bad job with hairy ~loop~ and requires manual
64 fixing. Since I don't use hairy ~loop~ much, this isn't a major
65 problem.
66
67Lines are 77 characters at most, except for strange special effects.
68Don't ask. This is not negotiable, though. Don't try to tell me that
69your monitor is very wide so you can read longer lines. My monitor is
70likely at least as wide. On the other hand, most lines are easily short
71enough to fit in my narrow columns, so the right hand side of a wide
72window would be mostly blank. This seems wasteful to me, when I could
73fill that space with more code.
74
75Lisp code does have a tendency to march across to the right quite
76rapidly given a chance. I have a number of strategies for dealing with
77this.
78
79 + Break a long nested calculation into pieces, giving names to the
80 intermediate results, in a ~let*~ form.
81
82 + Hoist deeply nested complex computations out into an ~flet~ or
83 ~labels~, and then invoke it from inside whatever complicated
84 conditional mess was needed to decide what to do.
85
86 + Shrug my shoulders and let code dribble down the right hand side for
87 a bit.
88
89
90* Packages and exporting
91
92A package collects symbols which are given meanings in one or more
93source files. If a package's code is all in one file, then the package
94definition can be put in that file too; otherwise I put it in its own
95file.
96
97I don't put ~:export~ in package definitions. Instead, I scatter calls
98to the ~export~ function throughout the code, right next to where the
99relevant symbol is defined. This has three important advantages.
100
101 + You can tell, when you're reading the code which defines ~foo~,
102 whether ~foo~ is exported and therefore a defined part of the
103 package interface.
104
105 + When you know that you're writing a thing which will form part of
106 the package interface, you don't have to go off and edit some other
107 file to export it.
108
109 + A master list of exported symbols becomes a merge hazard: if two
110 different branches add symbols to nearby pieces of the master list
111 then you get a merge conflict for no especially good reason.
112
113There's an apparent disadvantage: there's no immediately visible master
114list of exported symbols. But that's not a big problem:
115
116: (loop for s being the external-symbols of pkg collect s)
117
118See ~doc/list-symbols.lisp~ for more sophisticated reporting. (In
119particular, this identifies what kind of thing(s) each external symbol
120names.)
121
122
123* Comments and file structuring
124
125A file starts with a big ~;;;~ comment bearing the Emacs ~-*-lisp-*-~
126marker, a quick description, and copyright and licensing boilerplate. I
127don't use four-semicolon comments, and I only use ~#|~ ... ~|#~ for
128special effects.
129
130Then there's package stuff. There may be a ~cl:defpackage~ form (with
131explicit package qualifier) if the relevant package doesn't have its own
132package definition file.
133
134Then there's ~cl:in-package~. Like ~defpackage~, I use a gensym to name
135the package. I can't think offhand of a good reason to have a file with
136sections `in' more than one package. So, in the ~in-package~ form goes
137at the top of the file, before the first section header. If sections
138are going to end up in separate packages, I think I'd put a
139~cl:in-package~ at the top of each section in case I wanted to reorder
140them.
141
142The rest of the file consists of Lisp code. I don't use page boundaries
143~^L~ to split files up. Instead, I use big banner comments for this:
144
145: ;;;--------------------------------------------------------------------------
146: ;;; Section title.
147
148Sections don't usually have internal comments, but if they did they'd
149also be ~;;;~ comments.
150
151Almost all definitions get documentation strings. I've tried to be
152consistent about formatting.
153
154 + Docstring lines are 77 characters or less.
155
156 + The first line gives a summary of what the thing does. The summary,
157 together with the SLIME-generated synopsis, is likely enough to
158 remind you what the thing does.
159
160 + The rest of the lines are indented by three spaces, and explain
161 carefully what the thing does and what all the parameters mean.
162
163Smallish functions and macros don't usually need any further
164commentary. Big functions often need to be split into bitesize pieces
165with their own internal ~;;~ comments. The idea is that these comments
166should explain the code's overall strategy to the reader, and help them
167figure out how a piece fits into that strategy.
168
169Winged, single ~;~ comments are very rare.
170
171Files end, as a result of long tradition, with a comment
172
173: ;;;----- That's all, folks --------------------------------------------------
174
175
176* Macro style
177
178I don't mind complicated macros if they're doing something worthwhile.
179They need to have good documentation strings, though.
180
181That said, where possible I've tried to factor macros into an actual
182macro providing the syntactic sugar, and a function which receives the
183parameters and $\eta$-expanded forms, and does the actual work.
184
185It's extremely bad taste for a macro to evaluate its evaluable
186parameters in any order other than strictly left to right, or to
187evaluate them more than once.
188
189
190* Data structures
191
192I've tended to be happy with plain lists for homogeneous-ish
193collections. Strongly heterogeneous collections (other than input
194syntax, destructured using ~defmacro~ or ~destructuring-bind~) I've
195tended to make a proper data type for.
196
197My first instinct when defining a new structure is to use ~defclass~.
198While it's annoyingly verbose, it has the immense benefit over
199~defstruct~ that it's safe to redefine CLOS classes in a running image
200without the world breaking, and I usually find it necessary to add or
201change slots while I'm working on new code. Once a piece of code has
202settled down and I have a good feel for what my structure is actually
203doing, I might switch the ~defclass~ for a ~defstruct~. Several
204questions influence my decision.
205
206 + Do slot accesses need to be really fast? My usual Lisp
207 implementations aggressively optimize ~defstruct~ accessor
208 functions.
209
210 + Have I subclasses my class? While I can move over a
211 single-inheritance tree using ~:include~, it seems wrong to do this
212 most of the time. Also, I'd be precluding subclasses from multiple
213 inheritance, and I'd either have to prohibit subclassing by
214 extensions or have to commit to ~defstruct~ in the documentation.
215 In general, I'm much happier committing to ~defclass~.
216
217 + Are there methods specialized on my class? Again, structure classes
218 make fine method specializers, but it doesn't seem right.
219
220Apart from being hard to redefine, ~defstruct~ does a pretty good job of
221making a new structure type. I tend to tidy up a few rough edges.
222
223 + The default predicate always has ~-p~ appended. If the class name
224 is a single word, then I'll explicitly name the predicate with a
225 simple ~p~ suffix. For example, ~ship~ would have the predicate
a51bf71a 226 ~shipp~, rather than ~ship-p~.
1528431b
MW
227
228 + If there are slots I can't default then I'll usually provide a BOA
229 constructor which sets them from required parameters; other slots
230 I'll set from optional or keyword parameters according to my taste
231 and judgement.
232
233 + Slots mustn't be given names which are external in any package.
234 Unfortunately, slot names are used in constructing accessor names,
235 and sometimes the right accessor name involves a prohibited symbol.
236 I've mostly addressed this by naming the slot ~%foo~, and then
237 providing inline reader and writer functions. (CLOS class
238 definitions don't have this problem because you get to set the
239 accessor function names independently of the slot names.)
240
241 + BOA constructors are strange. You can set the initial slots based
242 on an arbitrary computation on the provided parameters, but you have
243 to roll up your sleeves and mess with ~&aux~ parameters to pull it
244 off.
245
246
247* Naming
248
249I'm a traditionalist in some ways, and one of the reasons I like Lisp is
250the richness of its history and tradition.
251
252In other languages, I tend to use single- or two-letter names for
253variables and structure slots; not so much in Lisp. Other languages
254express more using punctuation, so the names stand out easily; I find
255that short names can be lost more easily in Lisp.
256
257I've also tended to go for fairly prosaic names, taking my inspiration
258from the CLOS MOP. While I mourn the loss of whimsical names like
259~haulong~ and ~haipart~, I've tried to avoid inventing more of them.
260
261There's a convention, which I think comes from ML, of using ~_~ in a
262where a binding occurrence of a variable name is expected, to signify
263that that the corresponding value is to be discarded. Common Lisp,
264alas, doesn't have such a convention. Instead, there's a sequence of
265silly names used with the same intention, and the bindings are then
266explicitly ignored with a declaration. The names begin ~hunoz~,
267~hukairz~, and (I think) ~huaskt~.
268
269
270* Declarations
271
272The code is light on declarations, other than ~ignore~ and similar used
273to muffle warnings. The macros try to do sensible things with
274declarations, and I think they succeed fairly well, but there might be
275bugs and rough edges. I know that some are just broken because, for
276actual correctness, declarations provided by the caller need to be split
277up into a number of different parts of the expansion, which in turn
278requires figuring out what the declarations mean and which bindings
279they're referring to. That's not completely impossible, assuming that
280there aren't implementation-specific declarations which crazy syntax
281mixed in there, but it's more work than seems worthwhile.
282
283
284* COMMENT Emacs cruft
285
286#+LATEX_CLASS: strayman
287
288## LocalWords: CLOS ish destructure destructured accessor specializers
289## LocalWords: accessors DSLs gensym
290
291## Local variables:
292## mode: org
293## End: