jsonnet icon indicating copy to clipboard operation
jsonnet copied to clipboard

shorthand for deep field overrides

Open benley opened this issue 9 years ago • 7 comments


local foo = {
  a: { b: { c: { d: 1234 } } },
  e: 1
};

foo + { a.b.c.d: 999 } 

It would be really cool if the above (or something along those lines) worked and evaluated to:

{
  a: { b: { c: { d: 999 } } },
  e: 1
}

To achieve the same in today's jsonnet you would have to write:

local foo = {
  a: { b: { c: { d: 1234 } } },
  e: 1
};

foo + { a+: { b+: { c+: { d: 9999} }

I don't know how difficult and/or sane this would be to implement, but there is a similar construct in Nix that is quite useful :)

benley avatar Aug 15 '16 20:08 benley

Yeah this has come up a few times. I agree it would be nice.

You need a way to be able to compute the fields too, perhaps like this:

foo + { ["a"].["b"].["c"].["d"]: e } 

presumably self in each of those expressions bind the same way it would if there were syntax sugar, although there are no explicit { } there to guide the eye.

Then there's the question of avoiding duplicates:

{ ["a"].["b"]: e, ["a"].["c"]: e }  // OK 
{ ["a"].["b"]: e, ["a"].["b"]: e }  // Not OK 

sparkprime avatar Aug 16 '16 01:08 sparkprime

Perhaps it is OK to force the user to collect the c and b modification into a single mixin there?

sparkprime avatar Aug 16 '16 01:08 sparkprime

Here's the design I came up with after some thinking and trying to figure C++ and parsers.

Shorthand-dot operator suggestion

Currently, the parseObjectRemainder() will look for tokens BRACKET_L, IDENTIFIER, STRING_DOUBLE, STRING_SINGLE or STRING_BLOCK and will parse the following tokens as [+]:{1,3} construct.

I suggest to extend the case of IDENTIFIER initially to allow DOT to follow it. In that case, the remainder is parsed recursively as either IDENTIFIER+DOT pairs, or the usual [+]:{1,3}.

This makes the following:

{
    a.b.c: 1,
}

equal to

{
    a+: {
        b+: {
            c+: 1
        }
    }
}

which is, supposedly, one of the most used cases. The duplicates resolution must be updated to consider duplicates only of the leaves of DOT-chains, otherwise {a.b.c=1, a.b.d=2} would fail.

Version 2

To cover additional cases, STRING_DOUBLE, STRING_SINGLE or STRING_BLOCK should be allowed in the syntax (I don't think STRING_BLOCK would actually be any useful, but there's no good reason to exclude it).

Version 3

Allow indexing expressions of single elements of paths via [ expr ], e.g. { a.b[0].c: 1}. This would be primarily useful to override in-array values.

Note that I ignore the computational part of the dot-paths on purpose. The whole idea for them is to allow quick overrides in deep-nested objects (those are very common in kubernetes definitions) to make them more human-readable.

farcaller avatar Jul 04 '17 15:07 farcaller

I think you mean:

{
    a.b.c: 1,
}

is equal to

{
    a+: {
        b+: {
            c: 1
        }
    }
}

whereas

{
    a.b.c+: 1,
}

is equal to

{
    a+: {
        b+: {
            c+: 1
        }
    }
}

For the duplicates resolution, I suppose you could just say that:

{
    a.b.c: 1,
    a.b.d: 1,
}

Must be expressed as:

{
    a.b+: {
        c: 1,
        d: 1,
    }
}

I.e., so there are no additional smarts needed in that code.

sparkprime avatar Jul 05 '17 20:07 sparkprime

Then there's the question of avoiding duplicates:

{ ["a"].["b"]: e, ["a"].["c"]: e }  // OK 
{ ["a"].["b"]: e, ["a"].["b"]: e }  // Not OK 

I think this is fine to leave this feature as syntax sugar, and don't introduce any special runtime handling:

{ a.b.c[a].z: 1, a.b.c[a].x: 1 }
# =>
{
  a+: {
    b+: {
      c+: {
        [a]+: {
          z: 1,
        },
        [a]+: {
          x: 1,
        },
      },
    },
  },
}

Nix does it same way:

error: dynamic attribute 'test' already defined at (string):1:38
            1| let a = "test"; in builtins.toJSON({ a.b.c.${a}.z = 1; a.b.c.${a}.x = 1; })

CertainLach avatar Nov 28 '21 19:11 CertainLach

Has this feature been implemented?

jacksongoode avatar Dec 22 '22 03:12 jacksongoode