Skip to content

v9.0.0

Compare
Choose a tag to compare
@Gabriella439 Gabriella439 released this 25 Jul 01:00
· 405 commits to master since this release
6cbf57c

Breaking changes:

  • Remove old Optional literal syntax

    This is phase 2 of removing support for the old List-like Optional literal
    syntax.

    This phase removes the old Optional literals from the language. You now
    must use Some or None.

    For more details, including migration instructions, see:
    Migration: Deprecation of old Optional literal syntax

  • Forbid surrogate pairs and non-characters

    Dhall no longer supports surrogate pairs within escape sequences. In other
    words, something like this is no longer valid:

    "\uD834\uDD1E"

    ... and you must instead use a braced escape sequence to represent a Unicode
    character that would have previously required a surrogate pair:

    "\u{1D11E}"

    Dhall also no longer supports escape sequences for non-characters, so
    something like this is also no longer valid:

    "\uFFFF"

    Surrogate pairs and non-characters are also now explicitly forbidden within
    the source code (i.e. within comments or unescaped text literals), but these
    were already forbidden before. Dhall source code has to be valid UTF8, which
    already disallows those characters.

  • Add toMap keyword to create homogeneous maps from records

    You can now create an association list (a.k.a. a Map) from a Dhall record if
    all of the values stored within the record have the same type. For
    example:

    toMap { foo = 1, bar = 2 }
    
    = [ { mapKey = "foo", mapValue = 1 }, { mapKey = "bar", mapValue = 2 } ]

    This allows a Dhall binding to a configuration format to accept a list of
    key-value pairs if it doesn't know in advance what keys to expect, while
    still permitting the user to specify the key-value pairs using record-like
    syntax.

    Two other features within this same release take advantage of this:

    • You can now specify custom headers for imports using the record
      generated by toMap, like this:

      https://example.com/foo
        using toMap { Authorization = "token ${env:GITHUB_TOKEN as Text }" }
    • You can specify key-value pairs for the JSON type just added to the
      Prelude using toMap, too:

      let JSON = https://prelude.dhall-lang.org/JSON/package.dhall
      
      in  JSON.object (toMap { foo = JSON.number 1.0, bar = JSON.string "baz" })

    This is a technically breaking change because toMap is now a reserved
    keyword, but in practice most users will not be affected unless they used
    that label before this change.

  • Beta-normalization: Sort the fields of a record projection

    Normalization will now sort the fields of a record projection if it cannot
    be further reduced. For example, this expression:

    λ(x : { a : Bool, b : Bool, c : Bool })  x.{ c, a }

    ... now normalizes to:

    λ(x : { a : Bool, b : Bool, c : Bool })  x.{ a, c }

    This is a technically breaking change because it might perturb the hash of
    any expression that contains an irreducible record projection, but in
    practice this should not affect most users.

