Skip to content

Commit 3e27f3c

Browse files
update details on version declaration and backward compatibility
as discussed with @​roberth and @​piegamesde Co-authored-by: Yorick van Pelt <[email protected]>
1 parent a461ef9 commit 3e27f3c

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

rfcs/0137-nix-language-version.md

+51-3
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ Other discussions around language changes:
133133

134134
1. The language version for Nix expressions is denoted in special syntax, at the beginning of a parse unit.
135135
A parse unit is any text stream, e.g. a file or string.
136+
The evaluator must ignore a shebang line (starting with `#!) at the start of files, to leave room for additional tooling.
137+
138+
The language version declaration is optional if it is instead made in an external per-project file.
139+
The details of the per-project file syntax are out of scope for this proposal.
136140

137141
<details><summary>Arguments</summary>
138142

@@ -144,6 +148,7 @@ Other discussions around language changes:
144148
- This has the same trade-offs as when introducing the new syntax to begin with
145149
- (-) Editor support is made harder, since it requires switching the language based on file contents
146150
- (+) Making the language version accessible at all will probably outweigh the costs
151+
- (+) Using a per-project file avoids littering every file with version declarations.
147152

148153
</details>
149154

@@ -228,7 +233,6 @@ Other discussions around language changes:
228233
version \d*.\d*;
229234
```
230235

231-
The evaluator must ignore a shebang line (starting with `#!) at the start of files, to leave room for additional tooling.
232236
This implies that if no language version is specified in a Nix file, it is written in version 6 (the version implemented in the stable release of Nix at the time of writing this RFC).
233237

234238
The syntax is open for bikeshedding.
@@ -285,6 +289,10 @@ Other discussions around language changes:
285289

286290
Examples include semantic changes or removal of `builtins`, operators, or syntactic constructs.
287291

292+
Values are decidedly not covered by versioning, but must instead stay the same indefinitely.
293+
In particular, there must not be, e.g., string values internally tagged with different language versions.
294+
This constraint can be loosened with a follow-up RFC.
295+
288296
<details><summary>Arguments</summary>
289297

290298
- (+) The principled solution: guarantees reproducibility given a fixed language version
@@ -317,11 +325,20 @@ Other discussions around language changes:
317325
</details>
318326

319327
1. Semantics are preserved across file boundaries for past language versions.
328+
In other words, code written in an old language version evaluates to the same result when used from the new versions for all input values which are legal on the old version.
320329

321-
This should be fairly straightforward to implement since values passed around in the evaluator carry all the information needed to force them.
330+
This should be fairly straightforward to implement since values passed around in the evaluator can carry all the information needed to force them.
322331
Newer parts of the evaluator can always wrap their values in interfaces that are accepted by older parts, as far as possible.
323332

324-
Example: [Best-effort interoperability](#best-effort-interoperability)
333+
Examples:
334+
- [Best-effort interoperability](#best-effort-interoperability)
335+
- [Preserving semantics across version boundaries](#preserving-semantics-across-version-boundaries)
336+
337+
When new value types are added to the language:
338+
339+
- Passing new values to functions is allowed, as it cannot be prevented anyways due to laziness and composite types (like lists).
340+
- Any values of unknown type to code from an older Nix version are treated as the opaque "external" type (which already exists for things like plugins).
341+
Attempts at using them other than passing them around will thus cause type errors.
325342

326343
<details><summary>Arguments</summary>
327344

@@ -344,6 +361,14 @@ Other discussions around language changes:
344361

345362
</details>
346363

364+
1. The backward compatibility mechanism must be "zero cost" when not used, meaning that no performance overhead must be paid when no legacy Nix files are imported.
365+
366+
<details><summary>Arguments</summary>
367+
368+
- (+) This additional implementation constraint encourages being conservative with substantial changes.
369+
370+
</details>
371+
347372
1. It is not possible to import expressions written in newer versions.
348373

349374
Example: [Expressions are not forward compatible](#expressions-are-not-forward-compatible)
@@ -545,6 +570,29 @@ $ nix-instantiate --eval b.nix
545570
2
546571
```
547572

573+
### Preserving semantics across version boundaries
574+
575+
```nix
576+
# a.nix
577+
version 6.1;
578+
{ float };
579+
toString float
580+
```
581+
582+
```nix
583+
# b.nix
584+
version 7.0;
585+
{
586+
old = import ./a.nix 1.1;
587+
new = toString 1.1;
588+
}
589+
```
590+
591+
```console
592+
$ nix-instantiate --eval b.nix --strict
593+
{ old = "1.100000"; new = "1.1"; }
594+
```
595+
548596
### Pathological example
549597

550598
Usually existing code will be interacted with by calling functions.

0 commit comments

Comments
 (0)