Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document macros.unpackVarargs #18106

Merged
merged 3 commits into from
May 31, 2021

Conversation

timotheecour
Copy link
Member

@timotheecour timotheecour commented May 26, 2021

refs #18101 (comment)
closes #18101

(unless a reviewer can point to a use case, I think this is ready for deprecation) see discussion below, in particular #18106 (comment)

@timotheecour timotheecour added the Ready For Review (please take another look): ready for next review round label May 26, 2021
@kaushalmodi
Copy link
Contributor

/cc @bung87 @beef331

@bung87
Copy link
Collaborator

bung87 commented May 27, 2021

unpackVarargs is a utils function in macros module in Nim, but in other language , it's in language implementation.
for example you will use funcA(...arguments) when you get args in funcB in javascript, I dont use unpackVarargs directly but use same technic here https://github.com/bung87/db_adapter/blob/e3b0ef0b6aa71d217c63733681a79ec4a6e31b32/src/db_adapter.nim#L198
so I think it can be deprecated but should be a example in macros module's document.

@timotheecour
Copy link
Member Author

this doesn't answer the question: is there any single use case for it? see previous discussion in #18101 (comment) + tests in this PR, it seems that

unpackVarargs(bar1, a) is just same as bar1(a)

@bung87
Copy link
Collaborator

bung87 commented May 27, 2021

this doesn't answer the question: is there any single use case for it? see previous discussion in #18101 (comment) + tests in this PR, it seems that

unpackVarargs(bar1, a) is just same as bar1(a)

your example does not fit the situation , the real use case you dont get a, instead you get args, in my unpackMethodVarargs I dont even have bar1

@timotheecour
Copy link
Member Author

your example does not fit the situation , the real use case you dont get a, instead you get args, in my unpackMethodVarargs I dont even have bar1

can you show a working example illustrating the point of unpackMethodVarargs ?

@bung87
Copy link
Collaborator

bung87 commented May 27, 2021

@timotheecour
Copy link
Member Author

timotheecour commented May 27, 2021

I already put the link:

that doesn't use unpackVarargs and it's not a minimized working example illustrating it, and I can't nimble build your project either. If it's so hard to illustrate how it works with a working example, maybe it's a sign it's not so useful?

example adapted from
bung87/db_adapter@e3b0ef0/src/db_adapter.nim#L198

  import std/macros
  template `.`*(fun: typed; x: untyped, args: varargs[untyped]): untyped =
    # unpackVarargs(fun, args)
    fun(args) # same results

  template call(fun: typed; args: varargs[untyped]): untyped =
    # unpackVarargs(fun, args)
    fun(args) # same results

  proc fn1(a, b, c: int) = echo (a, b, c)
  proc fn2(a, b: string) = echo (a, b)

  call(fn1, 1, 2, 3)
  call(fn2, "a", "b")

  fn1.zook(2,3,4)
  fn2.zook("a", "b")

=> same results with or without using unpackVarargs

note

after investigating, the only case where it makes a difference is with with an empty varargs, at least that answers the question of in which case it makes a difference.

