Open yannham opened 2 years ago
As discussed during last nickel meeting, keeping the Nix syntax ({ inherit var, ...}
) is probably better.
@yannham also proposed to have a more intuitive syntax for inherit(record) var
which is inherit var from record
.
I agree with this proposal, but also feel it less a requirement for nickel than the simple form inherit var
which as said above, is the only way to write something meaning let a = something in {a = a}
in nickel because of records recursivity.
PureScript, JavaScript, et.al. would let you use the variable as a label such that { foo }
≍ { foo = foo }
(though I think inherit
ideas offer more flexibility)
@toastal, the end of the original post covers this case and explains why this wouldn't be optimal.
We have a notion of fields without a definition, and in general something that could be described as "partial configurations". Currently, {foo}
is already a valid value, which is a record with a field foo
that doesn't have yet a definition (which can be seen as a contract as well, which simply requires the existence of a field foo
). While the {foo} ~ {foo = foo}
is a natural and reasonable approach in other programming languages, that wouldn't work as well in Nickel, unfortunately.
Yeah, it is indeed very unfortunate that undefined field notation is the same as punning could be. It would be very natural even for people comming from js, where you can write: const some_field = 7; const an_object = { some_field }
and it is very handy... That's petty this opportunity has been lost (for making Nickel familiar for mainstream, in this case).
On the other side I think it would be good to avoid inherit
keyword, it is of course sensible (especially comming from nix, but not ony), but:
I have a bunch of ideas:
let foo = 7 in { <- foo }
trying to allude to traditional assignment from pseudocode (or R, Haskell)let foo = 7 in { *foo }
here is a pointer association or rather YAML aliases (and anchors)let foo = 7 in { put foo }
let foo = 7 in { use foo }
let foo = 7 in { add foo}
What do you think? @yannham? I do not know if those examles are not in collision with other syntax of Nickel, didn't analyse it, are they?
I personally prefer keyword-based solutions, because they don't assume that the reader of Nickel code is familiar with C-like languages, with JavaScript, with functional programming or whatnot. Although it does have a cost: it's more verbose, and it sometimes prevents said keywords from being used as an identifier (which is backward incompatible). That being said, in this case, because the syntax of field names is very restricted, it's probably never ambiguous (that is, reserving a keyword like use
or add
in this position doesn't prevent from using it as an identifier elsewhere, because it never clashes).
I'm not too worried about the size of inherit
, but the unnecessary association with OOP is a good point. add
is confusing, because it makes you think of number addition. put
is short and nice, but has an "imperative" feeling IMHO - like we are mutating something, which we aren't. use
is a good one; we just have to be careful if one day we want to also have something like Nix with
- but more principled, as described in this blog post - because use
would be a good candidate for that as well, and I'm not sure the two would coincide.
Naming is hard :upside_down_face: we can also add include
to the possibilities
Is OOP still as pervasive as it was in the ’90s & ’00s?
Yep, I agree with your conclusions about add
and use
keyword. Also put
gives false intuition with mutations, but in this case I would treat it as "put
this to the object which is under construction right now" not "put
something to object already created", so, I would still consider it as good option. include
sounds very good, so probably it is better than inherit
(although same size).
Also insert
could be considered, one letter less, but again it gives intuition related to mutations.
So I think include
is a winner.
Is OOP still as pervasive as it was in the ’90s & ’00s?
@toastal yep, sure :)
Inherit
Nix has an
inherit
keyword that is used to define a field with the same name and value as a a variable in scope:This kind of syntactic sugar is also present in other languages (Haskell, Rust, OCaml, etc.) sometimes under the name record /field punning.
Nix
inherit
also supports multiple fields, and the specification of another record to take the fields from:Recursive records in Nickel
While this is a nice shorthand,
inherit
is at most a nicety. However, in Nickel, records are recursive by default. This means that the expanded version above will just cause an infinite loop:This make defining fields with the same name and content as an identifier in scope a pain: one either has to change the variable from the beginning:
But sometimes that is not desirable. Variables can be defined far away, and can be used in a lot of other places where it makes sense to keep the original name. The only solution left is to bind those variables to new ones locally, but this must be done before the definition of the record:
Another case that I encountered in practice is when you need to recursively refer to a field defined in a parent record, but with the same name. There, you can't rename the original identifier either:
This starts to be really painful. Because records are recursive by default, I think having field punning is even more important for Nickel than for other languages.
Describe the solution you'd like
Have a syntactic construct, which can be
inherit
or something else, to define fields with the same name and value as a list of identifiers in scope.Note that the common punning syntax for several languages (Rust, OCaml, etc.) is to just write a field without a definition. For example in OCaml:
Or in Rust:
But this solution doesn't cope well with the general syntax of Nickel.
a lone field named
foo,
is taken to be a field without definitions, and this is consistent with other notations. Beside being a breaking change, I don't think that would be intuitive to change this syntax to meaninherit foo
.