Detailed Release Notes for F# 1.9.4
These are the full release notes for F# 1.9.4. The download link is on the main announcement page. We'll also use this page to note known issues with the release as we find them.
Summary
Language
- Symmetric Operator Overloading
- Additional nullness checking
- 'base' variables must now be called 'base'.
- Intrinsic members take predence over extension members
- Generic Equality now uses Object.Equals
- Downcasting For Interface Types
- Handle Optional Aruments Correctly when using a method as a first class function value
- Change .[] overload resolution behaviour
- Deprecate the Unicode symbols in the language
- Sealed attribute
- AbstractClass attribute
- typeof may be used in attributes, deprecate (type ...) syntax
- Decimal support
- Supply Named and Optional Aruments to COM methods
- Allow construction of delegates taking byref arguments
Library
- fold_left performance improvements
- Not_found now maps to KeyNotFoundException not IndexOutOfRangeException.
- Addition of the 'enum' overloaded function.
- Deprecate the Enum.to_int and Enum.of_int functions.
- Access control checking for modules and types implemented
- Deprecate the use of string.CompareTo in favour of System.String.CompareTo
- Deprecate the IEnumerable module in favour of Seq
- Deprecate the CompatArray and CompatMatrix modules when used with .NET 2.0
- Deprecate the truncate OCaml-compatibility function
- Make 'lock' function safer: may now only take reference types
Tools
- Counter Examples from Incomplete Pattern Matches
- Implement redundancy checking for isinst patterns
- Many Improved Error Messages
- Ctrl-C now copies, Ctrl-. used for Interrupt in F# Interactive in Visual Studio.
- Right-click menus supported in F# Interactive in Visual Studio
Current Known Issues
- Two overloads on "Complex" were deprecated (float * Complex and Complex * float) but no replacements provided. Just ignore the deprecation warning for now.
- Named parameters with custom attributes give a spurious warning. This may be ignored.
- There is a known problem using F# in Visual Studio on Vista machines where the Tablet PC input services are running, e.g. laptops. This may be addressed by stopping those services from the Control Panel.
Language Enhancements: Design Extensions and Changes
Symmetric Operator Overloading
F# uses a form of type-directed operator overloading. (Type-directed operator overloading means that operators such as '+' resolve to different implementations depending on the static types of the two arguments.) Previous releases of F# used asymmetric, type-directed overloading that placed more emphasis on the type of the left argument rather than the type of the right argument. For some time it has been recognized that this form of operator overloading is somewhat unintuitive. This release switches this to use symmetric operator overloading. For example, consider the following cases:
let f1 x y = x + y //: int -> int -> int
let f2 (x:float) y = x + y //: float -> float -> float
let f3 x (y:float) = x + y //: float -> float -> float
let f4 (x:matrix) y = x + y //: matrix -> matrix -> matrix
let f5 x (y:matrix) = x + y //: matrix -> matrix -> matrix
let f6 (x:matrix) (y:vector) = x * y //: matrix -> vector -> vector
These indicate that operator overloading resolves independent of whether the known type information is associated with the left-hand or right-hand argument of the operator.
The two principles that now form the basis of F# operator overloading are
- symmetry for binary operators and
- operator overload constraints are resolved using method overload resolution.
Resolution of an operator such as + is performed against a set of potential overload resolutions derived from the left and right hand argument types. For example, when resolving a constraint
static member (+) : float * matrix -> ?
The relevant operator overloads are drawn from the float and matrix types. At some points in inference (indeed very frequently) we have incomplete information about the types involved, e.g.
static member (+) : float * ? -> ?
In these cases it is important to note that later type information may discover additional nominal information, e.g. to resolve the constraint to
static member (+) : float * matrix -> matrix
In more detail,
- "Strongly determined" resolution is applied as soon as the relevant set of potential overloads becomes closed. In this case, the available operator resolutions are collected from each of the nominal types (e.g. op_Addition static members) and standard method overload resolution rules are applied. For example, if we write OP(?,?,?) for an operator overload constraint, then the constraint OP(float,float,?) resolves immediately to OP(float,float,float) .
- "Weakly determined" resolution is applied at specific points during inference in order to normalize the inference problem prior to making choices about generalization and type-directed overloading. For example, weakly determined resolution is used to resolve the operator constraint OP(Matrix<?>,?,?) that arises from the following code:
open Microsoft.FSharp.Math
let f7 (x:Matrix<_>) y = x + y
- In particular, we apply "Weakly determined" to all constraints involved in
- generalization
- method overload resolution for expressions
- resolving the '.' notation
- applying defaults at the end of the inference scope
Weakly-determined resolution resolves a constraint if either l.h.s. or r.h.s are nominal types. For example, given OP(float,?,?) then non-conservative resolution resolves immediately to OP(float,float,float) .
Conditional Method Calls and assert
Conditional method calls are a .NET feature where a call to particular methods marked with System.Diagnostics.ConditionalAttribute are only executed if a conditional compilation symbol such as DEBUG is defined. One common example of this is System.Diagnostics.Debug.Assert. F# now supports conditional method calls.
As a result of this change, calls to System.Diagnostics.Debug.Assert may no longer "trigger" in your code.
Uses of the assert function are now treated as if they are calls to System.Diagnostics.Debug.Assert. This means expressions such as assert (1=2) will not fire in your code unless --define DEBUG is specified. This follows standard .NET software engineering practice.
One exception is made for the syntactic expression form assert(false) . This is given a special type in F# and OCaml, i.e. has variable return type not unit. This allows it to be used as a "cannot happen" signifier. In this case, if --define DEBUG is not specified then an AssertionFailure exception is raised in order to halt execution. If --define DEBUG is specified then System.Diagnostics.Debug.Assert, and if the assertion is ignored and execution continues then the AssertionFailure exception is raised in order to halt execution.
Additional nullness checking
.NET is an object-oriented platform and thus includes the notion of null values for reference types. However, the use of null values is, in general, discouraged in F# programming. While it is possible to create null values for reference types, one of the design aims of F# is that this is not a commonly used technique and that, when used, the programmer is made aware of this.
In previous release of F#, creating null values of F# types was relatively easily, e.g. through the commonly used unbox function. This technique, however, will now raise a NullReferenceException. For example, the following code will now raise a NullReferenceException:
type MyRecord = { f : int }
let x = unbox<MyRecord>(null:obj)
This implemented via the use of efficient helper functions related to the types involved.
This change also eliminates several somewhat subtle inconsistencies with regard to types that use null as a valid representation. For example, the option type uses null to represent the None option. Unboxing a null value to one of these types now correctly succeeds and returns a valid value of the type.
In more detail, there are four kinds of types for F#:
- Types that have null as an "extra" value, e.g. string and where the use of the null literal is directly permitted, e.g. .NET reference types such as string.
- Types where the use of null is not directly permitted and which don't use null as a representation, e.g. F# list, record, union, tuple, function, class and interface types
- Types where the use of null is not directly permitted but which do use null as a representation, e.g. F# unit and option types. Note the null literal may not be used with these types.
- Value types, where there is no 'null' but do have a 'default' value.
The behaviour of the unbox and type test primitives of F# now treat these different categories appropriately.
Note that null is still used as a representation for some F# values, in particular None option values. In this case, the value doesn't carry runtime type information in the manner of other object values, and so type tests against such a value are inherently imprecise. This is correct and expected behaviour for these types.
If necessary, null and default values may be generated by calling the new library function Unchecked.defaultof<type> , a helper function specifically designed to make uses of arbitrary null and default values for F# types more traceable in code.
type MyRecord = { f : int }
let x = Unchecked.defaultof<MyRecord>
Minus syntax
Expressions of the form expr -expr, e.g. x -y now give a deprecation warning asking you to rewrite these as either expr - expr or expr-expr. This is to make room for a future design change.
New reserved keyword
The keyword global has been reserved for future use by F# code
Smaller Design Changes
- 'base' variables must now be called 'base' .
A deprecation warning is now given if this is not the case. In a future release of F# base variables will necessarily be called 'base'.
- Intrinsic members take predence over extension members .
Previously extension members were taking priority over intrinsic members in base classes. This has now been corrected.
- Generic Equality now uses Object.Equals
Uses of the generic equality operator (=) and related operators are now implemented via calls to System.Object.Equals.
- Downcasting For Interface Types.
The conversion operator expr :?> type can now be used to convert an interface or non-sealed class type to any other interface type. This matches the C# behaviour of this operator, with the exception that conversions from variable types are not permitted: in that case the expression should first be converted to an object using box.
- Handle Optional Arguments Correctly when using a method as a first class function value.
As has been reported several times in bug reports, when operations such as Async.Run which take optional arguments are used as first-class values the resulting function value previously required the optional argument be made explicit. This has now been changed, and the optional argument is dropped instead.
- Change .[] overload resolution behaviour.
Previously, the resolution of the expr.[expr] operator did not apply operator overloading rules. This led to incompletenessed where the operator could not be used in conjunction with certain C# types. This has now been corrected.
- Deprecate the Unicode symbols in the language.
The Unicode symbols for quotations have been deprecated. Instead, the ASCII symbols <@ @> and the prefix operators % and %% should be used instead.
Language Feature Completions
- Sealed attribute . This attribute may be added to class types to mark them 'sealed', i.e. no base types.
[<Sealed>]
type C(x:int,y:int) =
member this.X = x
member this.Y = y
member this.Sum = x+y
- AbstractClass attribute . This attribute may be added to class types to mark them 'abstract', i.e. missing implementations of some members, and/or with constructors that can't be used directly
[<AbstractClass>]
type C(x:int,y:int) =
abstract X : int
abstract Y : int
abstract GetSum : int -> int
- typeof may be used in attributes, deprecate (type ...) syntax
[<SomeAttribute(typeof<int>)>]
type C(x:int,y:int) =
abstract X : int
abstract Y : int
abstract GetSum : int -> int
- Decimal literals now implemented. For example, 120.00M. The decimal conversion function is now also supported amongst the standard set of conversion functions, and decimal is no longer a keyword.
let pocketMoney = 0.25M
let GDP = 12416505085952.00M
- Supply Named and Optional Aruments to COM methods. It is now possible to use the F# optional argument mechanism to supply arguments to COM methods. This is very important when working with Excel and Word Primary Interop Assemblies. For example,
chartobject.Chart.ChartWizard(Source = range5,
Gallery = XlChartType .xl3DColumn,
PlotBy = XlRowCol.xlRows,
HasLegend = true,
Title = "Sample Chart",
CategoryTitle = "Sample Category Type",
ValueTitle = "Sample Value Type")
Here 4 arguments have been omitted from the programmatic specification of an Excel chart.
- Allow construction of delegates taking byref arguments
Library Enhancements
- fold_left performance improvements.
A number of library functions that take binary functions have been optimized. Many thanks to the folk at Morgan Stanley for sugesting these!
- Collections that previously threw IndexOutOfRangeException now throw KeyNotFoundException.
The OCaml-compatibility exception type Not_found is now mapped to System.Collections.Generic.KeyNotFoundException, rather than System.IndexOutOfRangeException. This means a number of F# functions now raise KeyNotFoundException instead of IndexOutOfRangeException. In the rare case where you explicitly catch IndexOutOfRangeException in your code you will get a warning and may need to adjust your exception handling accordingly. This change was made because IndexOutOfRangeException is a CLR-reserved exception which should not be raised in user or library code.
- Addition of the 'enum' overloaded function.
The enum function can be used to convert integers to enumerations. Likewise, the function int32 can be used to convert back to an integer.
let sunday = System.DayOfWeek.Sunday
let monday = enum<System.DayOfWeek> 1
let tuesday = enum<System.DayOfWeek> 2
- Deprecate the Enum.to_int and Enum.of_int functions.
These can be replaced by uses of enum and int32 respectively.
- Access control checking for modules and types implemented.
That is, private and internal annotations on modules and types are now implemented. Previously these gave a warning.
- Deprecate the use of string.CompareTo in favour of System.String.CompareTo.
This makes room for a planned design change to add a conversion function called string.
- Deprecate the IEnumerable module in favour of Seq.
- Rename MailboxProcessor.PostSync to MailboxProcessor.PostAndReply , deprecating the old name
- Deprecate the CompatArray and CompatMatrix modules when used with .NET 2.0.
Future releases of F# will make .NET 2.0 the default. These modules are only required when using .NET 1.x. When using .NET 2.0 and above, uses of these modules can be replaced by uses of Array and Array2 respectively.
- Deprecate the truncate OCaml-compatibility function.
Instead you should use the synonymous for int_of_float or the F# conversion function int, applied to float values. The design of other F# conversion functions and operators means it is much more natural for truncate be an overloaded function applying to a range of numeric types. Thus a deprecation warning is now given on the use of the existing truncate function.
- Make 'lock' function safer: may now only take reference types.
Tool Enhancements
- Counter Examples from Incomplete Pattern Matches. For example,
let f x =
match x with
| 1 -> 7
| 2 -> 49
stdin(12,14): warning FS0025: Incomplete pattern matches on this expression. The value '3' will not be matched
Note: There is actually one known bug here, where incomplete matches on union types do not always give a valid counter example. This is being addressed.
- Implement redundancy checking for isinst patterns. That is, duplicate or redundant type tests in patterns will now be reported as warnigns.
- Many Improved Error Messages
Enhancements to F# Interactive in Visual Studio
- Ctrl-C now copies, Ctrl-. used for Interrupt. When used in Visual Studio, it is natural for Ctrl-C to be interpreted as 'copy'. This Ctrl-. ('Control-Stop') is now used for interrupt.
- Menus supported. The interrupt, select-all, copy, paste and clear options are now available from the right-click menu.
Bugs fixed
1171 F# Compiler bug binding to a SOAP dll
1109 F# Compiler Make assert a function
1325 F# Compiler Enums of chars are not accepted by F# Interactive
1316 F# Compiler Throw away invalid paths (#r) in FSI
1341 F# Compiler Compiler should reject explicit class construction when an implicit one is defined
1423 F# Compiler bad error message: The member or object constructor 'Random' takes 1 arguments but is here supplied with 1.
1227 F# Compiler ensure we can supply named and optional arguments to COM-interop methods
1404 F# Compiler optional arguments handled incorrectly when using a method as a first class function value.
1418 F# Compiler Methods on Enums should not be allowed
1457 F# Compiler FParsec test 0.4.2. failing with byref check
1185 F# Compiler change .[] overload resolution behaviour
1244 F# Compiler unnecessarily choosing defaults for variables unconstrained, leading to spurious warnings and true errors being needlessly downgraded to warnings
1430 F# Compiler Compiler spits out duplicate errors when given bogus syntax for named arguments
1462 F# Compiler Poor (and repeated) error message on type mismatch
1034 F# Compiler Downcasting for interface types
151 F# Compiler Cannot construt delegate values that accept byref arguments
1024 F# Compiler bug in type inference allows normal values to be polymorphic (type functions have to be declared explicitly and only at the top level)
1187 F# Compiler problem with object constructors and self references
1476 F# Compiler Setting static field in generic type fails to resolve in typechecker
1365 F# Compiler unexpected Warning 65 in the absence of structural hashing and comparison
1472 F# Compiler double quote breaks comment parsing (F# not fully compatible with OCaml)
338 F# Compiler Incomplete pattern matches should report cases that are not covered. THis could also be used by VS plugin when suggesting completions
1366 F# Compiler Unboxing inconsistencies w.r.t 'null'
1488 F# Compiler Implement redundancy checking for isinst patterns
1322 F# Compiler Unhandled Exception using --clr-mscorlib option
1470 F# Compiler Misleading warning "unit was constrained to FSharp.Core.Unit"
1484 F# Compiler Internal Error when compiling a try-with construct
1342 F# Compiler Bad error messages when constructs can't be quoted
1433 F# Compiler Count of supplied parameters incorrect in error message if named parameters are used.
1060 F# Compiler Quotation error: type varaible not found in environment
1463 F# Compiler quotation of a private value error is not reported until codegen, so is not reported in Visual Studio
1445 F# Compiler Failure when generating code for generic interface with generic method
1390 F# Compiler Pattern matching with bigint literals does not work
1105 F# Compiler params attributes not supported
1279 F# Compiler Constructor call with the object-initialization-expr should error
1278 F# Compiler Unresolved generic constructs in quotations should error instead of warn.
609 F# Compiler not printing explicit type constraints on type declarations
1101 F# Compiler spurious warning:This construct causes code to be less generic than indicated by the type annotations. The type variable 'd has been constrained to be type 'System.IDisposable'.
1502 F# Compiler implement a "sealed" attribute
1533 F# Compiler Support "static let"
1233 F# Compiler cyclic inheritance bug
1452 F# Compiler Complete checks for structs
1529 F# Compiler Incorrect IL generated for call to static method on a valuetype
1490 F# Compiler can't use typeof in attributes
997 F# Compiler Unable to implement interfaces with generic methods
1570 F# Compiler New testcase for "CustomAttributes on Module" failing
1392 F# Compiler Space should not be required between : and >
1437 F# Compiler Assembly attribute w/array parameter fails to build
1497 F# Compiler Quotations 'bindCtor' issue (WebTools & F# 1.3.9.14)
1622 F# Compiler Cannot use "null" in Attributes
1258 F# Compiler Consider design for parser and typechecker that doesn't require exceptions
1050 F# Compiler dot notation on datatype constructors is not resolved
1094 F# Compiler implement internal/public access control escape checks
1160 F# Compiler object should be evaluated eagerly when using a method as a first class function
1304 F# Compiler Explicit program entry point
1500 F# Compiler support conditional compilation (e.g. DEBUG, CODE_ANALYSIS)
1541 F# Compiler finally clause in seq is called out of order, before yield
1590 F# Compiler printf formats should reveal enough information to allow a reasonable implementation of using them in active patterns to scan strings
1644 F# Compiler Generated .fsi is wrong for optional (?-style) parameters
791 F# Compiler OverloadID attributes not in generated .fsi files
1552 F# Compiler Internal error: badly formed Item_ctor_group.
1332 F# Compiler ReflectedDefinition returning null should be allowed
1542 F# Compiler Repeated type argument not being inferred: type Graph <'a> = HashMultiMap<'a,'a>
959 F# Compiler TOp_asm in pattern match
1254 F# Compiler Spurious casts being inserted for upcast operations
1379 F# Compiler Property setter notation be used with mutable .NET fields and mutable record fields
1754 F# Compiler Indexer access should use overloading and not warn on generic constraint
721 F# Compiler suggested undentation from Robert pickering
1398 F# Compiler indentation rule is too strict
1458 F# Compiler Using anonymous type variable in attribute should either not be allowed or should do the right thing
1762 F# Compiler Method name resolution should consult intrinsic methods first
1764 F# Compiler Apply ADJACENT_PREFIX_MINUS rules to '+' as well.
1765 F# Compiler members being printed in reverse alphabetical order in signatures
1766 F# Compiler Treat all the funky operator names like '.[]<-' as single tokens.
1767 F# Compiler Desugaring of computation expressions should make use of operator overloading
1768 F# Compiler Allow the definition of immutable structs using the implicit construction syntax
1526 F# Compiler Possible Regression in FSforScientists sample
1165 F# Compiler Support return attributes?
1660 F# Compiler testcase failure: fsharp\core\verify
1608 F# Compiler Testcase failure: MutateStructFieldOnPropertySet
1112 F# Compiler Bug in definition of generic interface
1625 F# Compiler fsc generates assemblies that don't load/peverify
1683 F# Compiler dispatch slot checking in object expression manages to match non-virtual member
1730 F# Compiler F# allows Enums over string type (Does not PEVerify)
1743 F# Compiler incorrect resolution of overrides
1748 F# Compiler Internal Error: when calling a base member
1749 F# Compiler Interfaces should not allow implicit construction pattern. Bad codegen.
1431 F# Compiler 'end' token ambiguity for interface/class: Incorrect and unactionable error messages when defining class which just implements an interface
1148 F# Compiler class that only implements interface is parsed/recognised as interface (#light)
1275 F# Compiler signature matching is comparing declared interfaces not interface sets
1553 F# Compiler Checks associated with internal and private modules are not yet fully implemented.
1802 F# Compiler Give error messages a "default" number to ensure consistent error message format
1803 F# Compiler Field fails to hide property in parent
732 F# Compiler private modules still appearing in VS object browser
1797 F# Compiler large error range when solving constraint
942 F# Compiler mutable variable escapes its scope when used with an event handler
1505 F# Compiler Need to generate 'GetHashCode' on eception types
1707 F# Compiler MaxInt+1 numeric literals should error
1530 F# Compiler Attributes on properties should not also be put on getter and setter
1077 F# Compiler closing brace following generic type bracket is syntax error without whitespace (lexed into symbolic token).
1831 F# Compiler Finally block called twice for nested sequence comprehensions
1854 F# Compiler TestCase Failure: Peverify error in Adcenter Adpredictor sample
1763 F# Compiler Resolution to extension members should look through the entire hierarchy of a type
1363 F# Compiler Need to apply DefaultMemberAttribute to enable C# to consume F# Indexers
313 F# Tools fsyacc --ml-compatibility: Does not open the Parsing module
1425 F# Library check structural equality on non-zero based multi-dimensional arrays
932 F# Library Fix NaN equality on structured terms and make structural equality go through object.Equals
1059 F# Library "=" doesn't work with 2D array values
1311 F# Library NullReferenceException in StructuredFormat.Display.leafFormatter
1384 F# Library Suggestion: allow explicit exception type definitions to override members - specifically the Message property
975 F# Library Map Exceptions: when a key is not in a map, we get an index out of range exception instead of something like KeyNotFoundException
1572 F# Library support "enum" and "delegate" type decomposition constraints for typesafe generic code over enums and delegates (e.g. conversions and event creation)
1591 F# Library Bug in Async.Generate reported by David M Peixotto [dmp@rice.edu]
1598 F# Library Problem with Array.fold1_left
1571 F# Library Allow "int" and "char" functions to convert to/from int/char
1740 F# Library problem with Lazy.SynchronizedForce()
1760 F# Library Implement Unchecked.defaultof<_> (delete LanguagePrimitives.DefaultValueUnchecked)
1761 F# Library Implement IComparable and Equals on Math.Complex
1374 F# Library compelx number pretty printing broken
1776 F# Library async implementation hits tail recursion problems on 64-bit
1796 F# Library ThreadAbort is causing PostSync to raise exception
1800 F# Library implement decimal literals, "decimal" conversion function
1801 F# Library implement 'sign' and 'round' overloaded functions in library
1804 F# Library sprintf "%A" formats should print decimal literals in "g" format rather than any specific floating point format
1731 F# Library Need a way to cast primitive types to/from enums
1108 F# Library Langauge Specifiation Issue: Enumerations don't convert to int32, uint32 etc.
1861 F# Library lock function can be used on integers
1791 F# Perf Apply fold_left performance improvements to research branch (for Morgan Stanley)
1819 F# Testing Test error in tmptest.mli
1467 F# Language AbstractClass attribute
1599 F# Language Dispose not called in 'use _ = foo()'
1248 F# Language symmetric overloading
339 F# Language Support generic recursion
1558 F# Language Should offside rule be applied to last clause of match?
1633 F# Language Compiler override of Equals should not throw exceptions, per .NET coding guidelines.
1638 F# Language When functions are use/passed as values, we should not insist on optional values.
755 F# Language support marshalling parameter and return attributes
1395 F# Language parsing of minus (-)
641 F# Language Deprecate (type ty) syntax
1614 F# Language Should classes, unions, exceptions, records etc have a way to _not_ be marked with Serializable?
1535 F# Visual Studio Tooltip for List.combine claims "List.combine is a synonym for List.combine"
1651 F# Visual Studio Public constructors of non-visible types are showing up in top-level completion list
1652 F# Visual Studio Namespaces with no visible members at a given program point should not be included in completion list
Comments
Anonymous
May 02, 2008
We're very glad to announce the release of F# 1.9.4 , the Spring Refresh of F#, uploaded to the MicrosoftAnonymous
May 04, 2008
Une nouvelle version de F# est disponible sur le site de Microsoft Research . Pour les détails de cetteAnonymous
May 04, 2008
mau ikutan numpang nampang di disain baru geeks ah.. hi..hi..hi kali ini sambil ikutan kasih kabar bagiAnonymous
October 12, 2009
using the console enter the following code: > let rec fact n = if n=0 then 1 else n * fact n-1;; (do not sandwich n-1 in side the parans). if you hit the enter key you will get a confirmation like so: val fact : int -> int now try something like: > fact 6;; it bams out with a stack overflow exception. it looks like n * fact n-1 is interperted as (n * fact n)-1. hence the stack over flow. for consistency the parans following the function name must be made mandatory. so fact n should not be allowed. thanks Nasser