Backport from sid to buster
[hcoop/debian/mlton.git] / doc / guide / src / SyntacticConventions.adoc
1 SyntacticConventions
2 ====================
3 :toc:
4
5 Here are a number of syntactic conventions useful for programming in
6 SML.
7
8
9 == General ==
10
11 * A line of code never exceeds 80 columns.
12
13 * Only split a syntactic entity across multiple lines if it doesn't fit on one line within 80 columns.
14
15 * Use alphabetical order wherever possible.
16
17 * Avoid redundant parentheses.
18
19 * When using `:`, there is no space before the colon, and a single space after it.
20
21
22 == Identifiers ==
23
24 * Variables, record labels and type constructors begin with and use
25 small letters, using capital letters to separate words.
26 +
27 [source,sml]
28 ----
29 cost
30 maxValue
31 ----
32
33 * Variables that represent collections of objects (lists, arrays,
34 vectors, ...) are often suffixed with an `s`.
35 +
36 [source,sml]
37 ----
38 xs
39 employees
40 ----
41
42 * Constructors, structure identifiers, and functor identifiers begin
43 with a capital letter.
44 +
45 [source,sml]
46 ----
47 Queue
48 LinkedList
49 ----
50
51 * Signature identifiers are in all capitals, using `_` to separate
52 words.
53 +
54 [source,sml]
55 ----
56 LIST
57 BINARY_HEAP
58 ----
59
60
61 == Types ==
62
63 * Alphabetize record labels. In a record type, there are spaces after
64 colons and commas, but not before colons or commas, or at the
65 delimiters `{` and `}`.
66 +
67 [source,sml]
68 ----
69 {bar: int, foo: int}
70 ----
71
72 * Only split a record type across multiple lines if it doesn't fit on
73 one line. If a record type must be split over multiple lines, put one
74 field per line.
75 +
76 [source,sml]
77 ----
78 {bar: int,
79 foo: real * real,
80 zoo: bool}
81 ----
82
83
84 * In a tuple type, there are spaces before and after each `*`.
85 +
86 [source,sml]
87 ----
88 int * bool * real
89 ----
90
91 * Only split a tuple type across multiple lines if it doesn't fit on
92 one line. In a tuple type split over multiple lines, there is one
93 type per line, and the `*`-s go at the beginning of the lines.
94 +
95 [source,sml]
96 ----
97 int
98 * bool
99 * real
100 ----
101 +
102 It may also be useful to parenthesize to make the grouping more
103 apparent.
104 +
105 [source,sml]
106 ----
107 (int
108 * bool
109 * real)
110 ----
111
112 * In an arrow type split over multiple lines, put the arrow at the
113 beginning of its line.
114 +
115 [source,sml]
116 ----
117 int * real
118 -> bool
119 ----
120 +
121 It may also be useful to parenthesize to make the grouping more
122 apparent.
123 +
124 [source,sml]
125 ----
126 (int * real
127 -> bool)
128 ----
129
130 * Avoid redundant parentheses.
131
132 * Arrow types associate to the right, so write
133 +
134 [source,sml]
135 ----
136 a -> b -> c
137 ----
138 +
139 not
140 +
141 [source,sml]
142 ----
143 a -> (b -> c)
144 ----
145
146 * Type constructor application associates to the left, so write
147 +
148 [source,sml]
149 ----
150 int ref list
151 ----
152 +
153 not
154 +
155 [source,sml]
156 ----
157 (int ref) list
158 ----
159
160 * Type constructor application binds more tightly than a tuple type,
161 so write
162 +
163 [source,sml]
164 ----
165 int list * bool list
166 ----
167 +
168 not
169 +
170 [source,sml]
171 ----
172 (int list) * (bool list)
173 ----
174
175 * Tuple types bind more tightly than arrow types, so write
176 +
177 [source,sml]
178 ----
179 int * bool -> real
180 ----
181 +
182 not
183 +
184 [source,sml]
185 ----
186 (int * bool) -> real
187 ----
188
189
190 == Core ==
191
192 * A core expression or declaration split over multiple lines does not
193 contain any blank lines.
194
195 * A record field selector has no space between the `#` and the record
196 label. So, write
197 +
198 [source,sml]
199 ----
200 #foo
201 ----
202 +
203 not
204 +
205 [source,sml]
206 ----
207 # foo
208 ----
209 +
210
211 * A tuple has a space after each comma, but not before, and not at the
212 delimiters `(` and `)`.
213 +
214 [source,sml]
215 ----
216 (e1, e2, e3)
217 ----
218
219 * A tuple split over multiple lines has one element per line, and the
220 commas go at the end of the lines.
221 +
222 [source,sml]
223 ----
224 (e1,
225 e2,
226 e3)
227 ----
228
229 * A list has a space after each comma, but not before, and not at the
230 delimiters `[` and `]`.
231 +
232 [source,sml]
233 ----
234 [e1, e2, e3]
235 ----
236
237 * A list split over multiple lines has one element per line, and the
238 commas at the end of the lines.
239 +
240 [source,sml]
241 ----
242 [e1,
243 e2,
244 e3]
245 ----
246
247 * A record has spaces before and after `=`, a space after each comma,
248 but not before, and not at the delimiters `{` and `}`. Field names
249 appear in alphabetical order.
250 +
251 [source,sml]
252 ----
253 {bar = 13, foo = true}
254 ----
255
256 * A sequence expression has a space after each semicolon, but not before.
257 +
258 [source,sml]
259 ----
260 (e1; e2; e3)
261 ----
262
263 * A sequence expression split over multiple lines has one expression
264 per line, and the semicolons at the beginning of lines. Lisp and
265 Scheme programmers may find this hard to read at first.
266 +
267 [source,sml]
268 ----
269 (e1
270 ; e2
271 ; e3)
272 ----
273 +
274 _Rationale_: this makes it easy to visually spot the beginning of each
275 expression, which becomes more valuable as the expressions themselves
276 are split across multiple lines.
277
278 * An application expression has a space between the function and the
279 argument. There are no parens unless the argument is a tuple (in
280 which case the parens are really part of the tuple, not the
281 application).
282 +
283 [source,sml]
284 ----
285 f a
286 f (a1, a2, a3)
287 ----
288
289 * Avoid redundant parentheses. Application associates to left, so
290 write
291 +
292 [source,sml]
293 ----
294 f a1 a2 a3
295 ----
296 +
297 not
298 +
299 [source,sml]
300 ----
301 ((f a1) a2) a3
302 ----
303
304 * Infix operators have a space before and after the operator.
305 +
306 [source,sml]
307 ----
308 x + y
309 x * y - z
310 ----
311
312 * Avoid redundant parentheses. Use <:OperatorPrecedence:>. So, write
313 +
314 [source,sml]
315 ----
316 x + y * z
317 ----
318 +
319 not
320 +
321 [source,sml]
322 ----
323 x + (y * z)
324 ----
325
326 * An `andalso` expression split over multiple lines has the `andalso`
327 at the beginning of subsequent lines.
328 +
329 [source,sml]
330 ----
331 e1
332 andalso e2
333 andalso e3
334 ----
335
336 * A `case` expression is indented as follows
337 +
338 [source,sml]
339 ----
340 case e1 of
341 p1 => e1
342 | p2 => e2
343 | p3 => e3
344 ----
345
346 * A `datatype`'s constructors are alphabetized.
347 +
348 [source,sml]
349 ----
350 datatype t = A | B | C
351 ----
352
353 * A `datatype` declaration has a space before and after each `|`.
354 +
355 [source,sml]
356 ----
357 datatype t = A | B of int | C
358 ----
359
360 * A `datatype` split over multiple lines has one constructor per line,
361 with the `|` at the beginning of lines and the constructors beginning
362 3 columns to the right of the `datatype`.
363 +
364 [source,sml]
365 ----
366 datatype t =
367 A
368 | B
369 | C
370 ----
371
372 * A `fun` declaration may start its body on the subsequent line,
373 indented 3 spaces.
374 +
375 [source,sml]
376 ----
377 fun f x y =
378 let
379 val z = x + y + z
380 in
381 z
382 end
383 ----
384
385 * An `if` expression is indented as follows.
386 +
387 [source,sml]
388 ----
389 if e1
390 then e2
391 else e3
392 ----
393
394 * A sequence of `if`-`then`-`else`-s is indented as follows.
395 +
396 [source,sml]
397 ----
398 if e1
399 then e2
400 else if e3
401 then e4
402 else if e5
403 then e6
404 else e7
405 ----
406
407 * A `let` expression has the `let`, `in`, and `end` on their own
408 lines, starting in the same column. Declarations and the body are
409 indented 3 spaces.
410 +
411 [source,sml]
412 ----
413 let
414 val x = 13
415 val y = 14
416 in
417 x + y
418 end
419 ----
420
421 * A `local` declaration has the `local`, `in`, and `end` on their own
422 lines, starting in the same column. Declarations are indented 3
423 spaces.
424 +
425 [source,sml]
426 ----
427 local
428 val x = 13
429 in
430 val y = x
431 end
432 ----
433
434 * An `orelse` expression split over multiple lines has the `orelse` at
435 the beginning of subsequent lines.
436 +
437 [source,sml]
438 ----
439 e1
440 orelse e2
441 orelse e3
442 ----
443
444 * A `val` declaration has a space before and after the `=`.
445 +
446 [source,sml]
447 ----
448 val p = e
449 ----
450
451 * A `val` declaration can start the expression on the subsequent line,
452 indented 3 spaces.
453 +
454 [source,sml]
455 ----
456 val p =
457 if e1 then e2 else e3
458 ----
459
460
461 == Signatures ==
462
463 * A `signature` declaration is indented as follows.
464 +
465 [source,sml]
466 ----
467 signature FOO =
468 sig
469 val x: int
470 end
471 ----
472 +
473 _Exception_: a signature declaration in a file to itself can omit the
474 indentation to save horizontal space.
475 +
476 [source,sml]
477 ----
478 signature FOO =
479 sig
480
481 val x: int
482
483 end
484 ----
485 +
486 In this case, there should be a blank line after the `sig` and before
487 the `end`.
488
489 * A `val` specification has a space after the colon, but not before.
490 +
491 [source,sml]
492 ----
493 val x: int
494 ----
495 +
496 _Exception_: in the case of operators (like `+`), there is a space
497 before the colon to avoid lexing the colon as part of the operator.
498 +
499 [source,sml]
500 ----
501 val + : t * t -> t
502 ----
503
504 * Alphabetize specifications in signatures.
505 +
506 [source,sml]
507 ----
508 sig
509 val x: int
510 val y: bool
511 end
512 ----
513
514
515 == Structures ==
516
517 * A `structure` declaration has a space on both sides of the `=`.
518 +
519 [source,sml]
520 ----
521 structure Foo = Bar
522 ----
523
524 * A `structure` declaration split over multiple lines is indented as
525 follows.
526 +
527 [source,sml]
528 ----
529 structure S =
530 struct
531 val x = 13
532 end
533 ----
534 +
535 _Exception_: a structure declaration in a file to itself can omit the
536 indentation to save horizontal space.
537 +
538 [source,sml]
539 ----
540 structure S =
541 struct
542
543 val x = 13
544
545 end
546 ----
547 +
548 In this case, there should be a blank line after the `struct` and
549 before the `end`.
550
551 * Declarations in a `struct` are separated by blank lines.
552 +
553 [source,sml]
554 ----
555 struct
556 val x =
557 let
558 y = 13
559 in
560 y + 1
561 end
562
563 val z = 14
564 end
565 ----
566
567
568 == Functors ==
569
570 * A `functor` declaration has spaces after each `:` (or `:>`) but not
571 before, and a space before and after the `=`. It is indented as
572 follows.
573 +
574 [source,sml]
575 ----
576 functor Foo (S: FOO_ARG): FOO =
577 struct
578 val x = S.x
579 end
580 ----
581 +
582 _Exception_: a functor declaration in a file to itself can omit the
583 indentation to save horizontal space.
584 +
585 [source,sml]
586 ----
587 functor Foo (S: FOO_ARG): FOO =
588 struct
589
590 val x = S.x
591
592 end
593 ----
594 +
595 In this case, there should be a blank line after the `struct`
596 and before the `end`.