Import Upstream version 20180207
[hcoop/debian/mlton.git] / doc / guide / src / SyntacticConventions.adoc
CommitLineData
7f918cf1
CE
1SyntacticConventions
2====================
3:toc:
4
5Here are a number of syntactic conventions useful for programming in
6SML.
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
25small letters, using capital letters to separate words.
26+
27[source,sml]
28----
29cost
30maxValue
31----
32
33* Variables that represent collections of objects (lists, arrays,
34vectors, ...) are often suffixed with an `s`.
35+
36[source,sml]
37----
38xs
39employees
40----
41
42* Constructors, structure identifiers, and functor identifiers begin
43with a capital letter.
44+
45[source,sml]
46----
47Queue
48LinkedList
49----
50
51* Signature identifiers are in all capitals, using `_` to separate
52words.
53+
54[source,sml]
55----
56LIST
57BINARY_HEAP
58----
59
60
61== Types ==
62
63* Alphabetize record labels. In a record type, there are spaces after
64colons and commas, but not before colons or commas, or at the
65delimiters `{` 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
73one line. If a record type must be split over multiple lines, put one
74field 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----
88int * bool * real
89----
90
91* Only split a tuple type across multiple lines if it doesn't fit on
92one line. In a tuple type split over multiple lines, there is one
93type per line, and the `*`-s go at the beginning of the lines.
94+
95[source,sml]
96----
97int
98* bool
99* real
100----
101+
102It may also be useful to parenthesize to make the grouping more
103apparent.
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
113beginning of its line.
114+
115[source,sml]
116----
117int * real
118-> bool
119----
120+
121It may also be useful to parenthesize to make the grouping more
122apparent.
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----
136a -> b -> c
137----
138+
139not
140+
141[source,sml]
142----
143a -> (b -> c)
144----
145
146* Type constructor application associates to the left, so write
147+
148[source,sml]
149----
150int ref list
151----
152+
153not
154+
155[source,sml]
156----
157(int ref) list
158----
159
160* Type constructor application binds more tightly than a tuple type,
161so write
162+
163[source,sml]
164----
165int list * bool list
166----
167+
168not
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----
179int * bool -> real
180----
181+
182not
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
193contain any blank lines.
194
195* A record field selector has no space between the `#` and the record
196label. So, write
197+
198[source,sml]
199----
200#foo
201----
202+
203not
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
212delimiters `(` 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
220commas 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
230delimiters `[` 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
238commas 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,
248but not before, and not at the delimiters `{` and `}`. Field names
249appear 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
264per line, and the semicolons at the beginning of lines. Lisp and
265Scheme 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
275expression, which becomes more valuable as the expressions themselves
276are split across multiple lines.
277
278* An application expression has a space between the function and the
279argument. There are no parens unless the argument is a tuple (in
280which case the parens are really part of the tuple, not the
281application).
282+
283[source,sml]
284----
285f a
286f (a1, a2, a3)
287----
288
289* Avoid redundant parentheses. Application associates to left, so
290write
291+
292[source,sml]
293----
294f a1 a2 a3
295----
296+
297not
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----
308x + y
309x * y - z
310----
311
312* Avoid redundant parentheses. Use <:OperatorPrecedence:>. So, write
313+
314[source,sml]
315----
316x + y * z
317----
318+
319not
320+
321[source,sml]
322----
323x + (y * z)
324----
325
326* An `andalso` expression split over multiple lines has the `andalso`
327at the beginning of subsequent lines.
328+
329[source,sml]
330----
331e1
332andalso e2
333andalso e3
334----
335
336* A `case` expression is indented as follows
337+
338[source,sml]
339----
340case 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----
350datatype t = A | B | C
351----
352
353* A `datatype` declaration has a space before and after each `|`.
354+
355[source,sml]
356----
357datatype t = A | B of int | C
358----
359
360* A `datatype` split over multiple lines has one constructor per line,
361with the `|` at the beginning of lines and the constructors beginning
3623 columns to the right of the `datatype`.
363+
364[source,sml]
365----
366datatype t =
367 A
368 | B
369 | C
370----
371
372* A `fun` declaration may start its body on the subsequent line,
373indented 3 spaces.
374+
375[source,sml]
376----
377fun 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----
389if e1
390 then e2
391else e3
392----
393
394* A sequence of `if`-`then`-`else`-s is indented as follows.
395+
396[source,sml]
397----
398if e1
399 then e2
400else if e3
401 then e4
402else if e5
403 then e6
404else e7
405----
406
407* A `let` expression has the `let`, `in`, and `end` on their own
408lines, starting in the same column. Declarations and the body are
409indented 3 spaces.
410+
411[source,sml]
412----
413let
414 val x = 13
415 val y = 14
416in
417 x + y
418end
419----
420
421* A `local` declaration has the `local`, `in`, and `end` on their own
422lines, starting in the same column. Declarations are indented 3
423spaces.
424+
425[source,sml]
426----
427local
428 val x = 13
429in
430 val y = x
431end
432----
433
434* An `orelse` expression split over multiple lines has the `orelse` at
435the beginning of subsequent lines.
436+
437[source,sml]
438----
439e1
440orelse e2
441orelse e3
442----
443
444* A `val` declaration has a space before and after the `=`.
445+
446[source,sml]
447----
448val p = e
449----
450
451* A `val` declaration can start the expression on the subsequent line,
452indented 3 spaces.
453+
454[source,sml]
455----
456val 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----
467signature FOO =
468 sig
469 val x: int
470 end
471----
472+
473_Exception_: a signature declaration in a file to itself can omit the
474indentation to save horizontal space.
475+
476[source,sml]
477----
478signature FOO =
479sig
480
481val x: int
482
483end
484----
485+
486In this case, there should be a blank line after the `sig` and before
487the `end`.
488
489* A `val` specification has a space after the colon, but not before.
490+
491[source,sml]
492----
493val x: int
494----
495+
496_Exception_: in the case of operators (like `+`), there is a space
497before the colon to avoid lexing the colon as part of the operator.
498+
499[source,sml]
500----
501val + : t * t -> t
502----
503
504* Alphabetize specifications in signatures.
505+
506[source,sml]
507----
508sig
509 val x: int
510 val y: bool
511end
512----
513
514
515== Structures ==
516
517* A `structure` declaration has a space on both sides of the `=`.
518+
519[source,sml]
520----
521structure Foo = Bar
522----
523
524* A `structure` declaration split over multiple lines is indented as
525follows.
526+
527[source,sml]
528----
529structure S =
530 struct
531 val x = 13
532 end
533----
534+
535_Exception_: a structure declaration in a file to itself can omit the
536indentation to save horizontal space.
537+
538[source,sml]
539----
540structure S =
541struct
542
543val x = 13
544
545end
546----
547+
548In this case, there should be a blank line after the `struct` and
549before the `end`.
550
551* Declarations in a `struct` are separated by blank lines.
552+
553[source,sml]
554----
555struct
556 val x =
557 let
558 y = 13
559 in
560 y + 1
561 end
562
563 val z = 14
564end
565----
566
567
568== Functors ==
569
570* A `functor` declaration has spaces after each `:` (or `:>`) but not
571before, and a space before and after the `=`. It is indented as
572follows.
573+
574[source,sml]
575----
576functor 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
583indentation to save horizontal space.
584+
585[source,sml]
586----
587functor Foo (S: FOO_ARG): FOO =
588struct
589
590val x = S.x
591
592end
593----
594+
595In this case, there should be a blank line after the `struct`
596and before the `end`.