New features:

  • Implement importing paths as Location

    Dhall now permits reflection on fully resolved import paths so that these
    paths remain up-to-date no matter where the configuration file is
    interpreted from.

    For example, suppose that you store the following configuration file at
    /home/john/example.dhall:

    { packagePath = "./purescript-simple-json"
    }

    ... where packagePath is intended to point to
    /home/john/purescript-simple-json.

    ... but then you use that to configure a program running with a different
    current working directory, such as: PWD=/home/alice/. That program will
    fail to resolve the package path because /home/alice/purescript-simple-json
    does not exist.

    However, if you change the configuration to:

    { packagePath = ./purescript-simple-json as Location
    }

    Then the interpreter will replace the import with an expression encoding the
    absolute path to the import, generating an expression equivalent to this:

    let Location = https://prelude.dhall-lang.org/Location/Type
    
    in  { packagePath = Location.Local "/home/john/purescript-simple-json" }

    ... so that the Dhall configuration file can be used to configure a program
    running within any working directory.

    If the same file were hosted at https://example.com/john/example.dhall then
    the expression would evaluate to:

    let Location = https://prelude.dhall-lang.org/Location/Type
    
    in  { packagePath = Location.Remote "https://example.com/john/purescript-simple-json" }
  • Allow all RFC3986-compliant URLs

    Now all URLs are valid imports.

    For example, before this change https://example.com was not a valid import
    due to not having any path components and after this change URLs without
    paths are valid.

    This change also enables:

    • URLs with empty path components (i.e. https://example.com///)
    • Path components with unquoted special characters, such as =
  • Generalize empty list annotations

    You can now annotate an empty list with a type synonym, like this:

    let Example = List Natural
    
    in  [] : Example

    Before this change, the List in : List was part of the grammar for empty
    lists, and you could only create a type synonym for the list element type,
    but not the list type as a whole. Now you can create a type synonym for the
    list type.

  • Add Map type and utility functions to Prelude

    The Prelude is now enshrining the Dhall idiom of using
    List { mapKey : Text, mapValue : a } to represent homogeneous maps by
    adding basic types and utilities for working with values of that type.

    This change pairs well with the following matching changes in this release:

  • Use multihash for cache filenames

    Dhall caches imports protected by semantic integrity checks underneath
    ${XDG_CACHE_HOME}/dhall or ~/.cache/dhall and this change affects the
    names of the cache files, which are now preceded with the four characters
    1220 to reflect
    the multi-hash standard.

    This change means that the interpreter will not reuse old cache files when
    upgrading from an older release, so the cache will be rebuilt upon the first
    run of the interpreter. However, this is not a breaking change as this does
    not change the final result interpreting a protection protected by a semantic
    integrity check.

  • Add support for braced escape sequences

    You can now escape Unicode characters using braces, like this:

    "Musical symbol G clef: \u{1D11E}"

    This allows Dhall to escape Unicode characters with code points greater than
    0xFFFF without the use of surrogate pairs. This is necessary given that
    surrogate pair escape sequences are now forbidden within this same release.

  • Prelude: Add standard representation for weakly-typed JSON values

    Utilities like dhall-to-{json,yaml} and {json,yaml}-to-dhall have up until
    now only supported Dhall types with schemas known ahead-of-time. However,
    some configuration file formats support fields that can store arbitrary JSON
    code (such as arbitrary JSON that the configuration intends to "pass through"
    to configure another step).

    This change adds a canonical type to the Prelude for representing an arbitrary
    JSON value and utilities for creating such JSON values. For example:

    let JSON = https://prelude.dhall-lang.org/JSON/package.dhall
    
    in  JSON.object
        ( toMap
          { foo = JSON.null
          , bar = JSON.array [ JSON.number 1.0, JSON.bool True ]
          }
        )

    Also, the matching release of the dhall-json package supports this
    weakly-typed representation anywhere within the schema when converting
    either way between JSON/YAML and Dhall configuration files.

  • Use Prelude/Map for import headers

    You can now use a value of type List { mapValue : Text, mapValue : Text }
    to represent custom headers within an import's using clause instead of
    List { header : Text, value : Text }. For example:

    https://example.com/foo using
      [ { mapKey   = "Authorization"
        , mapValue = "token ${env:GITHUB_TOKEN as Text}"
        }
      ]

    ... or using the new toMap keyword:

    https://example.com/foo using
      toMap { Authorization = "token ${env:GITHUB_TOKEN as Text}" }

    The old header/value form is still supported, so this is not a breaking
    change. However, at some point in the future we may initiate the process of
    deprecating header/value support.

  • Add new Prelude/XML package

    There is now a Prelude/XML package that you can use to represent and
    render a subset of XML values using Dhall. This will eventually be used to
    power a dhall-to-xml utility.

    For example:

    let XML = https://prelude.dhall-lang.org/XML/package.dhall
    
    in  XML.render (XML.leaf { name = "foobar", attributes = XML.emptyAttributes })
    
    = "<foobar/>"

Other changes: