Here are the full release notes for F# 18.104.22.168.
The following syntax forms
expr := …
range := e2..e3
represent slicing from a 1D or 2D data structures that supports associative lookup on ordered keys. In practice these forms can be used with
- Any types supporting an appropriate GetSlice method, including F# vector and matrix types.
- In a future release ordered-key collection types such as Map and System.Collections.Generic.SortedDictionary may also support these operators
let s1 = “abcdef”
s1.[*] = s1
s1.[0..] = s1
s1.[1..] = “bcdef”
s1.[2..] = “cdef”
s1.[5..] = “f”
s1.[6..] = “”
let m1 = matrix [ [ 1.0; 2.0; 3.0; 4.0; 5.0; 6.0 ];
[ 10.0;20.0;30.0;40.0;50.0;60.0 ] ]
m1.[*,*] = m1
m1.[0..,*] = matrix [ [ 1.0; 2.0; 3.0; 4.0; 5.0; 6.0 ];
[ 10.0;20.0;30.0;40.0;50.0;60.0 ] ]
m1.[1..,*] = matrix [ [ 10.0;20.0;30.0;40.0;50.0;60.0 ] ]
m1.[*,1..] = matrix [ [ 2.0; 3.0; 4.0; 5.0; 6.0 ];
[ 20.0;30.0;40.0;50.0;60.0 ] ])
The primary restriction is that the syntax can’t yet be used to extract a vector from a matrix, e.g.
are not yet valid syntactic forms. These would have to map to different operators.
Technically speaking, the above represent calls to the Microsoft.FSharp.Core.Operators operators
val (.[..]) : ^src -> ‘idx option -> ‘idx option -> ^res
val (.[..,..]) : ^src -> ‘idx1 option -> ‘idx1 option -> ‘idx2 option -> ‘idx2 option -> ^res
e1.[e2..e3] == (.[..]) e1 (Some e2) (Some e3)
e1.[e2..] == (.[..]) e1 (Some e2) None
e1.[..e3] == (.[..]) e1 None (Some e3)
The implementation of (.[..]) requires:
- A GetSlice method on e1 with signature:
member GetSlice : ‘idx option * ‘idx option -> ‘res
An Item property on the return type of the GetSlice function:
member Item : ‘idx -> ‘elem with get
Similar conditions are used for the 2D lookup operator.
Calls to members (but not let-bound functions or function values) may use named arguments. For example
Named arguments may not be used with the curried arguments of a member (only the initial set of “tupled” arguments).
Named arguments must appear after all other arguments, so the following is not allowed:
The names of members may be listed in signature types and on the types used for abstract members, e.g.
static member ThreeArgs : arg1:int * arg2:int * arg3:int -> int
abstract TwoArgs : arg1:int * arg2:int -> int
Members (but not let-bound functions) may have optional arguments. These must come at the end of the argument list, though this is not currently checked. An optional argument is marked with a ? before its name. Inside the member the argument has type option<argType>. On the callside the argument typically appears to have type argType, though there is a way to pass a value of type option<argType> if necessary (see below).
let defaultArg x y = match x with None -> y | Some v -> v
type T() =
static member OneNormalTwoOptional (arg1, ?arg2, ?arg3) =
let arg2 = defaultArg arg2 3
let arg3 = defaultArg arg3 10
arg1 + arg2 + arg3
static member TwoOptional (?arg1, ?arg2) =
let arg1 = defaultArg arg1 3
let arg2 = defaultArg arg2 10
arg1 + arg2
In a signature optional arguments appear as follows:
static member OneNormalTwoOptional : arg1:int * ?arg2:int * ?arg3:int -> int
static member TwoOptional : ?arg1:int * ?arg2:int -> int
Callers may specify optional arguments either:
- by name, e.g. arg2=1.
- by propagating an existing optional value by name, e.g. ?arg2=None or ?arg2=Some(3) or ?arg2=arg2. This can be useful when building one method that passes numerous optional arguments on to another.
- by using normal, unnamed arguments matched by position.
Optional arguments can’t be used in member constraints. They can be used in interface and abstract members. The compiled representation
of optional arguments is fragile, in the sense that the addition of further optional arguments to a member signature will result in a
compiled form that is not binary compatible with the previous compiled form.
Hashing and equality on F# values
Recall that F# automatically implements comparison and hash semantics for tuple, record and discriminated union types
(only). Now F# will also implement Object.GetHashCode and Object.Equals for these types. For example:
> let x = box (1,2);;
val x : obj
val it : int = 5
> let x2 = box (1,2);;
val it : int = 5
val it : bool = true
This means System.Collections.Generic.Dictionary etc. will now be usable with tuple, record or discriminated
union keys with the expected semantics without supplying a custom comparer. This eliminates a common source of confusing
and possible unexpected behaviour.
Other Language enhancements
Added “workflow” syntax updates. More details to follow.
Added [1..2] without spaces.
Added [< assembly : attributeExpr >] for assembly level attributes.
Added pattern matching on 64-bit numbers.
Added extension members (examples in F# library files control.fsi and control.fs).
Added datatype constructors used as first class functions.
Made begin/end optional for modules.
Made class/interface/struct-end optional in for type definitions.
Made with/end optional for type-augmentations.
Added __SOURCE_FILE__ and __LINE__.
Added Microsoft.FSharp.Plot.* interactive plotting previews.
Added CodeDom provider.
Added typeof<ty>, sizeof<ty> as functions.
Adding ASP.NET samples.
Library minor changes
Additions to Seq module, e.g. orderBy, groupBy, countBy and sumByInt.
Additions to IEvent module, e.g. merge/split.
Additions to Quotations, added ReflectedTopDefn.
Added HashSet.Create for sequences.
Deprecated Idioms functions now available by other means.
Removed FlagsAttribute restriction on enum bit twiddling.
Deleted obsoleted CompatArray functions.
977 Fix: resx files compiled without change to cwd.
Fix: FSI reflection emit support for constrained callvirt opcodes.
Fix: Hashtbl copying bug.
Fix: nested module/type loading bug.
Fix: performance improvements to BigNat and BigInt