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

varargs forwarding doesn't work properly when the target proc has default params #9996

Open
zah opened this issue Dec 15, 2018 · 4 comments
Open

Comments

@zah
Copy link
Member

zah commented Dec 15, 2018

The following valid code fails to compile at the moment:

type
  SomeObject = object

proc procWithDefaults(o: SomeObject, x = 1, y = true) =
  echo x, " ", y

template myTemplate(T: type, args: varargs[untyped]) =
  var obj: T
  obj.procWithDefaults(args)

myTemplate(SomeObject, 2)
myTemplate(SomeObject, 3, true)
myTemplate(SomeObject, y = false)
myTemplate(SomeObject, x = 3)
myTemplate(SomeObject, y = false, x = 4)
myTemplate(SomeObject) # <--- Error here
Hint: template_varargs [Processing]
template_varargs.nim(16, 11) template/generic instantiation from here
template_varargs.nim(9, 6) Error: type mismatch: got <SomeObject, varargs[untyped]>
but expected one of: 
proc procWithDefaults(o: SomeObject; x = 1; y = true)
  first type mismatch at position: 2
  required type: int
  but expression '' is of type: varargs[untyped]

expression: procWithDefaults(obj119089, )

The problem is that the empty forwarded varargs are not recognized as a valid way to call the proc procWithDefaults even though all the required non-default parameters have been supplied.

The problem can be worked-around using the following trick:

template myTemplate(T: type, args: varargs[untyped]) =
  var obj: T
  when compiles(args[0]):
    obj.procWithDefaults()
  else:
    obj.procWithDefaults(args)

Another work-around that should probably work, but currently doesn't is the following:

template myTemplate(T: type, args: varargs[untyped]) =
  var obj: T
  when len(args) == 0: # len(args) doesn't compile
    obj.procWithDefaults()
  else:
    obj.procWithDefaults(args)
@krux02
Copy link
Contributor

krux02 commented Jul 17, 2019

Currently varargs has some self conflicting rules in its implementation that I can't see to be fixed in the very near future. I recommend to use openArray until varargs has been fixed properly.

@zah
Copy link
Member Author

zah commented Jul 17, 2019

The use case here is heterogeneous varargs and perfect argument forwarding (creating abstractions that rewrite function calls entirely at compile-time).

@timotheecour
Copy link
Member

timotheecour commented May 24, 2020

@zah it works with varagsLen I introduced some time ago

  template myTemplate(T: type, args: varargs[untyped]) =
    var obj: T
    when varargsLen(args) == 0:
      obj.procWithDefaults()
    else:
      obj.procWithDefaults(args)

@zah
Copy link
Member Author

zah commented May 24, 2020

I've switched to an in-house version of unpackArgs:
https://github.com/status-im/nim-stew/blob/master/stew/shims/macros.nim#L361-L370

The main difference with the stdlib version is that it allows you to mix the varargs with additional arguments inserted in the call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants