Skip to content

Sona v0.3

Pre-release
Pre-release

Choose a tag to compare

@IS4Code IS4Code released this 05 Oct 17:33
· 149 commits to master since this release

This is a pre-release version of the language. Until version 1.0, any aspects of the language may change with no guarantees towards backward compatibility.

To embed the compiler as a service in your project, please use NuGet. You may also install the compiler as a .NET tool.

Patterns

  • Fully usable in let, var, switch, for, try, if, and function parameters.
  • Support for:
    • Custom pattern calls (let Color(r, g, b) = Color.Red).
    • Tuple, array, and record members matching (with syntax analogous to expressions; { x = x, y, z } shorthand for { x = x, y = y, z = z }).
    • Option patterns (some x, none).
    • Conjunction and disjunction (and, or; conjunction propagates type/null information).
    • Null tests (null, not null/!null).
    • Narrowing type tests (is (i as int), is<int> i, is<int>).
    • Member tests (with { Size = 0 }).
    • Relational patterns (> 0 etc., can replace = after field names, e.g. { Size > 0 }).
    • Regular expressions (/sona is (?{what}\w+)/i, extracting the capture to the what pattern). The Regex instance is fully cached and reusable.

Declarations

  • Packages ‒ group related code via package Name … end.
  • Case functions ‒ functions that can be called from within patterns:
    • Declared as case function Something(x), case function (One or Other)(x) or case function Maybe?(x).
    • Can be referenced in expressions with a similar syntax, just without the function and parameters (case Package.Something etc.).
  • Optional return ‒ function f?() permits return both with and without an argument, returning an option.
  • Functions can have inline parameters, requiring inlineable functions.
  • Variable declarations can now contain multiple bindings (let a = 1, b = 2 etc.).
  • lazy variables ‒ stored in a static class, initialized the first time they are used (lazy a = printfn "Written when retrieved").

Statements

  • The try…catch/case…finally statement (try … catch … do … case … do … finally … end). catch is the same as case is, i.e. permits a narrowing conversion to the type asserted by the pattern.
  • The if let construction that optionally matches a value and enters the block only on successful match (if let valueNonZero and != 0 = value then …). Also usable inline in expressions.

Directives

Expressions

  • The unit operator (for unit of measurement conversion) is now required to be followed by <…>, to prevent grammar conflicts with unit (the value of the unit type).
  • unit can also be written as unit() to disambiguate it in other contexts.
  • The not/! operators now support other boolean-like types.
  • ++, --, and (!) = followed by any combination of <, >, = were reserved.

Compilation

  • Several diagnostics have improved messages.
  • "Less generic than indicated" warnings are not displayed if resulting from a wildcard type.

Fixes

  • Explicit return type (via as) in function expressions works properly.
  • Improved dependency loading to fix issues locating FSharp.Compiler.Service.resources.dll.
  • Fixed NullReferenceException when forming diagnostics involving pragmas and other whitespace tokens.
  • Interpolated strings can be properly used in custom attributes.
  • Qualified attribute names now work properly.
  • A single _ is not treated as a valid identifier in code generation.

Full Changelog: v0.2...v0.3

Missing features

  • Custom pattern calls with mixed positional and named arguments could be treated similarly to records (P(a, b = 1) could be interpreted as P(a = a, b = 1)).
  • Case functions with multiple alternatives do not support optional returns (an F# limitation). This could be implemented via a hidden unit alternative, but then it does not really return an option.
  • Array patterns do not support .. for arbitrary-length arrays.
  • Sequence patterns (for IEnumerable) are not supported.
  • throw patterns ‒ let [a, b] or throw = arr could indicate a total pattern that throws if [a, b] cannot be matched.
  • while let.
  • and not null should affect the patterns prior to it, removing the need for !null.
  • An alternative syntax to try…finally via defer could be explored.
  • The disambiguation of unit opens the door to measure-tagged unit values, constructed via unit<M>(). Practical use of such values is limited, but they could be utilized for type inference.
  • not is supported in patterns only in the special pattern not null. This could not be improved without significant reordering of the code.
  • lazy var is doable in theory, but proper usage is prevented by compiler bugs (dotnet/fsharp#18313).
  • The effect of #pragma once should have safety checks that prevent it being unobserved, and should warn if it is in effect too far from the pragma.
  • The code is still compiled as a single package, with no support for namespaces. #pragma forwardref should apply to the whole code (at least when at the top of the file).