~technomancy/fennel#77: 
provide &pack destructuring for function arglists and multi-value destructuring

It would be very nice to have a way to quickly store the ... part in functions, and the rest of multiple value return into a packed table like this:

(fn foo [x y &pack zs] zs)
(foo :a :b :c :d :e) ;=> {1 "c" 2 "d" 3 "e" :n 3}

Such function can expand to the following code:

(fn foo [x y ...]
  (let [zs (doto [...] (tset :n (select "#" ...)))]
    zs)

Multivalue destructuring can also benefit from this:

(fn bar [] (values :a :b :c :d))
(let [(a b &pack cs) (bar)]
  cs) ;=> {1 "c" 2 "d" :n 2}

Though this is a bit trickier to pull off, as it reqires storing multivalues somewhere in the first place, as we can't introduce a multivalue literal outside of the function's arglist. But it can be done if a function is generated:

local function bar() return "a", "b", "c", "d" end
local a, b, cs = (function (a, b, ...) return a, b, {n = select("#", ...), ...} end)(bar())
Status
RESOLVED WONT_FIX
Submitter
~andreyorst
Assigned to
No-one
Submitted
2 years ago
Updated
2 months ago
Labels
No labels applied.

~jaawerth 2 years ago

Rather than adding an entire new inline form, couldn't we just try to get & in arglists to work the same way they do when destructuring a table? It's effectively rest parameters as a sequence anyway, and that should lower cognitive debt. Plus, people are already used to rest params coming at the end, which this will also require.

(fn cut2 [a b & zs] zs)
(cut2 1 2 3 4 5) ; => [3 4 5]

~andreyorst 1 year, 6 months ago

nils will not be handled properly

~jaawerth 1 year, 6 months ago

Is that a response to me or a general statement? If the former, I'm not suggesting a different implementation, just arguing against adding another unique form for it. Currently, (fn [a b & xs] <stuff>) isn't valid fennel syntax, as the & is an error (it used to just bind the symbol &) outside of a destructured table. I'm just suggesting that this can be done just as easily in the top-level argslist without calling it &pack.

Basically, even if it emits different code under the hood based on context, it would make more sense to use the same syntax to achieve the same thing, at leas when you can do it without any ambiguity, which I think is the case here.

~andreyorst 1 year, 6 months ago

I'm not suggesting a different implementation, just arguing against adding another unique form for it. Currently, (fn [a b & xs] <stuff>) isn't validas the & is an error (it used to just bind the symbol &) outside of a destructured table. I'm just suggesting that this can be done just as easily in the top-level argslist without calling it &pack.

Oh, I see, sorry, for some reason I thought you meant that it would produce ordinary [] sequential table.

Basically, even if it emits different code under the hood based on context, it would make more sense to use the same syntax to achieve the same thing, at leas when you can do it without any ambiguity, which I think is the case here.

Yeah I agree. However this would mean that this special has to be implemented for () too

-- Andrey Listopadov

~technomancy REPORTED WONT_FIX 2 months ago

I don't think this is worth the overhead; if you want to know the number of args, you can call (select :# ...) yourself. Including it implicitly in the compiler output adds overhead unintuitively. We have been working hard to remove IIFEs from the compiler, and adding a new one to the multivals packing that doesn't look like it should IIFE would be counter-productive.

Register here or Log in to comment, or comment via email.