Import Upstream version 20180207
[hcoop/debian/mlton.git] / doc / guide / src / SMLNJDeviations.adoc
1 SMLNJDeviations
2 ===============
3
4 Here are some deviations of <:SMLNJ:SML/NJ> from
5 <:DefinitionOfStandardML:The Definition of Standard ML (Revised)>.
6 Some of these are documented in the
7 http://www.smlnj.org/doc/Conversion/index.html[SML '97 Conversion Guide].
8 Since MLton does not deviate from the Definition, you should look here
9 if you are having trouble porting a program from MLton to SML/NJ or
10 vice versa. If you discover other deviations of SML/NJ that aren't
11 listed here, please send mail to
12 mailto:MLton-devel@mlton.org[`MLton-devel@mlton.org`].
13
14 * SML/NJ allows spaces in long identifiers, as in `S . x`. Section
15 2.5 of the Definition implies that `S . x` should be treated as three
16 separate lexical items.
17
18 * SML/NJ allows `op` to appear in `val` specifications:
19 +
20 [source,sml]
21 ----
22 signature FOO = sig
23 val op + : int * int -> int
24 end
25 ----
26 +
27 The grammar on page 14 of the Definition does not allow it. Recent
28 versions of SML/NJ do give a warning.
29
30 * SML/NJ rejects
31 +
32 [source,sml]
33 ----
34 (op *)
35 ----
36 +
37 as an unmatched close comment.
38
39 * SML/NJ allows `=` to be rebound by the declaration:
40 +
41 [source,sml]
42 ----
43 val op = = 13
44 ----
45 +
46 This is explicitly forbidden on page 5 of the Definition. Recent
47 versions of SML/NJ do give a warning.
48
49 * SML/NJ allows rebinding `true`, `false`, `nil`, `::`, and `ref` by
50 the declarations:
51 +
52 [source,sml]
53 ----
54 fun true () = ()
55 fun false () = ()
56 fun nil () = ()
57 fun op :: () = ()
58 fun ref () = ()
59 ----
60 +
61 This is explicitly forbidden on page 9 of the Definition.
62
63 * SML/NJ extends the syntax of the language to allow vector
64 expressions and patterns like the following:
65 +
66 [source,sml]
67 ----
68 val v = #[1,2,3]
69 val #[x,y,z] = v
70 ----
71 +
72 MLton supports vector expressions and patterns with the <:SuccessorML#VectorExpsAndPats:`allowVectorExpsAndPats`> <:MLBasisAnnotations:ML Basis annotation>.
73
74 * SML/NJ extends the syntax of the language to allow _or patterns_
75 like the following:
76 +
77 [source,sml]
78 ----
79 datatype foo = Foo of int | Bar of int
80 val (Foo x | Bar x) = Foo 13
81 ----
82 +
83 MLton supports or patterns with the <:SuccessorML#OrPats:`allowOrPats`> <:MLBasisAnnotations:ML Basis annotation>.
84
85 * SML/NJ allows higher-order functors, that is, functors can be
86 components of structures and can be passed as functor arguments and
87 returned as functor results. As a consequence, SML/NJ allows
88 abbreviated functor definitions, as in the following:
89 +
90 [source,sml]
91 ----
92 signature S =
93 sig
94 type t
95 val x: t
96 end
97 functor F (structure A: S): S =
98 struct
99 type t = A.t * A.t
100 val x = (A.x, A.x)
101 end
102 functor G = F
103 ----
104
105 * SML/NJ extends the syntax of the language to allow `functor` and
106 `signature` declarations to occur within the scope of `local` and
107 `structure` declarations.
108
109 * SML/NJ allows duplicate type specifications in signatures when the
110 duplicates are introduced by `include`, as in the following:
111 +
112 [source,sml]
113 ----
114 signature SIG1 =
115 sig
116 type t
117 type u
118 end
119 signature SIG2 =
120 sig
121 type t
122 type v
123 end
124 signature SIG =
125 sig
126 include SIG1
127 include SIG2
128 end
129 ----
130 +
131 This is disallowed by rule 77 of the Definition.
132
133 * SML/NJ allows sharing constraints between type abbreviations in
134 signatures, as in the following:
135 +
136 [source,sml]
137 ----
138 signature SIG =
139 sig
140 type t = int * int
141 type u = int * int
142 sharing type t = u
143 end
144 ----
145 +
146 These are disallowed by rule 78 of the Definition. Recent versions of
147 SML/NJ correctly disallow sharing constraints between type
148 abbreviations in signatures.
149
150 * SML/NJ disallows multiple `where type` specifications of the same
151 type name, as in the following
152 +
153 [source,sml]
154 ----
155 signature S =
156 sig
157 type t
158 type u = t
159 end
160 where type u = int
161 ----
162 +
163 This is allowed by rule 64 of the Definition.
164
165 * SML/NJ allows `and` in `sharing` specs in signatures, as in
166 +
167 [source,sml]
168 ----
169 signature S =
170 sig
171 type t
172 type u
173 type v
174 sharing type t = u
175 and type u = v
176 end
177 ----
178
179 * SML/NJ does not expand the `withtype` derived form as described by
180 the Definition. According to page 55 of the Definition, the type
181 bindings of a `withtype` declaration are substituted simultaneously in
182 the connected datatype. Consider the following program.
183 +
184 [source,sml]
185 ----
186 type u = real ;
187 datatype a =
188 A of t
189 | B of u
190 withtype u = int
191 and t = u
192 ----
193 +
194 According to the Definition, it should be expanded to the following.
195 +
196 [source,sml]
197 ----
198 type u = real ;
199 datatype a =
200 A of u
201 | B of int ;
202 type u = int
203 and t = u
204 ----
205 +
206 However, SML/NJ expands `withtype` bindings sequentially, meaning that
207 earlier bindings are expanded within later ones. Hence, the above
208 program is expanded to the following.
209 +
210 [source,sml]
211 ----
212 type u = real ;
213 datatype a =
214 A of int
215 | B of int ;
216 type u = int
217 type t = int
218 ----
219
220 * SML/NJ allows `withtype` specifications in signatures.
221 +
222 MLton supports `withtype` specifications in signatures with the <:SuccessorML#SigWithtype:`allowSigWithtype`> <:MLBasisAnnotations:ML Basis annotation>.
223
224 * SML/NJ allows a `where` structure specification that is similar to a
225 `where type` specification. For example:
226 +
227 [source,sml]
228 ----
229 structure S = struct type t = int end
230 signature SIG =
231 sig
232 structure T : sig type t end
233 end where T = S
234 ----
235 +
236 This is equivalent to:
237 +
238 [source,sml]
239 ----
240 structure S = struct type t = int end
241 signature SIG =
242 sig
243 structure T : sig type t end
244 end where type T.t = S.t
245 ----
246 +
247 SML/NJ also allows a definitional structure specification that is
248 similar to a definitional type specification. For example:
249 +
250 [source,sml]
251 ----
252 structure S = struct type t = int end
253 signature SIG =
254 sig
255 structure T : sig type t end = S
256 end
257 ----
258 +
259 This is equivalent to the previous examples and to:
260 +
261 [source,sml]
262 ----
263 structure S = struct type t = int end
264 signature SIG =
265 sig
266 structure T : sig type t end where type t = S.t
267 end
268 ----
269
270 * SML/NJ disallows binding non-datatypes with datatype replication.
271 For example, it rejects the following program that should be allowed
272 according to the Definition.
273 +
274 [source,sml]
275 ----
276 type ('a, 'b) t = 'a * 'b
277 datatype u = datatype t
278 ----
279 +
280 This idiom can be useful when one wants to rename a type without
281 rewriting all the type arguments. For example, the above would have
282 to be written in SML/NJ as follows.
283 +
284 [source,sml]
285 ----
286 type ('a, 'b) t = 'a * 'b
287 type ('a, 'b) u = ('a, 'b) t
288 ----
289
290 * SML/NJ disallows sharing a structure with one of its substructures.
291 For example, SML/NJ disallows the following.
292 +
293 [source,sml]
294 ----
295 signature SIG =
296 sig
297 structure S:
298 sig
299 type t
300 structure T: sig type t end
301 end
302 sharing S = S.T
303 end
304 ----
305 +
306 This signature is allowed by the Definition.
307
308 * SML/NJ disallows polymorphic generalization of refutable
309 patterns. For example, SML/NJ disallows the following.
310 +
311 [source,sml]
312 ----
313 val [x] = [[]]
314 val _ = (1 :: x, "one" :: x)
315 ----
316 +
317 Recent versions of SML/NJ correctly allow polymorphic generalization
318 of refutable patterns.
319
320 * SML/NJ uses an overly restrictive context for type inference. For
321 example, SML/NJ rejects both of the following.
322 +
323 [source,sml]
324 ----
325 structure S =
326 struct
327 val z = (fn x => x) []
328 val y = z :: [true] :: nil
329 end
330 ----
331 +
332 [source,sml]
333 ----
334 structure S : sig val z : bool list end =
335 struct
336 val z = (fn x => x) []
337 end
338 ----
339 +
340 These structures are allowed by the Definition.
341
342 == Deviations from the Basis Library Specification ==
343
344 Here are some deviations of SML/NJ from the <:BasisLibrary:Basis Library>
345 http://www.standardml.org/Basis[specification].
346
347 * SML/NJ exposes the equality of the `vector` type in structures such
348 as `Word8Vector` that abstractly match `MONO_VECTOR`, which says
349 `type vector`, not `eqtype vector`. So, for example, SML/NJ accepts
350 the following program:
351 +
352 [source,sml]
353 ----
354 fun f (v: Word8Vector.vector) = v = v
355 ----
356
357 * SML/NJ exposes the equality property of the type `status` in
358 `OS.Process`. This means that programs which directly compare two
359 values of type `status` will work with SML/NJ but not MLton.
360
361 * Under SML/NJ on Windows, `OS.Path.validVolume` incorrectly considers
362 absolute empty volumes to be valid. In other words, when the
363 expression
364 +
365 [source,sml]
366 ----
367 OS.Path.validVolume { isAbs = true, vol = "" }
368 ----
369 +
370 is evaluated by SML/NJ on Windows, the result is `true`. MLton, on
371 the other hand, correctly follows the Basis Library Specification,
372 which states that on Windows, `OS.Path.validVolume` should return
373 `false` whenever `isAbs = true` and `vol = ""`.
374 +
375 This incorrect behavior causes other `OS.Path` functions to behave
376 differently. For example, when the expression
377 +
378 [source,sml]
379 ----
380 OS.Path.toString (OS.Path.fromString "\\usr\\local")
381 ----
382 +
383 is evaluated by SML/NJ on Windows, the result is `"\\usr\\local"`,
384 whereas under MLton on Windows, evaluating this expression (correctly)
385 causes an `OS.Path.Path` exception to be raised.