aboutsummaryrefslogtreecommitdiff
path: root/portToNewSyntax/1.3-and-2.0-differences.txt
blob: ceadbd59e77f2f86a0752c061e79a82cd79349b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
This file describes differences between Clean 1.3.x and Clean 2.x. It is aimed
to help you to port Clean 1.3.x programs to Clean 2.x

First of all: Clean 2.x is not downward compatible with Clean 1.3.x. Probably
you have to change your 1.3.x sources to get them through the Clean 2.x
compiler.

To be able to write Clean programs that can be compiled with both compiler
versions we have built a simple preprocessor into the Clean 2.x compiler. This
feature allows you to exclude certain parts of your source, depending on which
compiler version you use. See section "The Preprocessor" for details.

The following sections describe the differences in detail.

New Features in Clean 2.0
-------------------------

Clean 2.x has dynamic types, multiparameter type classes and generic classes.
For these items see the Clean language report.

With Clean 2.x cyclic dependencies between dcl modules are allowed.

Differences in Expression Syntax
--------------------------------

There is no strict let-before expression (let!) anymore in Clean 2.x. You still
can enforce strict evaluation using the strict hash let (#!).

Differences in the Type System
------------------------------

1. Array handling has become different, see section "Differences in the
   Standard environment

2.
  There is a difference in resolving overloading. Consider the following code:
  
     class c a :: a -> a
  
     instance c [Int]
       where
         c [1] = [2]

     f [x:xs]
       = c xs
  
  Although this is accepted by Clean 1.3.x, Clean 2.x will complain
   
     Overloading error [...,..,f]: c no instance available of type [a]
  
  The Clean 2.x compiler applies no type unification after resolving
  overloading. So c is in function f applied to a list with a polymorph element
  type ([a]). And this is considered to be different from the instance type
  [Int]. If you give f the type [Int] -> [Int] the upper code will be accepted.
  
3.
  Clean 2.x handles uniqueness attributes in type synonyms different than
  Clean 1.3.x. Consider the following definitions:
  
    :: ListList a :== [[a]]
  
    f :: *(ListList *{Int}) -> *{Int}
    f [[a]] = { a & [0]=0 }
  
  What does the ListList type synonym stand for in the type of f? In Clean 1.3.x the
  ListList type synonym was expanded to

    f :: *[*[*{Int}]] -> *{Int}
    
  whereas Clean 2.x expands it to
  
    f :: *[[*{Int}]] -> *{Int}
  
  This yields a uniqueness error in Clean 2.x because the inner list is shared
  but contains a unique object. Clean 1.3.x accepts the upper code.
  
  This problem happens only with type synonyms that have attributes "inbetween".
  What does this mean? An "inbetween" attribute is neither the "root" attribute
  nor the attribute of an actual argument.
  
  E.g. with the upper type synonym, the formal argument "a" is substituted with
  *{Int}. Note that also the "*" is substituted for "a". Further the whole
  result of expanding the type synonym gets the "root" attribute. Because we
  wrote *(ListList ...) the root attribute is "*". So far the result of
  expanding *(ListList *{Int}) is *[u:[*{Int]]. "u" is an attribute "inbetween"
  because it is neither the root attribute nor the attribute of a formal
  argument. Such attributes are made _non_unique_ in Clean 2.x and this is why
  the upper code is not accepted. The code will be accepted if you redefine
  ListList to 
  
    :: ListList a :== [*[a]]

4.
  The String type has become a basic type. As a consequence you cannot import
  this type explicitly:
    
    from StdString import :: String
  
  is not valid.

5.
  The Clean 1.3.x compiler has chosen lazy arrays whenever there was a choice.
  The Clean 2.x compiler will complain in these cases that internal overloading
  could not be solved. E.g.

    Start = size {1}

  is accepted by Clean 1.3.x but not by Clean 2.x.

6.
  Some bugs in the uniqueness typing system were fixed.

Differences in the Module System
--------------------------------

  The syntax and semantics of explicit import statements has been completely
  revised. With Clean 2.x it is
  possible to discriminate the different namespaces in import statements.
  In Clean 1.3.x the following statement
  
    from m import F
  
  could have caused the import of a function F together with a type F and a
  class F with all its instances from m. The syntax of Clean 2.x import
  statements is given below in the style that is also used in the Clean language
  report:
  
    ExplicitImportDef    = "from" ModuleName "import" {Imports}-list ";"
    Imports              = FunctionName                  
                         | "::" TypeName [ConstructorsOrFields]
    			           | "class" ClassName [Members]
                         | "instance" ClassName {TypeName}+
    ConstructorsOrFields = "(" ".." ")" 
                         | "{" ".." "}"
                         | "(" {ConstructorName}-list ")"
                         | "{" {FieldName}-list "}"
    Members              = "(" ".." ")" 
                         | "(" {MemberName}-list ")"

  Explanation:
    [notion]       means that the presence of notion is optional
    {notion}+      means that notion occurs at least once
    {notion}-list  means one or more occurrences of notion separated by commas
  
    Terminals are enclosed in apostrophes. All missing nonterminals are simply
    identifiers.
  
  For example the following import statement
  
    from m import F, :: T1, :: T2(..), :: T3(C1, C2), :: T4{..}, 
                  :: T5{field1, field2}, class C1, class C2(..), 
                  class C3(mem1, mem2)
  
  causes the following declarations to be imported:
  
    the function or macro F, the type T1, the algebraic type T2 with all it's
    constructors that are exported by m, the algebraic type T3 with it's 
    constructors C1 and C2, the record type T4 with all it's fields that are
    exported by m, the record type T5 with it's fields field1 and field2,
    the class C1, the class C2 with all it's members that are exported by m,
    the class C3 with it's members mem1 and mem2.
                 
  There is a tool called "coclPort" that is able to automatically convert
  Clean sources with 1.3.x import syntax to sources with 2.x syntax.
  
  Hint: The appearance of the compiler error message "... not exported as a
  function/macro by the specified module" is not a compiler bug. You probably
  forgot the "::" before a type identifier

Differences in the standard environment (StdEnv)
------------------------------------------------

*&^ HOI ALLEMAAL, DEZE WIJZIGINGEN IN HET STDENV ZIJN NOG NIET GEDAAN *&@#@
*&^ THESE CHANGES IN THE STDENV ARE PLANNED BUT NOT DONE *&@#@
1.
  We removed some definitions from the StdEnv. 

    instance toString [a]                    // in StdList
    instance < (a,b), instance < (a,b,c)     // in StdTuple
    instance == (a,b), instance == (a,b,c)   // in StdTuple

  We defined a module port.dcl/icl. This module contains these definitions.

2.
  We changed the behaviour of the following functions:

    take in StdList
         Clean 1.3.x: i<0 => take i x==x
         Clean 2.x  : i<0 => take i x==[]
    instance mod Int in StdInt
         In Clean 2.0: sign m==sign (n mod m)
                       This keeps the invariant n == m*(n div m) + (n mod m)
                           where div is division truncated to minus infinity
                       This is the behaviour people expect from a mod operator.
                       In Clean 1.3 the following invariant was kept:
                            n == m*(n/m) + (n mod m) where "/" truncates to 0.
                       Note that a difference only appears if exactly one
                       argument is negative
    
3.
  We changed the argument order of the functions (s)freads, (s)fseek, freopen
  in module StdFile such that the File argument is the last argument.

4.
  We fixed some bugs:
    - the createArray instances in module StdArray don't crash anymore for
      negative size arguments.
    - gcd's results are now correct for the case that the result is in the range of
      Int. In Clean 1.3.x it was not correct in cases when one argument was
      minInt.

5. 
  Array handling has become different. In Clean 2.x the Array class is a
  multiparameter class, whose first argument type is the array and whose
  second argument type is the array element. Therefore the following classes
  have vanished:

    ArrayElem, _uselectf, _uselectn, _uselectl, _updatei, _createArrayc,select_u
    uselect_u, uselectf_u, uselectn_u, uselectl_u, updatei_u, size_u, usize_u
    update_u, createArray_u, createArrayc_u, replace_u

  Example: Assume a function "f" that does something with arrays that had
  the following type in Clean 1.3:

    f :: (a b) -> b | select_u b & Array .a

  "(a b)" stands for "an array (can be strict, lazy or unboxed) with element b".
  In Clean 2.x this simply becomes:

    f :: (a b) -> b | Array a b


Miscellaneous Differences
-------------------------

1.
  For multiparameter type classes a small change in the syntax for instance
  definitions was necessary. In Clean 1.3.x it was assumed that every instance
  definition only has one type argument. So in the following 1.3.x instance
  definition
  
    instance c T1 T2
  
  the type "(T1 T2)" was meant (the type T1 with the argument T2). If this was
  the intention then this should be written in Clean 2.x as
  
    instance c (T1 T2)
  
  otherwise T1 and T2 will be interpreted as two types.
  
2.
  Anonymous uniqueness attributes in type contexts are not allowed in Clean 2.x.
  So in the following function type 

    f :: a | myClass .a

  simply remove the point.

3.
  There are differences in some libraries. See the library's documentation.

The Preprocessor
----------------

We think that for a while it should be made possible to let every source code
file be compiled with both the 1.3 and the 2.0 compiler. How can this be
achieved when the 2.0 compiler is not fully downward compatible? With a
preprocessor of course. The simple preprocessor that we have built into
into the 2.0 compiler has to distinguish parts of code that are either ignored
by the 1.3 compiler or by the 2.0 compiler. To illustrate this we show how you
could use the preprocessor to cope with the principial incompatibilities
in conjunction with arrays. Let's suppose you have a function defined like this

  g a i
    = a.[i]

and you want to write down the type for that function.
This function has really different principial types in Clean 1.3.x and Clean 2.x.
Your code is still compilable with both compiler versions if you write the
 following:

  //1.3
  g :: u:(a v:b) .Int -> v:b | select_u b & Array .a, [u <= v]
  //3.1
  /*2.0
  g :: .(a u:b) v:Int -> u:b | Array a b, [v <= u]
  0.2*/
  g a i
    = a.[i]

For the 2.0 compiler this would be the same as

  g :: .(a u:b) v:Int -> u:b | Array a b, [v <= u]
  g a i
    = a.[i]

because the preprocessor will take care that everything between "//1.3" and
"//3.1" will be ignored and that everything between "/*2.0" and "0.2*/"
will _not_ be treated as a comment.
For the 1.3 this would be the same as 

  g :: u:(a v:b) .Int -> v:b | select_u b & Array .a, [u <= v]
  g a i
    = a.[i]

Note that the "//1.3", "//3.1", "/*2.0" and "0.2*/" brackets have to be
the first characters of the line (no preceeding whitespace characters are
allowed). Otherwise they will be ignored. Furtheron such sections should
neither be nested nor overlapping.

Finally we have written an application "rmPreprop" that can be used to remove
all these preprocessor directives when you don't want them anymore.

We will remove the preprocessor in the future. Regard it as
a temporary feature.