Unpacking Argument Lists (* operator)

1,018 views
Skip to first unread message

David Rees

unread,
Apr 20, 2019, 2:58:40 PM4/20/19
to Jsonnet
Is there a way to unpack a list into an argument lists to a function using the * (splat) operator like in Python?

So instead of
  selfAlias('a', 'b')
one could do
  selfAlias(*['a', 'b'])

Of course my actual use case is more complicated than that. I have a list of lists that I want to pass to a function based on the first item in each list. The functions take different arguments so I can't just explicitly unpack each list.

Thanks!
dave 

Daniel Pittman

unread,
Apr 29, 2019, 11:56:14 AM4/29/19
to Jsonnet
In my experience real-world examples usually work better than hypotheticals.

Anyway, I recently wanted the opposite of this: gather an arbitrary number of arguments into an array, for processing.  Use case was a DSL for gmailctl; one of the examples from my configuration, plus my work-around for it:

local _from(values) = std.map(function(item) {from: item}, values);
local from(a, b=null, c=null, d=null, e=null) = _from(std.prune([a, b, c, d, e]);

This supports this expansion:

std.assertEqual(
  {rules: [ from('f...@example.com'), from('f...@example.com', 'b...@example.com')]}
  {rules: [{from: 'f...@example.com'}, [{from: f...@example.com}, {from: 'b...@example.com'}]]}
);

This is more interesting in the definition of logical operators for the DSL: `and`, `or`, and helpers like `mailing_lists(...)` which do significantly more complicated processing between the input and output.

An example of a fuller DSL rule, and the generated structure – which is a mess of nested objects – can be for a small amount of input data follows, to demonstrate why I prefer building this sort of convenience DSL.  Sadly, text of matches had to be censored, but is irrelevant to the interesting part, the structure nesting of `object=>object=>array=>object` for defining a rule.

kill(and(subject('AAAAA'), has('BBBBB'), or(has('CCCCC'), has('DDDDD'))))


{
  "actions": {
    "delete": true,
    "markImportant": false,
    "markRead": false
  },
  "filter": {
    "and": [
      {
        "subject": "AAAAA"
      },
      {
        "has": "BBBBB"
      },
      {
        "or": [
          {
            "has": "CCCCC"
          },
          {
            "has": "DDDDD"
          }
        ]
      }
    ]
  }
}

Stanisław Barzowski

unread,
May 18, 2019, 11:54:22 AM5/18/19
to Jsonnet
I agree with Daniel that it could be really nice to have variable length argument lists. I really missed this feature when playing with parser combinators in Jsonnet - it resulted in a lot of noise from double parens like `seq([a, b, seq([c, d])])`. And I think variable length functions shouldn't be a problem in general. Splat is a bit more controversial since then it's unclear from looking at the code how many arguments are passed (which is not a deal-breaker, but a serious disadvantage IMO).

Dave Cunningham

unread,
May 18, 2019, 5:48:53 PM5/18/19
to Stanisław Barzowski, Jsonnet
It'd b nice to support either exactly the same as python * and **, or something a bit simpler but equivalent, e.g.

f(x, y, z, ...) with the ability to somehow access keyword args and regular args from the ... when you're inside the function.  But then I don't know how you would call a function if you had an array / dict or both. Maybe it's not possible to do better than Python here? :)



--
You received this message because you are subscribed to the Google Groups "Jsonnet" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jsonnet+u...@googlegroups.com.
To post to this group, send email to jso...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jsonnet/c88387c5-96dc-42e8-a88c-082fed8017f3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Angus Lees

unread,
May 20, 2019, 3:35:57 AM5/20/19
to Dave Cunningham, Stanisław Barzowski, Jsonnet
Fwiw I think the minimum functionality here (which is not quite the same as splat) is something like "std.apply(f, args)".

Currently we can use arrays for functions with variable numbers of arguments (with the downside that you get double-parens, as mentioned earlier), and this at least works.  I don't think we have any meta-programming alternative currently to be able to *call* a function with a runtime-determined number of arguments.

 - Gus

On Sun, 19 May 2019 at 07:48, 'Dave Cunningham' via Jsonnet <jso...@googlegroups.com> wrote:
It'd b nice to support either exactly the same as python * and **, or something a bit simpler but equivalent, e.g.

f(x, y, z, ...) with the ability to somehow access keyword args and regular args from the ... when you're inside the function.  But then I don't know how you would call a function if you had an array / dict or both. Maybe it's not possible to do better than Python here? :)



On Sat, May 18, 2019 at 4:54 PM Stanisław Barzowski <stanislaw...@gmail.com> wrote:
I agree with Daniel that it could be really nice to have variable length argument lists. I really missed this feature when playing with parser combinators in Jsonnet - it resulted in a lot of noise from double parens like `seq([a, b, seq([c, d])])`. And I think variable length functions shouldn't be a problem in general. Splat is a bit more controversial since then it's unclear from looking at the code how many arguments are passed (which is not a deal-breaker, but a serious disadvantage IMO).


On Monday, 29 April 2019 17:56:14 UTC+2, Daniel Pittman wrote:
On Saturday, April 20, 2019 at 2:58:40 PM UTC-4, David Rees wrote:
Is there a way to unpack a list into an argument lists to a function using the * (splat) operator like in Python?

So instead of
  selfAlias('a', 'b')
one could do
  selfAlias(*['a', 'b'])

Of course my actual use case is more complicated than that. I have a list of lists that I want to pass to a function based on the first item in each list. The functions take different arguments so I can't just explicitly unpack each list.

In my experience real-world examples usually work better than hypotheticals.

Anyway, I recently wanted the opposite of this: gather an arbitrary number of arguments into an array, for processing.  Use case was a DSL for gmailctl; one of the examples from my configuration, plus my work-around for it:

local _from(values) = std.map(function(item) {from: item}, values);
local from(a, b=null, c=null, d=null, e=null) = _from(std.prune([a, b, c, d, e]);

This supports this expansion:

std.assertEqual(

For more options, visit https://groups.google.com/d/optout.


--
 - Gus
Reply all
Reply to author
Forward
0 new messages