| 20 Nov 2023 |
@johannes.kirschbauer:scs.ems.host | let
partialFoo = {
nested = {
foo = Number:
};
}
in
partialFoo & {
nested.foo = 1;
}
You can even use that value as type contract in any other place. e.g. if you want to say that bar is also of type foo.
{
bar = partialFoo & {
nested.foo = 2;
}
}
I kind of like the simplicity.
| 10:14:15 |
@johannes.kirschbauer:scs.ems.host | * let
partialFoo = {
nested = {
foo = Number:
};
}
in
partialFoo & {
nested.foo = 1;
}
You can even use that value as type contract in any other place. e.g. if you want to say that bar is also of type foo.
{
bar = partialFoo & {
nested.foo = 2;
}
}
I kind of like the simplicity.
| 10:14:51 |
@johannes.kirschbauer:scs.ems.host | * let
partialFoo = {
nested = {
foo = Number:
};
};
in
partialFoo & {
nested.foo = 1;
}
You can even use that value as type contract in any other place. e.g. if you want to say that bar is also of type foo.
{
bar = partialFoo & {
nested.foo = 2;
}
}
I kind of like the simplicity.
| 10:15:03 |
@johannes.kirschbauer:scs.ems.host | Hm nickel is still different i think. | 10:21:05 |
| 21 Nov 2023 |
| Eelco changed their display name from niksnut to Eelco. | 16:36:55 |
| 24 Nov 2023 |
@yannham:matrix.org | FWIW, In Nickel, currently you can't merge a contract and a number directlylike Number & 1 (maybe it would make sense to do that, but at least for now, we don't). However, because record contracts are no different from normal records (they are just more likely to have mostly annotations and yet-to-be-defined values), there is in theory two ways to "apply" a record contract. One is by setting the contract using =, as in Johannes Kirschbauer @hsjobeki 's example above:
let Contract = { foo | Number } in
{
inner = Contract
} & {
inner.foo = 1
}
Merge will be applied recursively and combine {bar = 1} with {bar | Number} and end up checking that 1 is a Number. However, usually what you want is to use an annotation/metadata (|) instead:
{
inner | Contract
} & {
inner.foo = 1
}
The difference is that the second form is more restrictive: it says "attach a contract Contract to inner". Attaching a contract propagates through merging, even if you override. That is, it means inner can never be changed or updated by merging to something that doesn't respect the initial contract. In particular, the contract is closed by default, meaning you can't add new values (for that, you have to add an ..), while solely merging records propagate the subcontracts but you can always merge with new stuff. Attaching a contract is thus more similar to the CUE model, it "refines" a value with a constraint, and merging just refines more and more.
For example:
nickel> { inner = Contract } & { inner.foo = 1} & {inner.bar = "hello"}
{ inner = { bar = "hello", foo | Number = 1, }, }
# turning the `=` into `|` makes it stricter
nickel> { inner | Contract } & { inner.foo = 1} & {inner.bar = "hello"}
error: contract broken by the value of `inner`: extra field `bar`
[...]
# With `=`, we can override the whole contract
nickel> { inner = Contract } & { inner | force = "something totally different"}
{ inner | force = "something totally different", }
# `|` doesn't let you do that
nickel> {inner | Contract} & { inner | force = "something totally different"}
error: contract broken by the value of `inner`
[...]
| 09:27:24 |
@yannham:matrix.org | * FWIW, In Nickel, currently you can't merge a contract and a number directlylike Number & 1 (maybe it would make sense to do that, but at least for now, we don't). However, because record contracts are no different from normal records (they are just more likely to have mostly annotations and yet-to-be-defined values), there is in theory two ways to "apply" a record contract. One is by setting the contract using =, as in Johannes Kirschbauer @hsjobeki 's example above:
let Contract = { foo | Number } in
{
inner = Contract
} & {
inner.foo = 1
}
Merge will be applied recursively and combine {foo = 1} with {foo | Number} and end up checking that 1 is a Number. However, usually what you want is to use an annotation/metadata (|) instead:
{
inner | Contract
} & {
inner.foo = 1
}
The difference is that the second form is more restrictive: it says "attach a contract Contract to inner". Attaching a contract propagates through merging, even if you override. That is, it means inner can never be changed or updated by merging to something that doesn't respect the initial contract. In particular, the contract is closed by default, meaning you can't add new values (for that, you have to add an ..), while solely merging records propagate the subcontracts but you can always merge with new stuff. Attaching a contract is thus more similar to the CUE model, it "refines" a value with a constraint, and merging just refines more and more.
For example:
nickel> { inner = Contract } & { inner.foo = 1} & {inner.bar = "hello"}
{ inner = { bar = "hello", foo | Number = 1, }, }
# turning the `=` into `|` makes it stricter
nickel> { inner | Contract } & { inner.foo = 1} & {inner.bar = "hello"}
error: contract broken by the value of `inner`: extra field `bar`
[...]
# With `=`, we can override the whole contract
nickel> { inner = Contract } & { inner | force = "something totally different"}
{ inner | force = "something totally different", }
# `|` doesn't let you do that
nickel> {inner | Contract} & { inner | force = "something totally different"}
error: contract broken by the value of `inner`
[...]
| 09:30:53 |
@yannham:matrix.org | The contracts-as-normal-values is also nice to build up new contracts using usual operations, including merging itself. For example, you can write let Combined = Derivation & OtherSpecificContract & {has_some_other_specific_field | String}. It gives you a simple form of "inheritance" (the proper term would be mixins, I think) | 09:39:38 |
@yannham:matrix.org | * FWIW, In Nickel, currently you can't merge a contract and a number directlylike Number & 1 (maybe it would make sense to do that, but at least for now, we don't). However, because record contracts are no different from normal records (they are just more likely to have mostly annotations and yet-to-be-defined values), there are in theory two ways to "apply" a record contract. One is by setting the contract using =, as in Johannes Kirschbauer @hsjobeki 's example above:
let Contract = { foo | Number } in
{
inner = Contract
} & {
inner.foo = 1
}
Merge will be applied recursively and combine {foo = 1} with {foo | Number} and end up checking that 1 is a Number. However, usually what you want is to use an annotation/metadata (|) instead:
{
inner | Contract
} & {
inner.foo = 1
}
The difference is that the second form is more restrictive: it says "attach a contract Contract to inner". Attaching a contract propagates through merging, even if you override. That is, it means inner can never be changed or updated by merging to something that doesn't respect the initial contract. In particular, the contract is closed by default, meaning you can't add new values (for that, you have to add an ..), while solely merging records propagate the subcontracts but you can always merge with new stuff. Attaching a contract is thus more similar to the CUE model, it "refines" a value with a constraint, and merging just refines more and more.
For example:
nickel> { inner = Contract } & { inner.foo = 1} & {inner.bar = "hello"}
{ inner = { bar = "hello", foo | Number = 1, }, }
# turning the `=` into `|` makes it stricter
nickel> { inner | Contract } & { inner.foo = 1} & {inner.bar = "hello"}
error: contract broken by the value of `inner`: extra field `bar`
[...]
# With `=`, we can override the whole contract
nickel> { inner = Contract } & { inner | force = "something totally different"}
{ inner | force = "something totally different", }
# `|` doesn't let you do that
nickel> {inner | Contract} & { inner | force = "something totally different"}
error: contract broken by the value of `inner`
[...]
| 09:52:04 |
| 28 Nov 2023 |
infinisil | @room: The next ~monthly meeting will take place in 1 hour! There's not a lot to discuss from my side, please don't hesitate to add topics you'd like to talk about to the meeting notes agenda. Meeting link | 13:04:15 |
nbp | Here is the reason why I think a module system (not only "the" module system) is not suited for the top-level for Nixpkgs, as opposed to using it for the configuration of packages.
A module system is about squashing additional non-conflicting changes and makes an exception for ordering with mkOrder, where as the override logic is all about ordering when changes are applied, when packages / package-set are copied under a different name and mutated separately it in a different way and replace the logic that previously existed.
To make it work, one would have to add extra semantic, such as the order of modules, to inject a default ordering / priorities into a module system used in the context of Nixpkgs. Thus, the modules would no longer be position independent.
| 13:32:42 |
profpatsch | they are? | 13:51:30 |
profpatsch | As far as I understand, the module list order determines the merging order | 13:51:43 |
profpatsch | like, for example, if you have a list that merges its element via append, the order of module imports will determine which elements are first in the resulting list | 13:56:57 |
infinisil | Robert Hensing (roberth): tomberek: Growpotkin: John Ericson: DavHau: phaer: Meeting time: https://meet.jit.si/nixpkgs-architecture | 14:01:53 |
problems | https://github.com/nixpkgs-architecture/issues/issues/24 | 15:08:34 |
nbp | Profpatsch: Well given that the order is left unspecified such that each module can import in which ever order, the serialized DAG is unknown to the end user. | 18:23:11 |
nbp | Within a module, you have no idea which of the import came before, nor which will come after, without having a global knowledge. | 18:23:56 |
nbp | Whereas with override, you are supposed to master this fact to be in control of the desired output. | 18:24:37 |
John Ericson | Oh shit sorry was afk on vacation and asleep then | 19:24:44 |
infinisil | phaer: Did all the removal steps, thanks for joining the team, even just for a brief period! | 21:32:31 |
| 29 Nov 2023 |
profpatsch | nbp: you are right of course | 09:11:39 |
profpatsch | I don’t think the module system is a good fit for nixpkgs either, if just because of the slowness | 09:11:55 |
| 1 Dec 2023 |
| b65be joined the room. | 19:41:52 |
| 4 Dec 2023 |
| Philip Taron (UTC-8) joined the room. | 20:56:47 |
| 5 Dec 2023 |
| @federicodschonborn:matrix.org changed their profile picture. | 00:38:06 |
| @quantenzitrone:matrix.org changed their display name from qz to quazi [ˈkvaːzi]. | 19:14:19 |
| 6 Dec 2023 |
infinisil | Making some progress with RFC 140: https://github.com/NixOS/nixpkgs/pull/272395 (still a draft, not ready for review, but the description gives the story) | 02:38:00 |
Philip Taron (UTC-8) | infinisil: I love pkgs/by-name and I write Rust at work. I'd be glad to be code reviewer when you' | 05:01:31 |
Philip Taron (UTC-8) | * infinisil: I love pkgs/by-name and I write Rust at work. I'd be glad to be code reviewer when you're ready. | 05:01:35 |