But note that you can use varargsLen for that (since #12907):

when true:
  import std/macros
  template call(fun: typed; args: varargs[untyped]): untyped =
    # unpackVarargs(fun, args)
    # fun(args) # works except for last case with empty `args`
    when varargsLen(args) > 0: fun(args)
    else: fun()

  proc fn1(a = 0, b = 1, c = 2) = echo (a, b, c)

  call(fn1, 10, 11, 12)
  call(fn1, 10, 11)
  call(fn1, 10)
  call(fn1) # requires either unpackVarargs or the above impl with `varargsLen`

unpackVarargs(fun, args) is arguably simpler to use for end users than this:

when varargsLen(args) > 0: fun(args)
else: fun()

so the next question is whether we can simply fix the compiler so that fun(args) can just work in the edge case of varargsLen(args) == 0.

@bung87
Copy link
Collaborator

bung87 commented May 27, 2021

the use case you need unpackVarargs

import std/macros
{.experimental: "dotOperators".}
macro `.`*(fun: untyped; x: untyped, args: varargs[untyped]): untyped =
  quote do:
    unpackVarargs(`fun`, `args`)
  #fun(args) # same results

macro call(fun: untyped; args: varargs[untyped]): untyped =
  quote do:
    unpackVarargs(`fun`, `args`)
  #fun(args) # same results

proc fn1(a, b, c: int) = echo (a, b, c)
proc fn2(a, b: string) = echo (a, b)

call(fn1, 1, 2, 3)
call(fn2, "a", "b")

fn1.zook(2,3,4)
fn2.zook("a", "b")

@timotheecour
Copy link
Member Author

timotheecour commented May 27, 2021

the use case you need unpackVarargs

your example is not convincing for the same reason i explained above: `fun`(`args`) works just as well as unpackVarargs(`fun`, `args`)`

again, as shown in #18106 (comment), it turns out the only case where it makes a difference is when the varargs can be empty (which wasn't illustrated in your example).

I'll update this PR later explain those findings and the varargsLen alternative as a runnableExamples, and if/when compiler gets fixed so that fun(args) works with the edge case of varargsLen(args) == 0, then at that point unpackVarargs can be deprecated

EDIT: done, I've updated PR

related: #9996, #14436, #8833, #8706 (last one was closed)

@timotheecour timotheecour removed the Ready For Review (please take another look): ready for next review round label May 27, 2021
@timotheecour timotheecour marked this pull request as draft May 27, 2021 05:30
@timotheecour timotheecour force-pushed the pr_deprecate_unpackVarargs branch from 44842ed to 2f53355 Compare May 27, 2021 18:40
@timotheecour timotheecour marked this pull request as ready for review May 27, 2021 18:40
@timotheecour timotheecour changed the title deprecate macros.unpackVarargs document macros.unpackVarargs May 27, 2021
@timotheecour timotheecour added the Ready For Review (please take another look): ready for next review round label May 27, 2021
@Araq
Copy link
Member

Araq commented May 30, 2021

Er, how do you write this without unpackVarargs?

import macros

template myecho(x: varargs[typed]) =
  unpackVarargs(echo, x)

myecho(1, 2, 3)

@timotheecour timotheecour force-pushed the pr_deprecate_unpackVarargs branch from 2f53355 to 5598e88 Compare May 31, 2021 03:03
@timotheecour timotheecour force-pushed the pr_deprecate_unpackVarargs branch from 5598e88 to 0ed1d86 Compare May 31, 2021 03:03
@timotheecour
Copy link
Member Author

timotheecour commented May 31, 2021

PTAL

Er, how do you write this without unpackVarargs?

it would work without unpackVarargs when forwarding varargs[untyped], but indeed, unpackVarargs is needed when forwarding varsgs[T] for some typed T to a routine accepting varargs[someTyped]; I've updated the PR doc comment + examples

@Araq Araq merged commit 18b4774 into nim-lang:devel May 31, 2021
@timotheecour timotheecour deleted the pr_deprecate_unpackVarargs branch May 31, 2021 18:49
@kaushalmodi
Copy link
Contributor

@timotheecour Here's an example usecase of unpackVarargs:

import std/[times, macros]

template timeIt*(theFunc: proc, passedArgs: varargs[typed]): float =
  let t = cpuTime()
  echo unpackVarargs(theFunc, passedArgs)
  cpuTime() - t

proc add2(arg1, arg2: int): int =
  result = arg1 + arg2

proc add3(arg1, arg2, arg3: float): float =
  result = arg1 + arg2 + arg3
  
echo timeIt(add2, 15, 5)
echo timeIt(add3, 15.5, 123.12, 10.009)

https://play.nim-lang.org/#ix=3rwD

@timotheecour
Copy link
Member Author

that is not very convincing because this works just as well:

template timeIt*(theFunc: proc, passedArgs: varargs[untyped]): float =
  let t = cpuTime()
  echo theFunc(passedArgs)
  cpuTime() - t

or even simpler/more general:

template timeIt2*(call: typed): float =
  let t = cpuTime()
  echo call
  cpuTime() - t

echo timeIt2(add2(15, 5))
echo timeIt2(add3(15.5, 123.12, 10.009))

@kaushalmodi
Copy link
Contributor

that is not very convincing because this works just as well:

template timeIt*(theFunc: proc, passedArgs: varargs[untyped]): float =
  let t = cpuTime()
  echo theFunc(passedArgs)
  cpuTime() - t

👍 Wow, I didn't know varargs[untyped] can be used this way.

PMunch pushed a commit to PMunch/Nim that referenced this pull request Mar 28, 2022
* deprecate macros.unpackVarargs

* un-deprecate unpackVarargs and add docs+runnableExamples

* update examples + tests with varargs[typed]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ready For Review (please take another look): ready for next review round
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants