aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--portToNewSyntax/1.3-and-2.0-differences.txt311
1 files changed, 311 insertions, 0 deletions
diff --git a/portToNewSyntax/1.3-and-2.0-differences.txt b/portToNewSyntax/1.3-and-2.0-differences.txt
new file mode 100644
index 0000000..85b338b
--- /dev/null
+++ b/portToNewSyntax/1.3-and-2.0-differences.txt
@@ -0,0 +1,311 @@
+This file describes differences between Clean 1.3.x and 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 we 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.
+ 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.
+ 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.
+ There was a bug in the uniqueness typing system: Records or data constructors
+ could have existentially quantified variables, whose uniqueness attribute
+ did _not_ propagate. So it was possible to write
+
+ f :: *{Int} -> Int
+ f a
+ #! a0 = a.[0]
+ a = { a & [0] = a0+1 }
+ = a.[0]
+
+ :: T = E..x: C (x->Int) x
+
+ getInt (C f x) = f x
+
+ Start
+ # myObject = C f {0}
+ = (getInt myObject, getInt myObject)
+
+ which resulted in (1,2), which isn't that much referential transparent. This
+ bug has been solved in Clean 2.x.
+
+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
+
+
+Miscellaneous Differences
+-------------------------
+
+1.
+ 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.
+
+2.
+ 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 shouldn't
+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 feature in the future. Regard it as
+a temporary feature.