Giter Site home page Giter Site logo

Comments (13)

Gabriella439 avatar Gabriella439 commented on September 27, 2024

Originally I intended to extend the operator to behave the way you ask (i.e. if there is a conflict between two fields that are not both records then prefer the right field).

The problem is when you have expressions like this:

λ(x : Text)  λ(y : {})  { foo = x }  { bar = y }

What would you expect that to normalize to?

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

Oops, I meant to say:

λ(x : Text)  λ(y : {})  { foo = x }  { foo = y }

from dhall-lang.

AlexeyRaga avatar AlexeyRaga commented on September 27, 2024

In this case I would expect { foo = {} } as a result.
My reasoning would be intuitive and "imperative":

  1. foo is set to x.
  2. combine happens and we check conflicting fields: "if both fields are records then combine them, otherwise RHS wins". Since foo is set to x: Text now, combine prefers RHS value.

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

The issue with that is that it would require interleaving type-checking with normalization which would significantly complicate the semantics. We would need to know that x has type Text and y has type {} in order to know that they conflict and y takes precedence. Also, in general I try to avoid users having to reason at the type level in order to infer what is happening at the term level.

Another issue with a recursive override operator is that it is no longer associative. For example:

x = { foo = { bar = 1 } }

y = { foo = "ABC" }

z = { foo = { baz = 2 } }


(x ∧ y) ∧ z = { foo = { baz = 2 } }

x ∧ (y ∧ z) = { foo = { baz = 1, baz = 2 } }

from dhall-lang.

AlexeyRaga avatar AlexeyRaga commented on September 27, 2024

Hm, OK, I thought it would be just a check whether both fields are records are not, which would need to be done anyway to determine whether to go deeper.

I am fine with non-associativity here. But I understand why it is a concern and this is why I am not asking to change the existing behaviour but rather to introduce another variation of combine.

It would allow pretty common use case for dealing with "big" APIs and configuration, like dealing Singularity where asking users to specify every single property of these types is impractical.

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

The reason you require type inference is because some fields might be bound variables, so you can't tell if the bound variable is a record or not without knowing its type

I also think the lack of associativity is an important reason why I wouldn't want to introduce this operator (even as a new operator). One of the design principles of Dhall is that all operators should be associative

Also, note that you can still update a nested record without specifying every field. In the worst case you can use the operator once per nesting level, like this:

    let example = { foo = { bar = { baz = 1 } } }

in  example ⫽ { foo = example.foo ⫽ { bar = example.foo.bar ⫽ { baz = 2 } } }

It's not ideal, but it at least doesn't require specifying the other fields at each nesting level

from dhall-lang.

AlexeyRaga avatar AlexeyRaga commented on September 27, 2024

Yeah, I think I'll have to go this way then, will see how it goes.
Thanks for the explanation.

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

You're welcome!

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

I will go ahead and close this, but feel free to reopen if there is more to do here.

from dhall-lang.

domenkozar avatar domenkozar commented on September 27, 2024

I'd just like to add that I always wanted the requested behavior in Nix and I'm sad to see dhall doesn't do it right, even though I understand it goes outside of desired design space.

A quite common configuration pattern is default values. One file has the defaults, the other overrides them for example like ./defaults.dhall /\ { ... }

Currently one can use // if the configuration is nested using Gabriel's trick, but can't use /\ as defaults can't be used.

Having a good story for defaults is important for introducing new fields to the configuration as the application using them gets new settings through it's lifetime.

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

@domenkozar: My main issue with the requested behavior is that it requires interleaving type-checking and normalization. Not only does this complicate the standard but it also complicates the user's mental model since they can't reason about how behaves without performing type inference in their head.

However, even if we were to accept that tradeoff, it still wouldn't completely solve the problem. For example, consider the case where you have a configuration of type:

{ foo : Optional Text, bar : List { baz : Optional Text } }

The wouldn't be able to recurse into the record inside the List of the bar field.

For a non-contrived example of this, see the menucolors.*.attributes field of the dhall-nethack configuration:

https://github.com/dhall-lang/dhall-nethack/blob/a99c2f7d5b4612d008393819602490047d328e99/examples/validated.dhall#L118-L119

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

Reopening this as we've been discussing adding a with keyword for deep overrides here: #754 (comment)

from dhall-lang.

Gabriella439 avatar Gabriella439 commented on September 27, 2024

The fix for this is up here: #923

from dhall-lang.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.