Full Release Notes for F# 1.9.2.7

Here are the full release notes for F# 1.9.2.7.

Slicing syntax

The following syntax forms

     expr := ...

          | e1.[range1]

          | e1.[range1,range2]

 

    range := e2..e3

           | ..e3

           | e2..

           | *

represent slicing from a 1D or 2D data structures that supports associative lookup on ordered keys. In practice these forms can be used with

  • Strings
  • Arrays
  • 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

For example:

     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.
     m1.[1,*]

    m1.[*,1]

 

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

 

i.e.
     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.

Named Arguments 

Calls to members (but not let-bound functions or function values) may use named arguments. For example

 
     System.Console.WriteLine(format="Hello {0}",arg0="World")
     System.Console.WriteLine("Hello {0}",arg0="World")
     System.Console.WriteLine(arg0="World",format="Hello {0}") 
 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:
    System.Console.WriteLine(arg0="World","Hello {0}")

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

Optional Arguments

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.

For example:

     T.OneNormalTwoOptional(3)
     T.OneNormalTwoOptional(3,2)
     T.OneNormalTwoOptional(arg1=3)
     T.OneNormalTwoOptional(arg1=3,arg2=1)
     T.OneNormalTwoOptional(arg2=3,arg1=0)
     T.OneNormalTwoOptional(arg2=3,arg1=0,arg3=11)
     T.OneNormalTwoOptional(0,3,11)
     T.OneNormalTwoOptional(0,3,arg3=11)
     T.OneNormalTwoOptional(arg1=3,?arg2=Some(1))
     T.OneNormalTwoOptional(arg2=3,arg1=0,arg3=11)
     T.OneNormalTwoOptional(?arg2=Some(3),arg1=0,arg3=11)
     T.OneNormalTwoOptional(0,3,?arg3=Some(11))
  

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

    > x.GetHashCode();;

    val it : int = 5

 

    > let x2 = box (1,2);;

   val x2 : obj

    > x2.GetHashCode();;

    val it : int = 5

    > x2.Equals(x);;

    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__.  

Library additions

  • Added Microsoft.FSharp.Plot.* interactive plotting previews.
  • Added Microsoft.FSharp.Collections.Permutation.
  • 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.

Bugs fixed:

  •     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