Welcome to F#. F# is a programming language for the .NET platform with a design based on the ML programming language with extensions to access .NET libraries. This release contains
Full details can be found at the F# website. There you can find details about how to join the F# email list. You may be interested in tracking Don Syme's F# blog and/or blogging about your experiences with using F#.
Installation:
Using and Learning:
Troubleshooting:
You may run F# programs in conjunction with other CLI implementations such as Mono. Please read the notes below. Some more information is available at the F# Wiki.
Lightweight syntax option. Are you sick of writing in? The #light option makes the use of certain keywords such as in optional by using indentation. See the informal language specification for details, as well as the ConcurrentLife sample and the Samples101 tutorial. Enable using #light.
First experimental cut at the Active Patterns. More details to follow on Don Syme's blog.
More modules in MLLib. Modules UInt8, Int8, Int16, UInt16 have been added.
More collections in Microsoft.FSharp.Collections. The Set and Map collections are now defined as object-oriented abstractions in Microsoft.FSharp.Collections. The corresponding MLLib modules are defined in terms of these OO abstractions.
Removed deprecated Stream module from MLLib. Minor updates to the LazyList module as a result.
--gnu-style-errors flag no longer accepts spurious integer argument.
Slight modification to overloading for +,*,/,mod.
In version 1.1.11 a slight change was made to the default overloaded signature for - operator to allow the return type to be unassociated to the two input types, as is required for overloading on the System.DateTime subtraction operator. This change was mistakenly applied to other operators, resulting in situations where type inference would report unexpected inference errors for fairly straight-forward floating point code.
Bug fixes.
--- F# Compiler -R clobbers DLLs with PDBs
--- F# Compiler no properties being generated for top level values
605 F# Visual Studio VFSI scroll to caret does not always show input position
643 F# Compiler internal warning when unpickling override of abstract member
655 F# Compiler interface implementing methods marked private but included in modul_typ
656 F# Compiler Runtime exception TypeLoadException method 'Specialize'... tried to implicitly override a method with weaker type parameter constraints
645 F# Debug problems setting breakpoints in inner functions (reported by Jack Palevich - thanks Jack!)
647 F# Compiler lowercase constructors are incorrectly permitted
654 F# Interactive cannot declare delegate types interactively
672 F# Visual Studio Unapplied methods should give signature of method overloads in error message
671 F# Compiler -R feature overwrites .dll file with .pdb file
670 F# Compiler protected access not permitted via member 'this' variables
668 F# Language L-R type inference with (fun x -> x * x * 1.0)
667 F# Language exceptions to carry line numbers?
663 Fix broken codegen for generalized constrained polymorphic functions
659 F# Visual Studio Intellisense does not work in a for .. to .. do line
676 F# Visual Studio Inappropriate popup
644 F# Language execution and inference for record expressions is not always left-to-right
533 F# Release proper uninstaller
517 F# Compiler fsi.exe does not process #r/#I directives for files on command line
678 F# Library delete very old obsolete functionality fro the 'Set' module
679 F# Library Add object-oriented version of immutable 'Sets' to Microsoft.FSharp.Collections
681 F# Visual Studio hardwhite intelisense
682 F# Compiler field and property names with same name - allowed
680 F# Visual Studio intelisense bugs
665 F# Language exprs ending in semi-expr sequences cause confusion when ending constructs which are themselves semi separated.
Copy-Local reference options DLLs that are not in the GAC must be copied to an application's directory prioer to execution. This is not currently well-supported by the F# Visual Studio mode. Thus the following options are now supported by the fsc.exe compiler and are especially recommended for use from Visual Studio:
-R DLL both reference the given DLL and copy it to the output directory at the end of compilation --copy-local FILE copy the given file to the output directory at the end of compilation
Note that -R = -r + --copy-local. Also these switches are not required by fsi.exe which is able to resolve and load DLLs from any location.
New Installer InstallFSharp.msi. This currently always installs to the Program Files directory.
New library module Microsoft.FSharp.MLLib.Native Helpers for native interop. See library documentation.
Minor breaking change for native pointers. The F# "'a nativeptr" is
now compiled as the .NET type System.IntPtr for all 'a.
.NET pointers such as "int*" are now represented by "ilsigptr
COMPILED and INTERACTIVE supported as standard --define in F# Interactive and compiled code This is useful as some code fragments such as Application.Run() are only needed in compiled code. Also accessing things such as resources can vary between interactive and compiled code.
Type Inference corrections for fields and records
It is implicit in the F# informal specification that record constructions should use contextual left-to-right type information to help determine the type being constructed. This is now implemented, and makes it easier to use record syntax when record member names overlap.
Types are no longer inferred from uses of class field labels alone. Previously, defining a class "C" with a value field called, say "f" meant that "f" became a scoped record label. This meant that "expr.f" would infer the type of "expr" to be "C". This is still done for _record_ labels, but is no longer done for class field labels, and instead an annotation may be needed to constrain the type of "expr" based on left-to-right type inference. A helpful warning about the deprecation of this language feature is given when this occurs. This was always meant to be the intended treatment of inference for these constructs - it was an artefact of the initial implementation that inference for record field labels was treated in this way.
Various .NET generic constraints implemented .NET generics supports a number of somewhat adhoc constraints on the structural properties of types. It is necessary for F# to support these in order to emit correct and valid generic code and make sound use of F# libraries. The syntax of the constraints is:
when 'a : struct // any struct, with the exception of Nullable when 'a : not struct // any reference type - note - this syntax is under revision when 'a : (new : unit -> 'a) // default constructor
The following F#-specific constraint has also been added:
when 'a : null // any reference type that supports null according to the F# pseudo-enforcement rules for prohibiting the use of null with F# types when default 'a : <type> // the variable will take the given value if not otherwise instantiated or generalized
Default constructors are called using the syntax:
new 'a()
Where 'a should be related to another annotation in the same definition, e.g. an argument of the enclosing function. This constructs is compiled as a call to System.Activator.CreateInstance<'a>().
Minor improvements and Bug Fixes
573 F# Compiler list equality is not tail recursive. 613 F# Library List.combine and List.split are not tail recursive (reported by Ralf Herbrich - thanks Ralf!) 615 F# Interactive FSI reflection code throws TypeLoad error for type reference within the same interaction. 602 F# Compiler name of type not reported in "member required" error 120 F# Compiler Things stored in public static fields should only be accessible via properties 495 F# Compiler SQL cannot load F# assemblies due to publically writable statics 625 F# Compiler Poor error location for error messages related to 'new' in signatures 626 F# Library Add 'generate' methods to IEnumerable. 628 F# Compiler nested ifdefs not always handled correctly (Reported by Jack Palevich - thanks Jack!) 630 F# Compiler Error writing assembly with F# 1.1.11.7 (reported by Lewis Bruck - thanks Lewis!) 631 F# Compiler System.MethodAccessException thrown by FSI.EXE (reported by Pierre Dangauthier - thanks Pierre!) 634 F# Compiler object expression limitations: let bound object expressions not generalized (reported by Greg Neverov - thanks Greg!) 640 F# Compiler record fields should be inferred from the known context type of the expression 639 F# Compiler class fields are contributing to the record field environemnt 638 F# Compiler multiple constraints on type parameters not being correctly printed 636 F# Compiler simple object expressions implementing interfaces should be allowed in "let rec" without generating an iniitalization graph warning 632 F# Debug smoother debugging needed for inner recursive functions 648 F# Library Documentation for printf codes for 64-bit integers is incorrect (reported by Richard Mortier - thanks Richard!) 650 F# Compiler incorrectly permitting the declaration of interfaces that contain fields (reported by Robert Pickering - thanks Robert!) 649 F# Compiler bug in quotation template filling for typed quotations (Reported by Tomas Petricek - thanks Tomas!) 646 F# Compiler attributes on top level values not propagating to generated static fields, e.g. ThreadStatic (reported by Robert Pickering - thanks Robert!) 645 F# Debug setting breakpoints in inner functions sort of broken (reported by Jack Palevich - thanks Jack!)
Minor improvements and Bug Fixes
-- Fix to permit the use of lambdas taking multiple tupled arguments within quotations.
-- Fix integer formats 0b101001 and 0o101030 in fsi.exe
-- Fix inlining of composition operator
-- Add signature to 'prim-types', hiding the presence of the "Basics" module
-- Fix optimization of integer keys for hash tables
F# Language: Namespaces.. Multiple namespaces fragments now permitted in a single file. Multiple fragments can also be constrained by a single signature. Multiple different files within an assembly may also contribute to the same namespace. For example:
/// Put the concrete type definition under 'Types'
namespace Microsoft.FSharp.Math.Types
type BigComplex = { r: bignum; i: bignum }
/// Now add a type abbreviation and module under the main namespace
namespace Microsoft.FSharp.Math
type bigcomplex = Microsoft.FSharp.Math.Types.BigComplex
module BigComplex = begin
open Microsoft.FSharp.Math.Types
let complex r i = { new BigComplex with r=r;i=i }
end
F# Language: Use of null values no longer require type annotations. null values previously required immediate type information. Instead, null constraints have now been incorporated into the inference process, meaning that the type associated with the use of the null value must simply be resolved at some point in the type inference scope. This means far fewer type annotations are needed when passing 'null' values to .NET.
F# Language/Library: Implementation of Structural comparison, equality and hashing now in F# code (hence easier to understand and debug). See the file prim-types.fs in the library for the implementation of the definition of structural and physical equality, used if all other optimization techniques fail.
F# Language: More General Type Checking Rule for Class Field Access and Setting. Accessing and setting a class field previously required the object being accessed to have precisely the type of the class containing that field. This has been liberalized so that the object can have any subtype of the class containing the field. This change may affect code that uses signatures, because the inferred type of a function may be more general. For example, given
type MChan =
class
val mutable sndLst : MChan list
end
let linkMChan src dstLst = src.sndLst <- append src.sndLst dstLst
the inferred type of linkMChan was previously
val linkMChan : MChan -> MChan list -> unit
but is now the more general
val linkMChan : #MChan -> MChan list -> unit
where as usual the # indicates that any subtype is accepted as the first argument. If no subtyping is required then a rigid type annotation may be used in the implementation:
let linkMChan (src : MChan) dstLst = src.sndLst <- append src.sndLst dstLst
F# Language: Overload Resolution when Multiple Overloaded Operators Exist. Some .NET types support multiple overloads for the same operator, which must be resolved according to a process similar to the resolution of overloaded methods. F# uses constraints to handle operator overloading, and now resolves the choice between multiple overloads using essentially the same technique as is used to resolve method overloading. For example, the following overloads now resolve correctly:
let f1 (x:DateTime) (y:TimeSpan) : DateTime = x - y let g1 (x:DateTime) (y:DateTime) : TimeSpan = x - y // Return type is also sufficient: let f2 (x:DateTime) y : DateTime = x - y let g2 (x:DateTime) y : TimeSpan = x - y // Just argument types are also sufficient: let f3 (x:DateTime) (y:TimeSpan) = x - y let g3 (x:DateTime) (y:DateTime) = x - y
F# Language: Type Qualified Disciminator Names. Ambiguity between constructors of a discriminated union can now be resolved by using the type-qualified path to the discriminator, for example:
type XY = X | Y
type YZ = Y | Z
let y1 = XY.Y
let y2 = YZ.Y
let f xy =
match xy with
| XY.X -> "X"
| XY.Y -> "Y"
let g yz =
match yz with
| YZ.Y -> "X"
| YZ.Z -> "Y"
The same is true of record field names, though this has been the case for some time now.
New F# Samples: DirectX 3D Visualization, WebCrawl. See the 'samples' directory.
F# Library: Warnings now given that 'Stream' will be renamed. This module has been renamed 'LazyList'.
F# Library: BigNum performance improvements. Major implementation improvements and tuning the cross-over between the multipliers.
F# Library: Additional Math.Complex operations.
F# Interactive and Library: Default floating point format for generic printing now 'g10'. i.e. for print_any, output_any, etc. and F# Interactive.
F# Interactive: --codepage switch now accepted by fsi.exe. This controls the codepage used to read the input files. The switch does not yet apply to fsc.exe.
F# Library: Primitive structural comparison and hashing routines moved. These were in Microsoft.FSharp.Primitives.CompilerPrimitives but are now under Microsoft.FSharp.LanguagePrimitives. After a review of the library and as part of the re-implementation of structural comparison and hashing in F# code (see below) the primitive functions used for polymorphic recursive calls in structural comparison and hashing have been moved to a new module Microsoft.FSharp.LanguagePrimitives. These functions may have been called recursively from some user code. The section in the language specification has been updated to reflect this.
F# Compiler: Optimizations and Code Quality. Fewer locals are now produced in many situations where inlining occurs. This improves the quality of the end x86 code, allows the JIT to inline more often and reduces the size of the metadata in generated assemblies.
Extensible expr.[idx] syntax for string, array, dictionary and other access operations.. The syntax expr.[idx] is now shorthand for accessing the Item property on a type. This means that expr.[idx] can be used to perform lookups on essentially any .NET collection type.
Note: As with overloaded operators on integers, the types string and the array types do not in reality support Item properties in the underlying .NET metadata. However F# arranges things to give the appearance that they do.
F# for Visual Studio: Minor improvements
F# Interactive: Suffixes .fsx and .fsscript now accepted.. These are useful for F# Interactive scripts.
F# Interactive: Formatting options may now be specified. There is an fsi object, of type InteractiveSession, available in the top-level.
namespace Microsoft.FSharp.Compiler.Interactive
type InteractiveSession
with
member FloatingPointFormat: string with get,set
member FormatProvider: System.IFormatProvider with get,set
member PrintWidth : int with get,set
member PrintDepth : int with get,set
member PrintLength : int with get,set
member ShowProperties : bool with get,set
member ShowIEnumerable: bool with get,set
member PrintIntercepts: (StructuredFormat.IEnvironment -> obj -> StructuredFormat.Layout option) list with get,set
member AddPrinter: ('a -> string) -> unit
...
end
Here's an example of it's use:
> fsi;; > fsi.FloatingPointFormat <- "%.3";; > fsi.PrintWidth <- 80;; > fsi.AddPrinter(fun (x:System.DateTime) -> sprintf "%Ld" x.Ticks);; > System.DateTime.Now;; > fsi.ShowIEnumerable <- false;; > fsi.ShowProperties <- false;;
F# Compiler: The --base-address flag. Base addresses indicate the default loading address for DLLs within a memory space. Loading a DLL at a default location can reduce the need for 'fixups' that occur when a native DLL gets relocated. Native DLLs occur with F# code if you use NGEN with your F# DLLs, and it is recommended that you use an appropriate base address if rebasing conflicts occur when using NGEN. Various tools and debuggers are available on the web to help determine if rebasing is occuring.
F# Compiler and F# Interactive: Use F# with Microsoft internal or self-built versions of the CLI. Some Microsoft internal or self-built implementations of the CLI have unusual, non-standard names such as v2.0.x86chk. The --cli-version flag can now be used to specify such a version.
F# Interactive: Minor improvements
Minor improvements and Bug Fixes
574 F# Compiler issue with top level mutables (fsi.exe), reported by Andrew Fitzgibbon
389 F# Perf Printf implementation allocated too many closures
594 F# Compiler tyvar lookup failed in ilreflect
595 F# Interactive F# Interactive code generation bug when closures used inside interface implementations
596 F# Interactive F# Interactive code generation bug: Implementing generic interfaces does
not always correctly work around Reflection.Emit limitations
586 F# Compiler local mutables spilled into other locals prior to use
588 F# Compiler expr of constructor argument is not typed-expr
587 F# Compiler poor error message on for i = 0 to 10 do .. done expr
590 F# Compiler match exprA,exprB with .... allocates tuples
592 F# Compiler poor error message when a constructor is too generic
582 F# Compiler fsi prints types of the latest interaction with full path
581 F# Compiler Problem with pickling: Quotation <@ 1.3 @> gives NaN
576 F# Perf Reduce number of generated IL locals
566 F# Compiler interface inheritance/extension not being printed correctly
471 F# Compiler Eliminate unnecessary .cctors
--- Fixes to printing and Array2 module for non-zero-bounded multi-dimensional arrays.
--- Instance members now permitted on types that may use null as a representation. They
are compiled as static members.
--- Fields in super classes not accessible (reported by Ralf Herbrich - thanks Ralf!)
The 'a nativeptr type. The unverifiable type constructor nativeptr is now supported for C/C++/C# pointer types, e.g. sbyte* becomes sbyte nativeptr. In principle this is a breaking change, as previously .NET pointer types were mapped to the F# type nativeint, and are now mapped to nativeptr instead. The new behaviour is, however, consistent with .NET and necessary to permit methods that overload by pointer type (e.g. the unverifiable System.String constructors accepting byte pointers) to be resolved correctly.
Minor improvements and Bug Fixes
F# Interactive for Visual Studio. It rocks! See the section above.
F# website now at http://research.microsoft.com/fsharp
Unified, first-class, composable events. .NET events can now be accessed directly through their real name (e.g. form.Click) rather than through their helper functions (form.add_Click etc.). They can also be used in a first-class way, i.e. form.Click can be passed around as a value. The type of such a value is Idioms.IDelegateEvent, which extends Idioms.IEvent. F# published delgate types should have type Idioms.IHandlerEvent. An MLLib module Microsoft.FSharp.MLLib.IEvent includes some basic polymorphic operations over IEvent types.
Quotation processing over raw quoted expressions. New quotation operators such as <@@ @@> are supported for quoting terms (expressions) in their raw form. More details can be found in the documentation on the Quotations module and the F# informal language specification.
Removed Drop-Down VS Discrimination Menus. Temporarily disabled discrimination drop-down Intellisense in VisualStudio, due to poor completions.
Minor improvements and Bug Fixes
Minor improvements and Bug Fixes
Minor syntax extension related to struct. The syntax module X = begin ... end can now be used in addition to the OCaml-compatible syntax module X = struct ... end. The use of the word struct is potentially ver confusing to .NET-savvy newcomers, who will confuse this with a C# struct. Likewise module X : begin ... end is now the recommended way of writing module X : sig ... end in signatures.
Address-of operator. Occasionally a need arises to pass a byref parameter on to a function. This can now by done using the '&expr' address-of operator. A warning will be given whenever this is used.
Source cleanup. Various cleanup work items completed.
ExportAs deprecated. ExportAs was an old, somewhat half-baked technique to export functions as classes. Now that the object model has been implemented it is no longer needed.
Matrix library redesign and cleanup. Microsoft.FSharp.Math has been reorganised.
Expression quotation library redesign and cleanup. Now called Microsoft.FSharp.Quotations.
HTML library manual pages now included in the release and on the Microsoft Research website.
HTML documentation generation with fsc.exe. Look for the --html* flags in the advanced flags. Documentation is given using "///" comment markers prior to modules, types, values and exceptions.
Fix some problems with the Visual Studio mode. Some files were missing.
Expression Quotation. Microsoft.FSharp.Experimental.Lifted (NOTE later renamed to Now called Microsoft.FSharp.Quotations) contains a range of functionality related to "lifted expressions", i.e. expression quotation, which is a form of meta-programming. This is still under development, and some important functionality is missing or incomplete, but is extensively used in the LINQ sample that is also available in the release.
LINQ Sample. The sample samples\fsharp\FLinq shows how F# can work with the Language-Integrated-Query libraries currently under development at Microsoft.
Source Release. source/... now includes the source code to the Abstract IL, ILX, the F# compiler, F# interactive, the library and the tools, as long promised.
Compiling: To compile it up you us the Makefile and the F# compiler from the distribution itself, and you currently need .NET 2.0, and there is some C/C++ helper code to compile which requires the use of the Microsoft Visual Studio 2005 C/C++ compiler. However you do not really need to compile the C/C++ code, which only enables debugging support etc. (and indeed you can reuse the absilsuppc.dll from the F# distribution itself instead of compiling it up afresh). It should be fairly straightforward to compile with .NET 1.0/1.1 (--cli-version 1.0, change define GENERICS to NOGENERICS etc.) and should also be possible to compile on Mono using 'fscp10ntc.exe', the portable bootstrapped compiler.
General comment: The source has its many quirks and there are many things in we will be cleaing up - if it's ugly then please be merciful and ignore it. Anyway, have fun with it!
Visual Studio mode: (The source for the VS plugin is not yet included, though a crucial file 'fsharp/vs/service.ml' is - this has the key functionality that implements the line-by-line lexing, typechecking cache etc.)
Argument name annotations for documentation purpose in signatures. Arguments can be labelled for documentation purposes, in signature files (.mli/.fsi) only. Note this is not the same os OCaml labelled arguments (which permit labels to be used at the callsite). For example:
val open_in_gen: flags:open_flag list -> permissions:int -> filename:string -> in_channel
First class uses of the 'unit' type now compiled to Microsoft.FSharp.Unit. Previous versions of F# compiled the unit type to System.Object. This has been changed to give better fidelity for runtime types, especially of function values. Note this will break C# 2.0 code that has not been using delegates of type System.Action</tt> as the way of creating function types.
Library Updates.
1.
Adjust the
signature of Idioms.using.
The current signature of
Idioms.using is
val
using: (_ :> System.IDisposable) -> (unit -> 'a) ->
'a
giving somewhat awkward usage
patterns such as
let
ts = new TransactionScope()
in
using ts (fun () ->
<do something with
ts>
)
In this release the signature
becomes
val
using: ('a :> System.IDisposable) -> ('a -> 'b) ->
'b
giving considerably more C#-like
usage patterns such as
using (new
TransactionScope()) (fun
ts ->
<do something with
ts>
)
When translating code from C# we
have found ourselves defining a new version of “using” to match the above, so it
seems preferable, and something we should switch to sooner rather than
later.
2.
Standardize on
the frequent use of “|>”
The operators “|>” and “>>”
are already defined in MLLib.Pervasives as follows:
let
(|>) x f = f x
let
(>>) f g x = g (f x)
Over time it has become clear that
use of these operators, and the “|>” operator in particular, is key to
succinct expression of functional programming when using left-to-right type
inference to resolve some name access base on type information (the technique F#
uses to resolve method overloading and property accesses). Thus we will be using
this operator far more extensively in F# code, tutorials and samples, and will
assume that it’s use one of the first things an F# programmer learns.
For example, note how “a” and “ty”
do not require type annotations in the following code to resolve the use of the
“.” notation.
This is because type information is propagated from the result
type of GetAssemblies through to these binding
sites.
let allMembers =
System.AppDomain.CurrentDomain.GetAssemblies()
|> Array.to_list
|> List.map (fun a -> a.GetTypes()) |> Array.concat
|> Array.to_list
|> List.map (fun ty -> ty.GetMembers()) |> Array.concat;;
(Now write that program in any other
.NET language in 4 lines!)
Assuming familiarity with “|>”has
some ramifications for library design, leading to some of the changes. In
particular:
·
Delete ‘transform’, ‘foreach’ etc. in MLLib.List, MLLib.Array
etc.
These functions were added in an attempt to give left-to-right type
inference, in the style above. However, they were never terribly effective at
doing this.
Furthermore the use of the name “foreach” clobbered the
corresponding name in Idioms. They are best
forgotten.
3.
Include decent
support for IEnumerable-related functions
·
Add the following modules to MLLib (NOTE: not all functions are supproted in this release)
module IEnumerable
// The following functions work over the
System.Collections.Generic.IEnumerable type
val length : #IEnumerable<'a> ->
int
val hd : #IEnumerable<'a> ->
'a
val tl : #IEnumerable<'a> ->
IEnumerable<'a>
val nth : #IEnumerable<'a> -> int
->
'a
val nonempty: #IEnumerable<'a> ->
bool
val empty : unit -> IEnumerable<'a>
val init : (int -> 'a
option) ->
IEnumerable<'a>
val unfold : ('b -> ('a
* 'b) option) -> 'b
->
IEnumerable<'a>
val append : #IEnumerable<'a> ->
#IEnumerable<'a> ->
IEnumerable<'a>
val concat : #IEnumerable< #IEnumerable<'a> > ->
IEnumerable<'a>
val exists : ('a ->
bool)
->
#IEnumerable<'a> ->
bool
val for_all : ('a ->
bool)
->
#IEnumerable<'a> ->
bool
val filter : ('a ->
bool)
->
#IEnumerable<'a> ->
IEnumerable<'a>
val choose : ('a -> 'b
option) ->
#IEnumerable<'a> ->
IEnumerable<'b>
val first : ('a -> 'b
option) ->
#IEnumerable<'a> -> 'b
option
val find : ('a ->
bool)
->
#IEnumerable<'a> ->
'a
val tryfind : ('a ->
bool)
->
#IEnumerable<'a> -> 'a
option
val iter : ('a ->
unit)
->
#IEnumerable<'a> ->
unit
val iteri : (int -> 'a
->
unit) ->
#IEnumerable<'a> ->
unit
val fold : ('b -> 'a
-> 'b)
-> 'b
->
#IEnumerable<'a> ->
'b
val map : ('a -> 'b)
->
#IEnumerable<'a> ->
IEnumerable<'b>
val mapi : (int -> 'a
->
'b)
->
#IEnumerable<'a> ->
IEnumerable<'b>
val of_array: 'a array -> IEnumerable<'a>
val of_list : 'a list -> IEnumerable<'a>
val to_array: #IEnumerable<'a> -> 'a
array
val to_list : #IEnumerable<'a> -> 'a
list
// The following functions work over the
System.Collections.IEnumerable type
// and are available on .NET
1.0/1.1
val untyped_fold : ('b -> 'a -> 'b) -> 'b -> #IEnumerable -> 'b
val untyped_iter : ('a -> unit) -> #IEnumerable -> unit
val untyped_map : ('a -> 'b)
-> #IEnumerable -> IEnumerable
val untyped_filter: ('a -> bool) -> #IEnumerable -> IEnumerable
val untyped_to_list:
#IEnumerable -> 'a list
·
Mark the following as obsolete.
Idioms.foldeach (replaced by
IEnumerable.fold_untyped)
Idioms.transform (replaced by
IEnumerable.map_untyped)
Idioms.foldeachG (replaced by
IEnumerable.fold)
Idioms.transformG (replaced by
IEnumerable.map)
Idioms.foreachE (never needed – all relevant
types implement IEnumerable)
Idioms.foldeachE (never needed – all relevant
types implement IEnumerable)
Idioms.transformE (never needed – all relevant
types implement IEnumerable)
Idioms.foreachEG (never needed – all relevant
types implement IEnumerable)
Idioms.foldeachEG (never needed – all relevant
types implement IEnumerable)
Idioms.transformEG (never needed – all relevant
types implement IEnumerable)
This leaves the
following in Idioms:
val foreach :
#System.Collections.IEnumerable
-> ('a
-> unit)
->
unit
val foreachG:
#System.Collections.Generic.IEnumerable<'a> -> ('a -> unit) -> unit
Rationale: The
purpose of Idioms is to hold F# representations of idioms in .NET, C# and other
languages. It should be comprehensible to beginner F# users. The above
functions were added in a bit of a hurry and simply shouldn’t be in Idioms,
since their purpose is to offer a consistent set of folding and mapping
operations over both the generic and non-generic (untyped) IEnumerable and
IEnumerator types. Much preferable is a module in MLLib that holds these
operations using the consistent MLLib naming scheme (iter, fold, map etc.).
Note: the LINQ
initiative will offer further platform-standard functionality similar to the
above, and when the final version of LINQ is released we will support a
namespace such as Microsoft.FSharp.Bindings.Linq which maps the Linq operators
into F#. Having a half-baked version of this stuff in Idioms doesn’t do anyone
any good. However we can’t wait for the release of Linq to fix this sort of
thing, and in any case Linq uses naming conventions which are different to F#
(select for map, where for filter etc.).
·
Mark as obsolete the very thinly
populated and undocumented
Idioms.IEnumerable, Idioms.IEnumerator. These were again added in a
hurry leading up to the last release and are again best
forgotten.
4.
Include
consistently named support for Enum-related functions
·
Add the following module to MLLib
module Microsoft.FSharp.MLLib.Enum
///Convert an enumeration value to an
integer.
The argument type is inferred from
context.
val to_int: 'a ->
int
when 'a
:> System.Enum
///Convert an integer to an enumeration
value.
The result type is inferred from context.
val of_int: int ->
'a
when 'a
:> System.Enum
///Combine enum values using 'logical
or'. The relevant enumeration type is inferred from
context.
val combine: 'a list -> 'a
when 'a
:> System.Enum
///Test if an enumeration value has a
particular flag set, using 'logical and'.
///The relevant enumeration type is
inferred from context.
val test: 'a -> 'a
->
bool
when 'a
:> System.Enum
·
Mark the following as obsolete.
Idioms.EnumToInt (replaced by
Enum.to_int)
Idioms.IntToEnum
(replaced by
Enum.of_int)
Idioms.CombineEnumFlags (replaced by
Enum.combine)
Idioms.TestEnumFlag (replaced by
Enum.test)
Rationale: The
purpose of Idioms is to hold F# representations of idioms in .NET, C# and other
languages. The above functions are not particularly idioms in any other .NET
language – they just represent things where you have to be a bit more explicit
in F#. They date from the day when Idioms was a sink for “anything which you
needed to do with a runtime check”. Their naming is not particularly consistent
with any other style. Nor are they particularly easy to
find.
It is much preferable to add a
module to MLLib that holds these operations using the consistent MLLib naming
scheme (to_int, of_int etc.).
Note: A future
version of F# may support + etc. on enum types.
Bug Fixes. Various minor fixes.
511 F# Interactive 1 0 errors raised during optimization exit fsi.exe 522 F# Interactive 1 1 fsi bug with operator names 523 F# Interactive 1 0 Automatic binding to a relative path (or the current directory) fails 532 F# VS Plugin 1 1 VS -I and -r relative paths are relative to somewhat random working directoy of VS process rather than the project/file working directory 534 F# VS Plugin 2 1 off-by-one error in VS mode balloon tips 525 F# VS Plugin 1 1 visual studio prior inputs with unicode signature are not being parsed correctly 537 F# Docs 1 1 Abbreviated types appearing in XMLDoc files, also 'unit' 543 F# Language 1 1 printing "List" and "Option" for types generated by uses of constructors looks gross 433 F# Compiler 2 2 Represent "unit" as a real type rather than abbreviating to "obj" 453 F# Compiler 2 2 print_any - no printing of repeated terms - no print depth/width controls 505 F# Language 1 0 implement a way to name arguments - crucial documentation 529 F# Compiler 1 0 differing orders of fields for records in signatures and implementations cause problems for record constructors and "with" 549 F# VS Plugin 1 0 VS redirecting stdout to Output window interferes with stdin 552 F# VS Plugin 1 1 VS mode show 2 resolutions for .NET types 553 F# VS Plugin 1 1 VS Mode method tips bounce back to first entry every time the "down" key is pressed (reported by Artem - thanks Artem!) 554 F# VS Plugin 1 1 Balloon Tips not showing XMLDoc help text for methods and types 555 F# VS Plugin 1 1 Intellisense not showing signatures and overloads for .NET constructors. 556 F# Documents 1 1 Incorrect XMLDoc signatures being generated for generic methods and some other generic gadgets 539 F# Interactive 1 0 compile F# Interactive on .NET 1.0 560 F# VS Plugin 1 1 TAB in VS mode doesn't activate completion 561 F# Language 1 1 Module abbreviations not permitted in signatures 563 Abstract IL 2 2 AbstractIL library contains duplicate hashtable modules etc. 562 F# Library 1 1 printf %s formats do not permit padding specifications 564 Abstract IL 1 1 Abstract IL library module names need to be much more sensibly organized
Matrix Library. Microsoft.FSharp.Math.Matrix<_> has been added as a generic matrix type, with extensive MATLAB-like operations at Microsoft.FSharp.Math.MatrixOps<_> and Microsoft.FSharp.Math.MatrixOps.Generic;. The former are for floating point matrices Matrix<float> = matrix, and the latter are generic over all matrix types. The interface to this library is likely to be stable. Vector and RowVector types are also defined - their status sill undergo revision after a few releases.
Very Preliminary Linear Algebra. Microsoft.FSharp.Math.LinearAlgebra<_> contains a handful of basic linear algebra functions.
Compositional, Customizable Structured Printing. A preliminary but powerful approach to user-definable structured display of terms has been implemented in this release. The solution is different to the OCaml-style "Format" library and is instead based on the generation of intermediary "layout" objects. So far, a layout describes how words will fit next to each other and where the breaks (and indentations) will/can be.
A layout engine typically constructs most layouts using a generic algorithm based on the term structure of F# data accessed via Microsoft.FSharp.Experimental.Reflection. Types that wish to customize their structured format specification can implement the StructuredFormat.IFormattable interface, which must provide a function that generates a StructuredFormat.Layout value. An environment is passed to the object that provides a function to use to generate layout for recursive calls. Leaf objects such as numbers and strings can be left unformatted, which gives a formatting engine control over how these appear (e.g. culture specific formatting of numbers). A default formatting engine is provided in Microsoft.FSharp.MLLib.Pervasives.LayoutOps for formatting layouts to strings, channels and text buffers. This engine can be customized to some extent (e.g. by print width, depth, culture and floating-point number formatting) and is used by thw following functions:
as well as the F# Interactive pretty printer. The end result is that objects are converted to textual formats consistently and in a customizable way. Here is and example of the output generated, here for a matrix holding further matrices:
> open Math;; > open MatrixOps.Generic;; > let m = matrix [[1.0;2.0;3.0]];; val m : Matrix> m;; val it = matrix [[1.000000; 2.000000; 3.000000]] > let m = matrix [[m];[m];[m]];; val m : Matrix<Matrix<float> > > m;; val it = matrix [[matrix [[1.000000; 2.000000; 3.000000]]]; [matrix [[1.000000; 2.000000; 3.000000]]]; [matrix [[1.000000; 2.000000; 3.000000]]]]
Here is an example of customization of the structured layout to format complex numbers, without actually specifying the formats of the constituent components:
open StructuredFormat.LayoutOps
type Complex = { real: float; imaginary: float }
with
member x.r = x.real
member x.i = x.imaginary
interface StructuredFormat.IFormattable with
member x.GetLayout(env) =
objL (box x.r) ++ rightL "r" ++ sepL "+" ++ (objL (box x.i) $$ rightL "i")
end
Named arguments for attributes. Attribute specifications can now take named arguments, e.g.
[<DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)>]
let MoveFile ((src : string), (dst: string)) : bool = failwith "extern"
Abstract properties. Interfaces and classes may now define abstract properties and specify overrides and defaults for these. This is functionality that was not completed in the first release of the object model. e.g. in an interface definition:
Abstract properties and properties in interfaces. Interfaces and classes may now define abstract properties and specify overrides and defaults for these. This is functionality that was not completed in the first release of the object model. e.g. in an interface definition:
type IEnvironment =
interface
/// A property indicating the maximum number of columns
abstract MaxColumns : int
/// A property indicating the maximum number of rows
abstract MaxRows : int
end
And in an implementation by a class:
type MyEnvironment =
class C
interface IEnvironment with
method x.MaxColumns = 3
method x.MaxRows = 4
end
end
And in an implementation by an object expression:
{ new IEnvironment
with MaxColumns = 3
and MaxRows = 4 }
Rename 'MLLib.Vector' to 'MLLib.ReadonlyArray'. 'Vector' and 'vector' are now used for Microsoft.FSharp.Math.Vector, mutable column vectors whose element type typically support certain element operations.
Bug Fixes.
470 F# Compiler Constructors and method can't be overloaded betweeen 0/1 arguments 473 F# Compiler Operator overloading bug 474 F# Visual Studio Pattern hints for lists showing operator names, also no testing for these 475 F# Visual Studio Pressing BAR causes poor menus to pop up in Visual Studio too often 478 F# Compiler #use only processes one interaction per file 479 F# Compiler fsi - ctrl-C during command line arg processing unhandled. 481 F# Compiler fsi - syntax error recovery... 482 F# Language any_to_string doesn't print arrays 483 F# Compiler internal type variable error (reported by Karthik) 484 F# Compiler overloaded indexer properties not correctly resolved (from F# Mailing list) 485 F# Compiler uppercase non-constructor names used in patterns do not give a warning 486 F# Doc Fix documentation bug (reported by Greg Chapman - thanks Greg!) 491 F# Library Equality not implemented on matrices 492 F# Compiler imperative type vars and type var bindings not being shown in error messages (reported by Karthik) 391 F# Compiler F# not automatically usable on x64 boxes 372 F# Compiler F# gives syntax error for OCaml top level expressions 349 F# Compiler Inferred constraints of the form "x :> obj" should be ignored (e.g not required in signatures) 250 F# Visual Studio Load on-the-fly XML documentation into Visual Studio, or connect to VS interfaces that will do this for us 309 F# Compiler import C# constrained polymorphism as F# constrained polymorphism 315 F# Visual Studio output does not go to console window by default 490 F# Library Consistent approach to structured print layout needed
Bug Fixes. Various minor fixes to F# Interactive, e.g. large bytearrays. F# Interactive now works on .NET 2.0 Relase Candidate versions. Additional warnings on some minor incomplete features.
Visual Studio. Now supports "Go To Definition" and "Go To Declaration"
MLLib.Printf. Now supports '%M' for decimal values and '%O' for any 'any' object value. These are currently printed using Object.ToString() but may in the future be printed using any_to_string.
Bug Fixes. Visual Studio fixes for '|' triggers.
Core Language. Integer constants for the types 'bignum' and 'bigint' are now supported, e.g.
do Printf.printf "%O\n" 3N do Printf.printf "%O\n" 3I do Printf.printf "%O\n" (3N / 4N) do Printf.printf "%O\n" (3N / 400000000N) do Printf.printf "%O\n" (3N / 3N) do Printf.printf "%O\n" (-3N) do Printf.printf "%O\n" -3N do Printf.printf "%O\n" (-3N / -3N) do Printf.printf "%O\n" -30000000000000000000000000000000000000000000000000000000000000N
The following operartors are now supported and can be used for multi-dimensional array lookup/assignment.
arr.(i,j) -- Look up a rectangular (non-jagged) 2D array of type 'ty[,]' arr.(i,j) <- x -- Assign into a rectangular (non-jagged) 2D array of type 'ty[,]' arr.(i,j,k) -- Look up a rectangular (non-jagged) 2D array of type 'ty[,]' arr.(i,j,k) <- x -- Assign into a rectangular (non-jagged) 2D array of type 'ty[,]'
The MLLib modules Array2 and Array3 provide basic operations for 2 and 3 dimensional arrays. .NET operations on the System.Array type can also be used directly.
Library. The Compatibility.CompatArray and Compatibility.CompatMatrix module now give better results (no polymorphism restrictions apply) if inadvertantly used from .NET 2.0. Use of these modules is not recommended from .NET 2.0 but sometimes occurs when code is copied from cross-compiling samples.
Attributes. Specification clarifications for attributes. Attributes now give warnings when used inappropriately. Attributes can now be referenced with or without the Attribute suffix, e.g. [<Obsolete("this function is obsolete")>] or [<ObsoleteAttribute("this function is obsolete")>].
Compilation Speed Optimizations. Improved compilation speeds, especially when using the --standalone flag.
VS Mode. Better response as now compacts less often. Now accepts all fsc.exe flags within the argument window: those irrelevant to type-checking are still used when the command line compiler is invoked.
Minor renamings. The .NET compiled names of some exceptions have changed to follow .NET library design guidelines
AssertFailure --> AssertionFailureException.
MatchFailure --> MatchFailureException.
Undefined --> UndefinedException.
The names from F# code are now either the above names or, when using MLLib, the equivalents Assert_failure, Match_failure and Undefined.
Turning off default augmentations for discriminated unions. By default F# dsicriminated unions are augmented with properties and methods such as member IsRed : bool,member Red : int -> Color and Red1 : Color -> int for a constructor Red of int in a type Color. Now that augmenetations are supported directly in the F# language it is often more convenient to manually design these augmentations. The default augmentations can now be suppressed by using the [<DefaultAugmentation(false)>] attribute. For example, the Option<'a> type in the F# library is defined as:
[] /// The type of optional values. When used from other .NET languages the /// empty option is the 'null' value. type Option<'a> = None | Some of 'a /// Augmentation type Option<'a> with member x.Item = match x with Some x -> x | None -> op_Raise (new System.IndexOutOfRangeException()) static member IsNone(x : Option<'a>) = match x with None -> true | _ -> false static member IsSome(x : Option<'a>) = match x with Some _ -> true | _ -> false static member None : Option<'a> = None static member Some(x) : Option<'a> = Some(x) end
Initial support for Microsoft.FSharp.Experimental.Collections With the completion of the F# support for members and augmentations we are moving the functionality of the MLLib collections to be co-designed libraries for functional and obejct oriented programming. The means that a functional programming API to the collection types will be offfered in MLLib, and a mixed object-oriented/functional API within FSLib. This will greatly improve the usability of the collection types from C# and other .NET languages, without losing the essence of OCaml-compatible ML programming. The first class we have applied this treatment to is Microsoft.FSharp.Experimental.Collections.HashTable and the related HashSet, CHashTable and CHsahSet.
Generic Recursion support temporarily withdrawn. Some bugs were found in the support for generic recursion added in 1.1.0.4 (unverifiable binaries could be produced in some situations). In particular, full signatures need to be given to make a function eligible for generic recursion, and this is not yet enforced. Functions and values may still be given explicit type parameters, but recursive uses of explicitly paramaterized values must at invariant instantiations, as was always the case for versions prior to 1.1.0.4.
Bug fixes. Several bug fixes related to attributes, generalization, enumerators and exception abbreviations, Arg.usage. Thanks to Martin Churchill, Dominic Cooney, SooHyoung Oh, Ondrej Rysavy, Robert Pickering, Greg Lee and Adam Granicz among others for reporting these bugs. Some other bugs recently recorded as fixed in out database are as follows:
443 F# Library MLLib.Stream incorrect behaviours 442 F# Compiler print_any raises exceptions on singleton constructor values 452 F# Compiler Visual Studio and fsc.exe both have problems with unicode, reported by DOminic Cooney 440 F# Tools lex/yacc - partial parses of stdin require extra token before succeeding and discard buffered input 441 F# Compiler uncaught exceptions are not reported in user friendly way (no details of what they carry...) 444 F# Compiler records compile to classes with duplicate members names - a problem for debugging 445 F# Compiler serialisation of nil list fails 426 F# Compiler "end of file in string or comment" error doesn't report start-of-string-or-comment 459 F# Compiler Undefined type variable problem 458 F# Compiler typechecker doesn't decode all attributes correctly (decode_simple_cattr_data) 371 F# Compiler Support adding managed resources to .NET DLLs and EXEs 422 F# Compiler VideoPlayer sample gives error 406 F# Library Bignums package 470 F# Compiler Constructors and method can't be overloaded betweeen 0/1 arguments 467 # Library any_to_string on char fails on 1.1
Compiler for use with Mono. The binary fscp10ntc is a version of the F# compiler that is reported to work to some extent in conjunction with the Mono CLI implementation. Tailcalls have reported to cause problems on Mono, hence this is a "no tailcall" (ntc) version of the compiler, which leads to changes in performance. The matching "ntc" versions of the libraries are also included. This is also a CLI 1.0 binary, again changing the performance.
This version of the compiler is reported to be sluggish, so a reasonably fast machine may be required. It may also be worth investigating the use of pre-compilation (mono --aot) in conjunction with this binary to improve startup times (pre-compilation is pretty much essential for any compiler).
The F# Object and Encapsulation Extensions. F# types can now be augmented with properties, members and operators. Furthermore, .NET-style class and interface types may also be defined in F# itself. Fairly complete documentation is provided in the language specification.
Big integers and arbitrary sized rational arithmetic. The types under Microsoft.FSharp.Math.* are the implementations of the F# arbitrary precision integer and rational arithmetic types. A partially-OCaml-compatible version of this functionality is included in MLLib, i.e. use the functionality available via 'open Num'. The types support overloaded operators. The naturals are used to build arbitrary sized integers and rationals. The implementation aims to for a lower garbage cost and provides multiplication that scales effectively up to huge numbers.
The F# Language Specification (Preliminary). A work-in-progress language specification is now included in the manual.
Specification clarifications.
Attributes attached to values in F# signatures (.fsi and .mli files) are incorporated into any F#-specific interface metadata associated with the generated assembly and the .NET IL metadata for the generated assembly. Attributes attached to values in F# implementations (.fs and .ml files) are only saved into the .NET IL metadata. Thus attributes that are relevant to F# type checking (e.g. Obsolete attributes, which generate warnings at compile time when constructs are used) must be placed in signatures. Attributes from signatures need not be duplicated in implementations.
Managed and Unmanaged Resource Linking. The command-line flags --resource, --link-resource and --win32res are now supported by the F# compiler for embedding native and managed resources (text files, icons, bitmaps, audio files etc.) into executables. They have the same meanings as the corresponding C# flags.
New in Microsoft.FSharp.Idioms. The following are new in this module of useful .NET idioms:
val foreachE: (_ :> System.Collections.IEnumerator) -> ('a -> unit) -> unit
val foldeachE: (_ :> System.Collections.IEnumerator) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transformE: (_ :> System.Collections.IEnumerator) -> ('a -> 'b) -> System.Collections.IEnumerator
val foreach: (_ :> System.Collections.IEnumerable) -> ('a -> unit) -> unit
val foldeach: (_ :> System.Collections.IEnumerable) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transform: (_ :> System.Collections.IEnumerable) -> ('a -> 'b) -> System.Collections.IEnumerable
#if GENERICS
val foreachG: (_ :> System.Collections.Generic.IEnumerable<'a>) -> ('a -> unit) -> unit
val foldeachG: (_ :> System.Collections.Generic.IEnumerable<'a>) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transformG: (_ :> System.Collections.Generic.IEnumerable<'a>) -> ('a -> 'b) -> System.Collections.Generic.IEnumerable<'b>
val foreachEG: (_ :> System.Collections.Generic.IEnumerator<'a>) -> ('a -> unit) -> unit
val foldeachEG: (_ :> System.Collections.Generic.IEnumerator<'a>) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transformEG: (_ :> System.Collections.Generic.IEnumerator<'a>) -> ('a -> 'b) -> System.Collections.Generic.IEnumerator<'b>
#endif
type 'a sizeof = { result: int }
val inline sizeof: unit -> $a sizeof
Bugs fixed.
438 F# Compiler Mixed null and string matches bypassed pattern simplifier 441 F# Compiler Uncaught exceptions wrapping a string report their message. 442 F# Compiler Experimental.Reflection failed on singleton constructor values. F# VS Mode Type inference variables appearing in the displayed hover-text for F# values F# Library open_in now opens in ASCII encoding. Use stream_reader_to_in_channel to open in other encodings
Local names. Improved naming of locals to help during debugging.
Additional Overloading Strings now support overloaded '+'.
Customizable Debugger Views for F# Types. F# types can now be augmented in a a number of ways to customize how the values appear in a debugger. Firstly, the ToString member may be adjusted for each F# concrete type (i.e. record, discriminated union and object types). Secondly, the .NET 2.0 standard DebuggerDisplay attribute can be used in conjunction with member augmentations to customize the simple textual display associated with a type. For example:
type [] MyIntList = | MyNil | MyCons of int * MyIntList with member x.Length = let rec length x acc = match x with MyNil -> acc | MyCons(a,b) -> length b (acc+1) in length x 0 end
Finally, for sophisticated structured collections the .NET 2.0 standard DebuggerTypeProxy can be used in conjunction with member augmentations to specify a class that represents the visual display of an object. For example:
type [] MyIntList = MyNil | MyCons of int * MyIntList and MyIntListDebugView = class val v: MyIntList new(x) = { v = x } [ ] member x.Items = let rec length x acc = match x with MyNil -> acc | MyCons(a,b) -> length b (acc+1) in let len = length x.v 0 in let items = Array.zero_create len in let rec go n l = match l with MyNil -> () | MyCons(a,b) -> items.(n) <- a; go (n+1) b in go 0 x.v; items end
Custom Attribute Extensions Custom attributes now accept 'type' arguments. Double parantheses (to disambiguate the start and finish of the extra argument) and the keyword type must currently be used:
[]
Library additions: Option. The Option module is now a standard part of MLLib. It has a set of functions similar to List.
Library additions: Printf.failwithf and more. The Printf module now supports the failwithf function, which uses structured formatting to print to a string and then raise a Failure exception for this string. The new printer bsprintf is also supported: this prints to a string but intermediary functions print to string buffers. More general compositional forms of Printf operators are also included that let you specify a 'final action' for the printig such as flushing or raising an exception. Finally the OCaml-style 'format4' printer specifications are now also supported - these enable overall return types to be distinct from the types generated by intermediary printers.
Inclusion of a very preliminary release of a top-level command-line interactive environment for F#. The top-level environment will be fsi.exe. This is work in progress, and is included only for testing purposes.
Inclusion of a very preliminary release of FSharp.Compiler.dll, a hostable F# compiler. This is work in progress, and is included only for testing purposes.
Defining Events in F# Events should be defined using new definitions in Microsoft.FSharp.Idioms. For example:
open System.Windows.Forms
open Idioms
type MyCanvas =
class
inherit Form
val redrawListeners: EventListeners
member x.Redraw = x.redrawListeners.Event
override x.OnPaint(args) = x.redrawListeners.Fire(args)
new() = { inherit Form(); redrawListeners= new EventListeners() }
end
let form = new MyCanvas()
do form.Redraw.Add(fun args -> Printf.printf "OnRedraw\n")
do form.Activate()
do Application.Run(form)
Note we are using a property of type Idioms.IEvent<PaintEventArgs> to represent the event. The object returned by this property has Add, AddHandler and RemoveHandler methods (see below). In a future release of the compiler properties of type Idioms.IEvent<PaintEventArgs> will automatically result in appropriate .NET metadata for the event being inserted in the generated assembly. In the current release events defined using this mechanism may still be used from C# and other .NET by using AddHandler and other methods on themediating object.
type Idioms.SimpleEventArgs<'a> =
class
inherit System.EventArgs
member Data: 'a
new: 'a -> SimpleEventArgs<'a>
end
type Idioms.SimpleEventHandler<'a> = System.EventHandler>
type Idioms.IEvent<'a> =
interface
inherit IDelegateEvent >
// The inheritance gives:
// abstract AddHandler: SimpleEventHandler<'a> -> unit
// abstract RemoveHandler: SimpleEventHandler<'a> -> unit
// We add this one, which from F# code this is very simple to use:
abstract Add: ('a -> unit) -> unit
end
type Idioms.event<'a> = IEvent<'a>
type Idioms.EventListeners<'a>
with
member Fire: 'a -> unit
member Event: IEvent<'a>
new: unit -> EventListeners<'a>
end
Renamed fslib10ng.dll to fslib10.dll, since there was a bug with using F# with Visual Studio 2003, and also the "ng" (non-generic) suffix was redundant and clumsy.
Stabilized string hash codes across .NET v1.1 and v2.0. That is, F#'s structural hash function no longer hashes strings by calling String.GetHashCode, since the hash codes returned were different between version 1.1 and 2.0.
Fixed a bug with the debug marks being attached for the entrypoint of executables.
A special function Pervasives.rethrow is now supported. This rethrows the exception for the current "try/with" block. However, it may only be used in catch blocks. Using it in a first class way or outside a catch block will result in a binary that cannot be verified. The correct use of this function is not checked in this version of F# but will be checked in a later version.
Fixed a bug that prevented the generic EventHandler type from being used (or indeed any generic type that was in the same namespace as a non-generic type with an identical name).
F# .EXEs that do not use function values, list types, option values or any other fslib or mllib no longer pick up a dependency on fslib.dll. DLLs incorporating interface data or optimization data still acquire a dependency.
Welcome James Margetson to the F# team!
F# now works with Whidbey Beta 2 releases of .NET (EDITOR: the latest releases no longer support Beta 2). F# can continue to be used with .NET 1.0 and 1.1, but can no longer be used with Whidbey Beta 1. If you are still using Whidbey Beta 1 and don't want to upgrade to Whidbey Beta 2 then add --cli-version 1.1 to your compilation switches to compile for .NET 1.1 (likewise 1.0) instead.
Change to Library Naming. The F# libraries fslib and mllib now come in two flavours: one for use with .NET 1.x (no generics) and one for use with .NET 2.0 Beta 2 and beyond (this is to ensure that the library can take advanatage of new features of the platform). The .NET 1.x version of the library has the suffix "10" attached. Thus you will see both fslib.dll and fslib10.dll in this release. F# will automatically reference the correct DLL. When compiling C# code with .NET 1.x you will need to reference fslib10.dll and mllib10.dll.
Rename some internal functions. Some internal functions such as GenericCompare have been renamed appropriately, e.g. to StructuralCompare.
Performance improvements.do Console.WriteLine("res = {0}\n",Decimal.op_Addition(new Decimal(10), new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(10)) + (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new DateTime(1970,10,1)) + (new TimeSpan(1000000000L)))
do Console.WriteLine("res = {0}\n",(new DateTime(1970,10,1)) - (new TimeSpan(1000000000L)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) / (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) - (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) * (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) mod (new Decimal(7)))
Bugs fixed
351 F# Compiler Use of invalid format specifier such as %l in a Printf string gives a poor error message 381 F# Library input_char cause exception to be thrown 318 F# Compiler F# lets two constructors have the same name and gives error when emitting binary 321 F# Compiler compiler error reported by Greg Lee 332 F# Compiler F# reports error when a "for" variable is used within an inner closure, complaining it is mutable 333 F# Compiler Cannot hide exception declarations 252 F# Perf fsyacc parser is allocating a lot of list and option nodes 399 F# Perf Move generation of comparison and hash methods earlier (to typechecker) so that the code can be fully optimized (and inlined!!) 281 Abstract IL implement output of debug symbols for Abstract IL and bootstrapped compiler 175 F# Tools Implement error recovery in fsyacc generated parsers
Restricted operator overloading to built-in types only for the time being. This is simply an implementation incompleteness.
Added float32 and other float32-related operations to Pervasives.
Constrained Type Parameters
F# now allows type parameters to be constrained to specify the minimum functionality the instantiating type must support.
You may be familiar with constrained type parameters from elsewhere. For example, C# and .NET generics support 'subtype' constraints on generic type variables. OCaml supports structural 'object-type' constraints and an additional kind of variable known as a 'row' variable. Standard ML supports a two minor forms of constrained polymorphism in the form of record types (which must be locally resolved) and equality types.
Constrained polymorphism affects both type checking and type inference. In this release, F# supports coercion constraints (on any type variables) and overloaded operator constraints (on pseudo type variables).
Coercion constraints are of the form typar :> type, and also arise from the constructs expr :> type and pattern :> type. For example:
val throw: 'e -> unit when 'e :> System.ExceptionThe same declaration can be written using the following more convenient syntactic forms:
val throw: (_ :> System.Exception) -> unit
class C { static void SomeMethod(IComparable x) }
Then calling this with the F# code:
C.SomeMethod(x)
will induce a constraint that x is coercable to IComparable, i.e. ty :> IComparable when ty is the static type of x.
C# 2.0 and other .NET 2.0 code may use coercion constraints to specifying that a type parameter should support functionality such as IComparable. However, this pattern is not so common in F# code, where dictionaries of functionality are typically passed around by using tuples or records of function values.
Overloaded operator constraints arise when using overloaded operators +, - etc. For example, the operator + may be used on any two .NET values supporting the overloaded operator op_Addition (written static operator +(...) in C#). (They may also be used on built-in integer and floating point types, which are considered by F# to implicitly define operators such as op_Addition). Overloaded operators are generally only defined within the F# library. Overloaded operator constraints can only be placed on pseudo type variables.
(Aside: pseudo type variables are type variables that occur only within the type checking of a single file. These type variables arise primarily from the use of pseudo-functions such as overloaded operators.)
Examples
In a signature a value declaration may be annoated with constraints. The most primitive way to do this is to use a when annotation on a value declaration. We saw an example of this above. The same declaration can be written using the following more convenient syntactic forms:
val throw: 'e -> unit when 'e :> System.Exception
val throw: (_ :> System.Exception) -> unit
val throw: ('e :> System.Exception) -> unit
As with types, constraints will be inferred from the definition of a method. For example
open System.IO
let to_binary_writer s = new BinaryWriter(s)
will infer the type
val to_binary_writer: (_ :> Stream) -> BinaryWriter
That is, because the constructor for System.IO.BinaryWriter accepts any subtype of System.IO.Stream, F# has also inferred that the derived function should accept any subtype of System.IO.Stream as its argument. You could also write this explicitly using:
let to_binary_writer (s :> Stream) = new BinaryWriter(s)
Here the pattern (s :> Stream) means 's should match a value whose type can be coerced to Stream'.
Type Inference and Checking
Type inference and checking of constraints is fairly straight-forward: each use of a value or type whose specification involves constrained type parameters will induce a constraint on the actual type parameters associated with the use of that item. (Aside: each time an ML value is used a fresh set of actual type parameters is generated - for example each time you write List.length a fresh inference type parameter is implicitly used as the actual type parameter for the value.)
Constraints are solved, or partially solved, as they are generated. For example:
The following limitations currently apply:
Extensions to the Grammar for Constrained Type Parameters
The extensions to the grammar are as follows:
<val-type> :=
| <type> -- unconstrained type
| <type> when <constraints> -- constrained type
The following syntactic forms are for convenience. They imply constraints at the binding site related to the type variable (see below).
<type> :=
| <typar> :> <type> -- the same as <typar>, with an implied constraint
| <typ> when <constraints> -- constrained type
The constraints can be of the following forms:
constraint :=
| <typar> :> <typ> -- the type parameter converts to the type
| $<typar>.<method-name> : <method-type> -- overload constraint
Aside: Binding sites for type variables are inferred in the usual way for ML languages of the OCaml family. This binding site is either a value declaration, a type declaration. Inference variables will be bound at the value declaration where they are generalized, or if not generalized will have the scope of the entire file.
Extensions to the Semantics of Coercion Operators
The operator expr :> typ now means 'expr can be coerced to typ'. This includes the use of representation-changing conversions such as boxing.
Uses of Constrained Polymorphism in the F# Library
Pervasive Operators:
Overloading is supported for the following operators. The operators all default to operating over the int type should there be no other type information in the file to further constrain the use of the operator.
val (+): $a -> $b -> $a when $a.op_Addition : ($a, $b) -> $a
val (-): $a -> $b -> $a when $a.op_Subtraction : ($a, $b) -> $a
val ( * ): $a -> $b -> $a when $a.op_Multiply : ($a, $b) -> $a
val (/): $a -> $b -> $a when $a.op_Division : ($a, $b) -> $a
val (mod): $a -> $b -> $a when $a.op_Modulus : ($a, $b) -> $a
val (~-): $a -> $a when $a.op_UnaryNegation : ($a) -> $a
val (~+): $a -> $a when $a.op_UnaryPlus : ($a) -> $a
val (land): $a -> $a -> $a when $a.op_BitwiseAnd : ($a,$a) -> $a
val (lor): $a -> $a -> $a when $a.op_BitwiseOr : ($a,$a) -> $a
val (lxor): $a -> $a -> $a when $a.op_ExclusiveOr : ($a,$a) -> $a
val lnot: $a -> $a when $a.op_LogicalNot : ($a) -> $a
val (lsl): $a -> int -> $a when $a.op_LeftShift : ($a,int) -> $a
val (lsr): $a -> int -> $a when $a.op_RightShift : ($a,int) -> $a
val (asr): $a -> int -> $a when $a.op_RightShift : ($a,int) -> $a
List, Stream, Vector, Array, Set:
The following functions are for transforming F# collections to and from .NET collections and now accept coerced arguments at F# call-sites:
List.of_IEnumerable: (_ :> IEnumerable<'a>) -> 'a list
List.of_ICollection: (_ :> ICollection<'a>) -> 'a list
Array.of_IEnumerable: (_ :> IEnumerable<'a>) -> 'a[]
Array.of_ICollection: (_ :> ICollection<'a>) -> 'a[]
Vector.of_IEnumerable: (_ :> IEnumerable<'a>) -> Vector<'a>
Vector.of_ICollection: (_ :> ICollection<'a>) -> Vector<'a>
Stream.of_IEnumerable: (_ :> IEnumerable<'a>) -> Stream<'a>
Stream.of_ICollection: (_ :> ICollection<'a>) -> Stream<'a>
Idioms:
The following functions now accept coerced arguments at F# call-sites:
Idioms.foreach: (_ :> IEnumerable) -> ('a -> unit) -> unit
Idioms.foldeach: (_ :> IEnumerable) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
Idioms.foreachG: (_ :> IEnumerable<'a>) -> ('a -> unit) -> unit
Idioms.foldeachG: (_ :> IEnumerable<'a>) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
Idioms.using: (_ :> System.IDisposable) -> (unit -> 'a) -> 'a
Idioms.lock: (_ :> System.Object) -> (unit -> 'a) -> 'a
The following functions are now checked more strictly.
Idioms.EnumToInt: 'a -> int when 'a :> System.Enum
Idioms.IntToEnum: int -> 'a when 'a :> System.Enum
Idioms.CombineEnumFlags: 'a list -> 'a when 'a :> System.Enum
Idioms.TestEnumFlag: 'a -> 'a -> bool when 'a :> System.Enum
Fixed the following bugs:
282 fsyacc doesn't like // comments
267 interface data being attached to assemblies includes is bigger than it should be
286 NGEN of bootstrap compiler fails due to multiple mscorlib references.
291 bug in the implementation of stable_sort
292 Compiler bug - cannot find fslib library automatically
295 --standalone doesn't fold in debug symbols of the assemblies that have been read
293 alternative-install.bat gives a spurious error while loking for NGEN
296 multiple mscorlib references are appearing in --standalone assemblies (fscbng.exe)
302 VS plugin is not reloading referenced DLLs as they are recompiled (this forced users to restart VS to see changes)
303 Sys.time is returning Ticks not TotalSeconds
305 Implementing IEnumerator on .NET v2.0 beta 2 is difficult due to inclusion of parent interfaces with identical method names
Fixed a bug related to inner polymorphic closures reported by Nikolaj Bjoerner (thanks Nikolaj!)
Fixed a bug related to over-applied polymorphic functions reported by Dominic Cooney (thanks Dominic!)
Implemented intellisense for further long-name lookups in VS integration, e.g. val.field.field or val.property.field
Fixed the following bugs:
272 Fixed: AV in VS Plugin when endlessly loading & unloading large F# projects 274 Fixed: A failure "stelem" occurred when compiling a test for .NET 2003 247 Fixed: test and document hashq operator 232 Fixed: verify non-generic assemblies using v1.0 and v1.1 peverify's 223 Fixed: Change test procedure to generate config files in order to test on various versions of the clr 275 Give better error messages when passing a value to a Params C# method 276 Give better error message when a CompatArray is needed
Added another DirectX Tutorial (Tutorial 1)
Fixed installer problems on VS 2003 - Babel package was still being registered with VS 2005
Reduce size of optimization information attached to F# DLLs.
Minor fixes to the Visual Studio installer.
Minor performance improvements for the command line compiler.
Fixed this bug:
268 F# Compiler: not all type definitions were being checked for cyclic abbreviations
Fixed one bug with intellisense where extra text on the line after the cursor was interfering with intellisense. Some glitches remain in this area.
Reduced the number of match-bracket calls to improve reponsivity of VS. Some bugs remain in this area.
Minor fixes to the Visual Studio installer.
Performance improvements for the command line compiler.
Fixed minor bugs with the recent additions to MLLib.
New reserved keywords after review of keyword policy: atomic, checked, class, decimal, event, pure. In addition the existing reserved word interface is now actually used as a keyword, and will hence give errors if used in your program. The others will give warnings.
Intellisense is now supported in the Visual Studio integration. Essentially all features are complete, though incorrect or slightly misleading information is occasionally be shown, and the correct context is not always available to allow information to be shown. You can turn off Intellisense globally by setting the environment variable FSharp_NoIntellisense=1.
Extended Object Expressions are now supported. This means objects created via object expressions can support multiple interfaces, which also makes F# a CLS Extender language according to the official definition of such things. The syntax is:
{ new with
interface with
...
interface with }
e.g.
{ new Object()
with Finalize() = cleanupFunction(false);
interface IDisposable
with Dispose() = cleanupFunction(true); }
Nested modules within a top-level module are now supported, e.g.
type ident = Id of string
module Ident = struct
let OfString(s) = Id(s)
let ToString(Id(s)) = s
end
and in the interface file
type ident
module Ident : sig
val OfString: string -> ident
val ToString: ident -> string
end
The atomicity of dynamic initialization is on the granularity of top-level modules, i.e all the bindings in a top-level module are executed for side-effects if any values in the file are required.
Patterns can now refer to .NET literals.
More .NET related functionality in the ML compatibility library. Modules Float, Float32, UInt32, UInt64, Stream. A much more systematic treatment of conversions between various integer and floating point types. Conversion functions to allow MLLib collections to be used as .NET collections (ICollection etc.). More efficient implementations of some functions.
Visual Studio for .NET will now work with Visual Studio 2003. See the installation instructions elsewhere in this file.
Controlling F# for Visual Studio if it starts to misbehave. The following global environment variables can be used to selectively control some of the features of F# for Visual Studio. They can also be set within the command shell where you execute devenv.exe if you run it explicitly.
set FSharp_Logging=1
set FSharp_LoggingVerbose=1
set FSharp_NoParsing=1
set FSharp_NoChecking=1
set FSharp_NoPriorInputParsing=1
set FSharp_NoConfigBuilding=1
set FSharp_NoPriorInputTypeChecking=1
set FSharp_NoTypeChecking=1
set FSharp_NoLexing=1
set FSharp_NoIntellisense=1
Documentation:
-- Revised grammar documentation in manual -- Revised interop decumentation in manual
Various bug fixes:
The following bugs were recorded as fixed in the F# bug database:
_ F# Compiler Implement setting of fields and properties on .NET value types for the simpe cases of mutable locals and byref arguments 196 F# Compiler Poor error message for signature mismatch when an abbreviation is hidden 211 F# Compiler too many long paths printed when using -i 204 F# Compiler fsyacc: newline missing 200 F# Compiler Newline or similar needed between errors 197 F# Compiler Can access hidden constructors and fields using long path names 137 F# Compiler Implement accessing generic methods 210 F# Compiler --standalone bug for winforms reported on f# list 259 F# Compiler Fixed a bug with generalizing variables: not all generalized type variables were being marked as rigid 255 F# Compiler The representation of discriminated unions that uses static fields and unique objects for unary constructors does not work for deserialized data 263 F# Compiler X-module optimization bug related to incorrectly fixed-up optimization data 183 F# Compiler Error messages from failed overloading can be poor (e.g. Text3D sample) 187 F# Compiler Error message when attempting to access a protected method from outside a subclass needs work 218 F# Compiler Add error when module name declaration is missing from intf or impl when filenames match e.g a.ml & a.mli 227 F# Compiler Signature checking of modules should be able to unify inference type variables 242 F# Language support #else in #if/#endif 194 F# Library Ensure float32, float etc. and other conversions are all complete and orthogonal in MLLib 249 F# Library Sys.time not correctly implemented 256 F# Library Added functions to Set, List and Stream to relate MLLib collections to .NET collections 206 F# Documentation export interop documentation needs work 212 F# Documentation Add 'differentiate' and other samples to the sdk 260 F# Documentation Update docs in parsing sample to reflect the presence of fsyacc and fslex 231 F# Visual Studio Plugin 'UncontrolledError' appears in error box when using VS 261 F# Release Visual studio mode fails to install if user has never started up visual studio since installing it
Various bug fixes: 33 26/11/2004 Abstract IL Generic constraints not correctly read/emitted in binary reader/writer 157 26/11/2004 F# VS VS should take into account the include path 180 02/12/2004 F# Compiler Private constructors may be visible to importing modules 185 10/12/2004 F# VS Problem when loading a F# project where a file did not exist 193 10/12/2004 F# Compiler Abstract IL and F# bug: errors when accessing fiels and methods where types have custom attributes 192 10/12/2004 F# Compiler upcasting from .NET array types to object reported a bogus warning about boxing, 191 10/12/2004 F# Compiler Errors are not reported at right location when argument types are wrong 186 10/12/2004 F# Language Cannot access protected methods on .NET objects 178 19/11/2004 F# Compiler Declaring a field of a given name blocks out any ability to access members of that name regardless of type annotations 177 19/11/2004 F# Compiler Some value recursive declarations incorrectly being labelled as "recursive data"
1. New compiler switches: --all-warnings: Print all warnings. --no-warnings: Do not print any warnings. --warn: Report the given specific warning. --no-warn : Do not report the given specific warning. --all-warnings-as-errors: Treat all warnings as errors. --warn-as-error : Treat the given specific warning as an error. Warning numbers are printed as part of error messages and the less obvious ones will have further documentation in the manual including links to tutorials. 2. Better and fewer error messages for uses of value recursion. 3. Fixed a number of bugs: - Pretty much all uses of data constructors within value recursion declarations were incorrectly being labelled as "direct recursion" instead of "value recursion". - Field lookup was preferring ML-style field lookup over adhoc-name field lookup based on inferred type. This meant that declaring an F# field such as "Text" anywhere in your program meant that no adhoc lookup on "Text" would ever be resolved. - Type information was not being propagated correctly from outside-in for "let rec" bindings.
1. Change the compilation model to compile assemblies in one shot
like C#. This gets rid of ALL the .cno, .cni, .cnx and .cnw files,
leaving just a DLL. The compiler will add a custom attribute to store
the F# interface and optimization data. For this version this will be
brittle under changes to the F# compiler, but we will revisit that in
later versions to arrive at a stable metadata format.
2. Cleanup code in preparation for the long-awaited source release. In particular
* The parser had several of uppercase/lowercase distinctions left over from my
initial version of a parser for the Caml syntax. These don't apply to F#
which disambiguates more identifiers at a later stage.
* Some optimizations have been rearranged, so less is done in the backend
phase of the compiler. This greatly simplifies the code.
* The treatment of the decision trees that arise from pattern matching was
too complex. This has been simplified.
3. Add more support for making F# code highly usable from C# and other .NET
languages. I have the long term aim to make sure that simply no one can tell
something is written in F# if you don't want them to. The design for this is
somewhat up in the air, but will almost certainly involve attributing the F#
code to indicate how it should look from C# and other .NET languages.
4. Cleanup namespaces.
All F# stuff is now in Microsoft.FSharp.
All built-in types like list, option, ref, etc. will also be defined there.
From C# they will be called List, Option, Ref etc.
Microsoft.FSharp.MLLib.Pervasives
Microsoft.FSharp.MLLib.String
Microsoft.FSharp.MLLib.List
etc. This has obvious advantages, and allows for an F#-specific library in
the future, and perhaps even other libraries and source syntaxes to provide
some level of mix-n-match for other functional programming languages.
5. Generate generic code by default. Non-generic code for
use with versions of the CLR prior to Whidbey will need a
command line option, e.g. "-no-generics"
6. Revisit subtyping, especially w.r.t. overloading, upcast, downcast etc.
Casting and nulltest operations for .NET types are now built-in
as primitive syntactic forms in F#.
expr ==
| e :? ty -- dynamically test if 'e' has type 'ty'. A compile-time error
will occur if local type inference does not
infer types such that this is a valid downward type test.
| e :> ty -- statically upcast 'e' to type 'ty'. A compile-time error
will occur if local type inference does not
infer types such that this is a valid upcast.
| e :?> ty -- dynamically downcast 'e' to type 'ty'. A compile-time error
will occur if local type inference does not
infer types such that this is a valid downcast.
| downcast e -- runtime checked downcast from 'e' to an arbitrary type
inferred from the context. A compile-time error
will occur if local type inference does not
infer types such that this is a valid downcast.
| upcast e -- statically checked upcast from 'e' to an arbitrary type
inferred from the context. A compile-time error
will occur if local type inference does not
infer types such that this is a valid upcast.
| e1 ?? e2 -- dynamically test if 'e1' is null, and if so evaluate e2.
A compile-time error will occur if local type inference
does not infer types such that e1 is a .NET type. Equivalent to
(match e1 with null -> e2 | freshv -> freshv)
| null -- generate a null value of an arbitrary type inferred
from the surrounding context. A compile-time error
will occur if local type inference does not guarantee that
the type of the value is definitely a .NET reference type.
pat ==
| null -- the pattern corresponds to a null test. A compile-time error
will occur if local type inference does not ensure that
the value being matched against is a .NET reference type.
| :? ty -- the pattern corresponds to a .NET type test. A compile-time error
will occur if local type inference does not
infer types such that this is a valid downward type test.
| :? ty as id -- the pattern corresponds to a .NET type test, and if
successful the variable 'id' is bound to the value at the given
type.
Examples:
a. Doing a null test in a pattern match:
let d = new OpenFileDialog() in
match d.OpenFile() with
| null -> Printf.printf "Ooops... Could not read the file...\n"
| stream -> ...
let r = new StreamReader(stream) in
Printf.printf "The first line of the file is: %s!\n" (r.ReadLine());
b. Doing a null test in an expression:
let myReader = new StreamReader(new FileStream("hello.txt")) in
while true do Console.WriteLine(myStream.ReadLine() ?? raise End_of_file); done;
Valid casts are those between .NET types related by class extension or interface
inheritance, and also between F# reference types and the type 'obj' (i.e. System.Object).
Thus F# values can be stored in heterogeneous collections such as
System.Collections.ArrayList.
Local type inference is underspecified in this version of F#.
In a future version of F# this will be adjusted to correspond to the
process of using only "definite" type information in order to make a
compile-time assessment, i.e. type information from external libraries and modules, from
user type annotations, from uses of F# discriminated unions and F# record labels,
and from other similar type information that arises directly from F# syntactic
forms.
In this version of F# local type inference applies applies all type information
available to the left of a term, including the use of type equivalences inferred
via Hindley-Milner style unification.
(TODO) 7. Allow attributes to be declared. Syntax proposed is "[]"
in various places. This is not yet settled and is certainly up for discussion.
8. Typesafe OCaml-style 'printf' is now supported. See the Printf library module.
9. Object expressions are now supported.
9a. Basic object expressions.
An object expression declares an implementation and/or extenstion of a class or interface.
For example,
"{new IComparer with Compare(a,b) = if a < b then -1 else if b < a then 1 else 0 }"
In each example below the "{new ... with ... }" expression generates a new class
underneath the hood that implements/extends the given type.
Note how little type information you need: the required signatures for OnPaint,
Compare, ToString etc. are inferred by looking at the unique virtual method that
we must be overriding. Note too how the anonymous classes close over free variables
(e.g. capture the variable "n") behind the scenes.
open System
open System.Collections
open System.Windows.Forms
let myComparer = {new IComparer with Compare(a,b) = compare a b}
let myFormattable = {new IFormattable with ToString(fmt,fmtProvider) = ""}
let myForm title n =
let res =
{new Form()
with OnPaint(paintEventArgs) = Printf.printf "OnPaint: n = %d\n" n
and OnResize(eventArgs) = Printf.printf "OnResize: n = %d\n" } in
res.Text <- title;
res
You may only override/implement methods in anonymous classes. You may not declare fields
or new methods. To override/iumplement virtual properties you should override the "get_PropertyName" and
"set_PropertyName" methods that represent the property under-the-hood. Likewise to override
virtual events you should override the "add_EventName", "remove_EventName" and "fire_EventName"
methods that represent the event under-the-hood.
9b. Accessing "this" in object expressions.
There is no "this" keyword, and for good reasons:
1. In object-oriented languages an object may not be sucessfully constructed
at many points where "this" can be used. These leads to inherent weaknesses
in the initialization-soundness guarantees of these languages.
2. The natural typing for "this"/"self" would reveal the anonymous type
of the implementation. Object expressions are for defining implementations,
not types, and it is not desireable to mix type-generation with object expressions
unnecessarily. This is similar to the way the discriminants of discriminated
unions are not types in F# (though they may be types in the underlying IL).
3. Sometimes you want to access not "this"/"self" but another object in a self-referential
graph of objects. There is nothing fundamentally different between doing that
and accessing "this" or "self".
However, you can access "this" by using the "reactive recursion" feature described elsewhere in these
notes. This feature results in a compiler warning that the initialization guaranteed for the object
expression may not be as strong as you wish, and in particular that (in theory) the constructor
for the object may invoke a virtual method which uses "this" before the object is initialized. For
example
let rec obj = {new System.Object()
with GetHashCode() = (obj.ToString()).Length}
Here the identifier "obj" plays the role of "self" or "this". This example makes it plainer
why "let rec" must be used: obj is certainly defined in terms of itself, i.e. its definition is
self-referential or recursive.
Note that mutually-self-referential objects can be defined via the same mechanism:
let rec obj1 = {new System.Object()
with GetHashCode() = (obj2.ToString()).Length}
and obj2 = {new System.Object()
with GetHashCode() = (obj1.ToString()).Length}
Thus the primitive is self-referentiality via "reactive recursion" rather than allowing all
object expressions to access "this".
9c. How to access the base class members, e.g. C#'s base.OnPaint()
An inescapable part of the design of .NET object-oriented libraries is that they
require extensions of some class types to use the implementations of overriden methods
as part of the definition of the extension. This is seen in C#'s "base" identifier.
F#'s permits object expressions that extend classes to be defined partly in terms
of the base functionality of that class. This is done be labelling that functionality
as part of the object expression:
{new Form() as base
with ... }
Here "base" is not a keyword, just as "this" and/or "self" are not keywords. Any identifier
can be used for base, and if object expressions are nested then different identifiers
should be used at different points.
In the example, the variable "base" has type "Form", and can only be used to perform
method invocations, e.g. as follows:
let myForm =
{new Form() as base
with OnPaint(args) = base.OnPaint(args); Printf.printf "OnPaint\n" n
and OnResize(args) = base.OnResize(args); Printf.printf "OnResize\n" n }
9d. Implementing multiple interfaces
This is not supported in this release.
10. Allow F# exceptions to be mapped to/from .NET exceptions, especially
in cases like Out_of_memory and Stack_overflow.
11. Further optimizations:
- Standard functional language optimizations for expressions known to be
strings, constructors and tuples
- Lift additional closed expressions to the top level
- Optimize away inner polymorphism when functions are only used at one type
13. Extensive testing for all optimizations (a number of bugs were fixed
which meant optimizations weren't always firing.)
14. Fix a bunch of minor bugs
* Too much stuff was being made public. This was hurting abstraction and interop.
* Precedence bug with infix operators such as "&&&&" and "||"
* Improved various error messages
* Minor stuff with calling methods on structs
* A bug with Flush on StreamWriters reported by Dominic Cooney (thanks Dominic!)
* Some bugs with error reporting reported by Alain Frisch (thanks Alain!)
* A bug meant that we weren't turning tailcalls into loops for recursive public functions
* A bug meant that an obscure internal error such as "undefined type variable: 'a567" was sometimes being reported. Appears to be the same as a bug reported by Dominic Cooney (thanks Dominic!)
* Robert Pickering reported various bugs, including one involving delegates (thanks Robert!)
* Creation of delegates taking no arguments (e.g. ThreadStart) had a bug
* Fixed a typechecker bug with indexer properties
* A couple of error messages weren't being printed, resulting in messages such as 'Tc.Fields_from_different_types(_, _, _)'
* Fixed a couple of bugs with parsing floating point numbers
* int_of_float now truncates the floating point number toward zero, rather than
rounding. This is in line with the OCaml specification. While it's not
clear that this is the desired behaviour, it seems appropriate that the
items in Pervasives should follow the semantics of OCaml as closely as possible.
* Fixed many bugs associated with F# values accessed using long paths, e.g.
Microsoft.FSharp.Some("3") is a valid way to refer to Some("3").
* The number of compiler generated names appearing in the output has been reduced, and the
internally generated identifiers that are produced have been made simpler, with fewer
numbers appearing.
* Can now reference multi-module assemblies.
* Fixed a bug with the shift operators reported by Dominic Cooney (thanks Dominic!)
* Fixed a bug with the ConcurrentLife sample's repainting behaviour reported by Dominic Cooney (thanks Dominic!)
15. Support 64-bit, 16-bit, 8-bit constants, and unsigned versions of the same,
62y: 8-bit signed byte
62uy: 8-bit unsigned byte
62s: 16-bit signed
62us: 16-bit unsigned
62l: 32-bit signed
62ul: 32-bit unsigned
62L: 64-bit signed
62UL: 64-bit unsigned
The use of 'l' is a little unfortunate for 32-bit integers, since in C/C++-land
it means "long", i.e. 64-bit. However the above is consistent with OCaml's
use of constants, and there is no point being needlessly inconsistent.
Literals of type 'bytearray' are now supported, with syntax B"abc\n" etc.
Literals with syntax "abc\n" are unicode strings as previously.
Literals of type 'byte' are now supported, with syntax B'\n', B'0', B'\t', B'a', B'\212' etc.
Literals with syntax '\n', '0', '\t', 'a' '\212' etc. are unicode characters as
previously.
16. Greatly improve debug support by getting more accurate sequence points.
17. Unicode escape sequences in identifiers and strings, ala C# style, i.e. \uXXXX and \UXXXXXXXX
Somewhat crude support for authoring files in UTF-8 encoding is also supported.
Unicode UTF-8 input may be used, where unicode characters are only currently allowed to appear in strings.
Unicode characters in identifiers will also currently parse, but no true support is offered here: in particular
error messages will be garbled, and we do not restrict identifier characters to the expected set of
alpha-numeric equivalent characters.
18. Support for commercially use by permitting deployment of the F# library if it
is statically linked into an application.
The --standalone switch statically links the F# library and all referenced DLLs
that depend on that library into the assembly (normally a .EXE) being produced.
A verbatim copy is made of all the types and other definitions in all these
DLLs and the copy is added to the assembly produced. Although these types
may have the same name as the original types in the C# library, they are
logically distinct.
19. Operators. The following operators have always been supported by F#, but are now
user definable, rather than being tied to arrays and unicode strings.
.[] .() .[]:= .():=
This can help with porting OCaml code to F#, since the operations .[] and .[]:=
can now be redefined to act on bytearrays rather than unicode strings.
e.g.
let (.[]) s n = Bytearray.get s n
let (.[]<-) s n m = Bytearray.set s n m
let (.()) s n = Microsoft.FSharp.Compatibility.CompatArray.get s n
let (.()<-) s n = Microsoft.FSharp.Compatibility.CompatArray.set s n
The operators ~- and ~-. have always been available in OCaml but not previously in F#.
These let you redefine the unary "-" and "-." operators respectively, e.g.
let (~-) n = Int64.neg n
20. Accessing .NET: Indexer properties. Indexer properties can now be accessed with the following
natural syntax:
let s = "abcdef" in
s.Chars(2) // returns 'c'
and for properties with C# syntax 'x[n]' use:
x.Item(n)
e.g
open System.Collections;
let f (x:ArrayList) = x.Item(0)
21. F#'s version of "recursion through data types using 'let rec'"
to create "infinite" (i.e. self-referential) data structures is now slightly
more restricted. You can't use recursive 'let rec' bindings through immutable fields
except in the assembly where the type is declared. This means
let rec x = 1 :: x
is not supported. This was required to make sure the head/tail fields of lists are
marked "private" and "initonly" in the underlying assembly, which is ultimately more
important than supporting all variations on this rarely-used feature. However note that
type node = { x: int; y: node}
let rec myInfiniteNode = {x=1;y=myInfiniteNode}
is still supported since the "let rec" occurs in the same assembly as the type definition,
and
type node = node ref
let rec myInfiniteNode = { contents = myInfiniteNode }
is supported since "contents" is a mutable field of the type "ref".
22. Nice-Compiled-Forms: Access of discriminated unions from other .NET languges has been improved.
F# data types are compiled to C# classes with additional support to access the information carried by
the data type.
Constructing values of F# discriminated unions
----------------------------------------------
A static method is supported for each discriminant, e.g.
List.Cons(3,null)
Option.Some(3)
Discriminating on F# discriminated unions
-----------------------------------------
The following section applies if the type has more than one discriminant.
The support depends very marginally on when "null" is used by the F# compiler as
a possible representation of value of the data type. This is because types where "null" is used as
representation cannot support some instance members (they would result in a null pointer exception
when used from C#).
"null" will ONLY be used by the F# compiler in EXACTLY the following situations:
- For the single value of the "unit" type
- For discriminated unions with exactly 2 constructors, where exactly one of
those constructors is nullary - of course 'null' is then used for
as the representation for the nullary constructor. Thus "null" may be
used for the "list" and "option" types, and types very similar to these,
but will rarely be used for other datatypes.
If "null" is NOT used as representation then a type will support
(a) a Tag property and several tag_... compile-time constants. These can be used for discrimination
by switching.
(b) a series of IsXYZ() instance methods, one for each constructor. These can be used for discrimination
by predicates.
If "null" IS used as representation then a type will support
(a) a GetTag() static method, and several tag_... compile-time constants. These can be used for switching
In the latter case discrimination by predicates can be performed by comparing values to "null",
since the null value is then guaranteed to be used for the single nullary constructor of the type.
Thus if the C# value x has type MyType and the F# definition of MyType is:
type MyType = A of ... | B of ... | C of ...
then the following C# code is valid:
Console.WriteLine("{0}", x.IsA());
Console.WriteLine("{0}", x.IsB());
switch (x.Tag)
{
case MyType.tag_A:
Console.WriteLine("A");
break;
case MyType.tag_B:
Console.WriteLine("B");
break;
default:
Console.WriteLine("Must be a C");
break;
}
23. Nice-Compiled-Forms: Names for tuple types have changed
The compiled form of tuple type names and tuple member names has been improved, e.g.
Tuple<_,_>.Item1
Tuple<_,_>.Item2
Tuple<_._,_>.Item1
Tuple<_._,_>.Item2
Tuple<_._,_>.Item3
Tuple<_._,_,_>.Item1
Tuple<_._,_,_>.Item2
Tuple<_._,_,_>.Item3
Tuple<_._,_,_>.Item4
...
Tuple<_._,_,_,_,_,_>.Item1
...
Tuple<_._,_,_,_,_,_>.Item7
The compiled forms for tuples of size > 7 are under-specified. The above names change slightly
when targetting .NET 1.0 or 1.1, i.e. a non-Whidbey release, because we then can't use the arity
of the generic type to disambiguate the various "Tuple" names. So the names become
Tuple2, Tuple3 etc. to Tuple7.
24. Nice-Compiled-Forms: Data fields compiled as properties, not fields
Properties are now used to compile all memebers of F# record types, i.e.
type recd = { Name: string; Size: int }
will support
recd.Name (a property, not a field)
recd.Size (a property, not a field)
25. Nice-Compiled-Forms: Fields of alternatives can have names.
F# discriminated unions can now have named fields, e.g.
type 'a list =
Nil
| Cons of { Head: 'a; Tail: 'a list }
Currently this information is ONLY present for describing the .NET view of such a type.
The use of such a name leads to the creation of a .NET property with the given name.
Thus there are strict limitations:
- The names may not currently be repeated amongst different alternatives.
- These fields may not be selected from F# code
- Pattern matching against this form is not yet supported.
- That is, for all other purposes the declaration is treated as
if the fields were declared sequentially as normal, i.e.
| Cons of 'a * 'a list
These restictions may be lifted in a future release.
The inbuilt list and option types are treated as if they have this form, i.e.
type 'a list =
Nil
| Cons of { Head: 'a; Tail: 'a list }
type 'a option =
None
| Some of { Item: 'a }
and thus C# code can use
List x = List.Cons(3,(List.Nil));
Console.WriteLine("x.Head = {0}", x.Head);
Console.WriteLine("x.Tail = {0}", x.Tail);
Console.WriteLine("x.Tail - IsNil = {0}", x.Tail);
26. (This section only applies when targeting a CLR that supports generics, i.e. when the
--no-generics switch is NOT used. )
The compiled form of function types has been finalized to be Microsoft.FSharp.FastFunc<A,B>. This
will not change, though the details of the implementation of the
Microsoft.FSharp.FastFunc class may be revised. FastFunc<A,B> is not a
delegate type (which may be what some users expect). This option has been finally rejected
for both interoperability and performance grounds.
Creating function values that accept one argument
-------------------------------------------------
It it important to be able to create and use values of this type from C# in a
fashion that is as easy and natural as possible.
One option is to create function values by using subclasses of
Microsoft.FSharp.FastFunc<A,B> that override the "Invoke" method. However this
is not the recommended way of creating such values, since it is then not so easy to
use C#'s anonymous delegate feature when creating delegates.
The most uniform way to create a FastFunc is to use an anonymous delegate. You simply
create an appropriate .NET function-like delegate (e.g. System.Converter) and then
call Microsoft.FSharp.FuncConvert.ToFastFunc. In particular,
FuncConvert.ToFastFunc(...) supports the following overloads:
...(System.Converter<T,U> f) producing FastFunc<T,U>
...(System.Action<T> f) producing FastFunc<T,object>
...(System.Predicate f) producing FastFunc<T,bool>
Additionally, there is an implicit conversion from System.Converter<T,U> to FastFunc<T,U>,
and thus you can omit the call to FuncConvert.ToFastFunc() but ONLY when reating a delegate
of type System.Converter<A,B> (for some A,B).
For example, the following are equivalent:
List.map(FuncConvert.ToFastFunc((Converter<int,string>) delegate(int x)
{ return x.ToString() + x.ToString(); }),
myList);
and
List.map((Converter<int,string>) delegate(int x)
{ return x.ToString() + x.ToString(); },
myList);
Creating curried function values that accept multiple arguments
---------------------------------------------------------------
The above techniques works well when creating F# function values that expect one argument.
However the above can be awkward when creating F# function values that accept multiple
values, whether by "currying" or by "tupling". Thus the F# library defines
additional similar types in order to support additional conversions. In particular it defines
delegate void System.Action<A1,A2>(A1 x, A2 y);
delegate void System.Action<A1,A2,A3>(A1 x, A2 y,A3 z);
delegate B System.Converter<A1,A2,A3,B>(A1 x, A2 y,A3 z);
and Microsoft.FSharp.FuncConvert.ToFastFunc(...) method supports
the following overloads that produce "curried" functions:
ToFastFunc(System.Converter<A1,B> f) producing 'A1 -> B', i.e. FastFunc<A1,B>
ToFastFunc(System.Converter<A1,A2,B> f) producing 'A1 -> A2 -> B', i.e. FastFunc<A1,FastFunc<A2,B>>
ToFastFunc(System.Converter<A1,A2,A3,B> f) producing 'A1 -> A2 -> A3 -> B', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,B>> >
ToFastFunc(System.Action<A1> f) producing 'A1 -> unit', i.e. FastFunc<A1,object>
ToFastFunc(System.Action<A1,A2> f) producing 'A1 -> A2 -> unit', i.e. FastFunc<A1,FastFunc<A2,object> >
ToFastFunc(System.Action<A1,A2,A3> f) producing 'A1 -> A2 -> A3 -> unit', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,object> > >
For example:
using System;
using Microsoft.FSharp;
using Microsoft.FSharp.MLLib;
List<int> myList = List.of_array(new int[] { 4, 5, 6 });
string joined =
List.fold_right<int,string>
(FuncConvert.ToFastFunc((Converter<int,string,string>) delegate(int i,string acc)
{ return i.ToString() + "-" + acc; }),
myList,
"");
Creating function values that accept multiple arguments as tuples
-----------------------------------------------------------------
To create F# function values that accept their arguments as tuples use
Microsoft.FSharp.FuncConvert.ToTupledFunc.
ToTupledFastFunc(System.Converter<A1,B> f) producing 'A1 -> B', i.e. FastFunc<A1,B>
ToTupledFastFunc(System.Converter<A1,A2,B> f) producing 'A1 * A2 -> B', i.e. FastFunc<A1,FastFunc<A2,B>>
ToTupledFastFunc(System.Converter<A1,A2,A3,B> f) producing 'A1 * A2 * A3 -> B', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,B>> >
ToTupledFastFunc(System.Action<A1> f) producing 'A1 -> unit', i.e. FastFunc<A1,object>
ToTupledFastFunc(System.Action<A1,A2> f) producing 'A1 * A2 -> unit', i.e. FastFunc<A1,FastFunc<A2,object> >
ToTupledFastFunc(System.Action<A1,A2,A3> f) producing 'A1 * A2 * A3 -> unit', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,object> > >
27. Added List.of_array and List.to_array.
28. Initialization semantics for toplevel bindings have been changed to be
more suitable for a multi-language, dynamic loading setting.
- .EXEs: The only top-level bindings that are immediately evaluated on startup are those
in the last module specified on the command line when building a .EXE.
- .DLLs: All bindings in a DLL are executed on demand, at most once each time a module is loaded into
a .NET application domain. The execution may be triggered by the access of any of
the fields or methods of a module. The granularity is guaranteed to imply that all the
top level bindings in a single F# source file are evaluated sequentially if
any are evaluated.
29. The compiled type name for the type of hashtables is now
Microsoft.FSharp.MLLib.Hashtbl.Hashtbl
rather than
Microsoft.FSharp.MLLib.Hashtbl.t
This looks better in the debugger and from other .NET langauges.
The latter (or equivalently Hashtbl.t) is still valid from F# code, and
is a F# synonym for the former. In the future the compiled name of the type may
be changed to be simply Microsoft.FSharp.MLLib.Hashtbl.
The same applies to Lazy.t
30. The Buffer module has been implemented in MLLib and is a trivial wrapper for ML's Buffer.t
type to .NET'd StringBuilder type.
31. Type operations
The expression "e :? ty" is equivalent to a dynamic type test. A warning
will be emitted if the type of e cannot be statically determined to be
a subtype of ty (statically determined == using the inference
information available at this point in the typechecking of the program, where
inference proceeds left-to-right through the program). An error will
be reported if the type test will always succeed.
This is especially useful for testing for classes of .NET exceptions, e.g.
try
...
with
| e when (e :? System.Net.Sockets.SocketException) -> ...
| e when (e :? System.OutOfMemory) -> ...
The expression "e as ty" is equivalent to an upcast. An error
is given if the compiler cannot statically
32. Subsumption can now be used at method call sites where this disambiguates
a method overload.
That is, upcasts will now be allowed for arguments when calling .NET methods. The rule for
resolving overloading will be:
o we only consider overrides that match by name and arity (since we always know the
number of arguments being applied)
o if there is only one such method then each actual/formal argument must either
match by an upcast or by unification
o if there are multiple such methods then:
- if the argument types of only one such method match by type equivalence then that one is used
- otherwise if the argument types of only one such method match by type equivalence
and/or upcasts then that one is used
- otherwise report an error
Here upcasts and type equivalence are performed in the sense of "local type inference"
as described below. Thus the overload resolution is less aggressive than
C# (no automatic boxing/implicit-conversions, less aggressive resolution of ambiguity
between methods based on "best overload") but you can always specify the overload you want.
33. Runtime-checked reactive 'let rec' recursion is now supported.
This means you can write values (and not just functions) whose
specifications appear to refer to themselves, but where the
self-references are hidden inside delayed values such as inner functions,
other recursive functions, anonymous 'fun' lambdas, lazy computations,
and the 'methods' of object-implementation expressions. A much
broader class of expressions can now be used in 'let rec' bindings,
and in particular the expressions can be applications, method calls,
constructor invocations and other computations.
The recursion is 'runtime checked' because there is a possibility that
the computations involved in evaluating the bindings may actually take
the delayed computations and execute them. The F# compiler gives
a warning for 'let rec' bindings that may be ill-founded (i.e. bindings which
it can't convince itself are well-founded), and inserts
delays and thunks so that if runtime self-reference does occur then
an exception will be raised. In the future the exception raised will
be augmented to carry useful information such as line numbers and
the dependencies in the bindings.
The recursion is 'reactive' because it only really makes because
it really only makes sense to use this when defining automaton such
as forms, controls and services that respond to various inputs
and make self-referential modifications as a result, e.g. GUI
elements that store and retrieve the state of the GUI elements
as part of their specification. A simple example is the following
menu item, which prints out part of its state as part of its action:
let rec menuItem : MenuItem =
new MenuItem("&Say Hello",
new EventHandler(fun sender e ->
Printf.printf "Hello! Text = %s\n" menuItem.Text),
Shortcut.CtrlH)
A compiler warning is given when compiling this code because
in theory the "new MenuItem" constructor could evalute the callback
as part of the construction process, in which case a self-reference
would have occured - and F# can't prove this won't happen. It is an
current research topic in the language design community to
design type systems to catch these cases, but in the context of
.NET a relatively non-restrictive construct is needed since stateful
components are unavoidable, and it would be difficult (if not impossible)
to design libraries such as WinForms in such a way that a type system
would prove the well-foundedness of the self-referential accesses.
34. Additional syntax forms supported:
expr := ...
| try <expr> finally <expr> -- always execute an exit block, even if an exception occurs
topdecl := ...
| module <long-identifier> -- specify the namespace/class for the generated bindings
| do <expr> -- execute the given expression
bindings := ...
| do <expr> -- execute a statement as part of a recursive binding
35. New keywords
For .ML, .MLI, .FS and .FSI files: finally, upcast, downcast, null, :> , :?> , :?
Reserved for .FS and .FSI files:
base constraint default namespace return switch
enum extern fixed functor include inherit module
object virtual sig using interface class volatile
process method
36. Namespaces and module names can be specified with an initial
declaration at the head of a file, e.g.
module Microsoft.FSharp.MLLib.Pervasives
module MyLibrary.MyModule
The final identifier is treated as the module name, the former
identifiers as the namespace.
By default there is no namespace and the existing rule is used
for the module name (i.e. the first letter of the filename is
capitalized). A default namespace can be specified via the --namespace
command line option. If any module ddeclaration is given it overrides
both the default namespace and the rule for naming modules.
37. 'try-finally' blocks are supported
38. The Game of Life sample has been thoroughly revised
to be a Multi-threaded GUI application showing how
to control the progress of underlying computations as
they execute.
39. C#/C++-style "//" comments-to-end-of-line are now supported.
"(*" and "*)" have no special meaning inside this comment text.
This is technically an incompatibility with OCaml code, however it
is usually trivial to simply change the name of the "//" operator
to something else.
40. An extra compiler switch --minimal-cli-version is supported by
which you can specify the minimal .NET CLI required to run
the generated binary. For example, even if you are developing
using v2.0 (Whidbey) you can generate a bnary for use on V1.1
by using a combination of "--minimal-cli-version 1.1.4322" and
"--no-generics", likewise "--minimal-cli-version 1.0.3705".
The generated binary may, of course, still require library
features from later versions. You should certainly run peverify
from the appropriate version of the .NET SDK on the binaries to
ensure they are correct.
As an alterntaive to all of this you may also alternatively
be able use a configuration file for fsc.exe to ensure
the correct runtime is used when compiling - see examples such
as ilasm.exe.config in your
C:\WINDOWS\Microsoft.NET directory.
41. F# now supports C#-style #if/#endif conditional compilation. The
command line switch is --define. The conditional compilation syntax to
support mixed OCaml/F# programming has also changed a little (the old syntax
was universally regarded as gross and was non-uniform). The syntax how is simply
that text surrounded by
(*IF-FSHARP ... ENDIF-FSHARP*)
and (*F# ... F#*)
are included when compiling with the F# compiler, and text surrounded by
(*IF-CAML*) ... (*ENDIF-CAML*)
(*IF-OCAML*) ... (*ENDIF-OCAML*)
is excluded when compiling with the F# compiler. Of course the converse holds when
compiling programs using the OCaml compiler.
42. F# now supports generation of retargetable .NET binaries. Retargetable binaries
are neutral w.r.t. the publisher of particular referenced binaries. For example,
a truly portable .NET program will be neutral w.r.t. the publisher of mscorlib -
rather than picking up a dependency against the publisher of mscorlib used at
compile-time. This means the program will bind to ANY assembly called "mscorlib",
which is OK for mscorlib but is not necessarily such a good idea for other strong
named assemblies.
You can tell if you have generated retargetable references by using the ILDASM
tool that comes with the CLR. If you have you will see:
.assembly extern retargetable mscorlib
{
.publickeytoken = (96 9D B8 05 3D 33 22 AC ) // ....=3".
.ver 2:0:3600:0
}
.assembly extern retargetable System
{
.publickeytoken = (96 9D B8 05 3D 33 22 AC ) // ....=3".
.ver 2:0:3600:0
}
and so on. Public key tokens are used to help name a referenced assemblies.
The particular public key token used above is the unique "neutral" key token as
specified by the .NET ECMA spec.
I have been told that Microsoft's Compact Framework (CF) counts as a second set of "published" assemblies,
and so if you want to make binaries that can be executed on the CF and other versions of the
CLR then you should use this option.
The --retargetable option is used to indicate a particular assembly reference to
make retargetable in the produced binary. There is no way to make all assembly references
retargetable - you have to do it on a case-by-case basis. Furthermore the reference
to "fslib" is not retargetable, since you have to use the fslib provided in the F#
distribution.
43. F# now supports funcitons Map.Make and Set.Make that accept comparison functions and
return record expressions that act as components. These are akin to
OCaml's Set.Make and Map.Make functors. The release also includes Map,
Set and Hashtbl implementations that use polymorphic comparison. Hashtbl.Make is
yet to be done.
44. F# now supports "forall" types on fields. That is, fields can have types that logically
speaking correspond to generic methods. This is useful when records are used to
represent modules, e.g. with Map.Make and Set.Make's fold functions.
45. F# field names may now be used as part of the "." notation even when the field names
have not been brought into the top level scope via an "open". For example if
a module contains
type recd = { Name: string }
then you may use
x.Name
if x is determined by local type inference to be of type "r". This is subject to the
same rules as .NET member lookups, i.e. the type of the value to the left of the "."
must be determined by local type inference using annotations and other
information available left-to-right, outside-to-inside.
46. Optimization improvements to "==" and polymorphic comparison.
47. A Visual Studio integration is now supported, with syntax
highlighting, automatic parsing, automatic typechecking
and a simple project system.
48. --target-winexe, --target-exe and --target-dll are now supported.
49. Pervasives now supports string-named versions of all the Caml-style
operators defined in that file, e.g. op_GenericEquality for '='. See
pervasives.fsi for the full list of names used.
50. A lexer generator along the lines of ocamllex/mosmllex is now supported.
Input files identical to ocamllex files are supported, with the following exceptions:
- using 'as' to label internal portions of matched strings is not supported
- '#' regular expressions are not supported
- 'shortest' matching is not supported
- Command line options -o, -ml, -q are not supported
The Lexing library module is supported with a specification similar to the specification
of OCaml's Lexing module. This was coded from scratch. Most of the fields
of the lexing state are hidden, adn thus differ from OCaml, with the exception
of Lexing.lex_start_p and Lexing.lex_curr_p.
51. A parser generator along the lines of ocamlyacc/mosmlyacc is now supported.
Input files identical to ocamlyacc files are supported. See the notes in the Parsing
module in MLLib for some compatibility issues.