Skip to content

Allow by-name repeated parameters #499

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

Closed
odersky opened this issue Apr 24, 2015 · 12 comments
Closed

Allow by-name repeated parameters #499

odersky opened this issue Apr 24, 2015 · 12 comments

Comments

@odersky
Copy link
Contributor

odersky commented Apr 24, 2015

Motivation

Scala so far does not allow by-name repeated parameters. But I can't see a good reason why this combination should be disallowed. Also, the combination is necessary to allow vararg parameters that are passed as expressions to inline methods (instead of being lifted out).

Syntax

The syntax for ParamType becomes

  ParamType         ::=  [`=>'] ParamValueType
  ParamValueType    ::=  Type [`*']              

The syntax implies that a type such as => T*, which is both by-name and repeated is interpreted as => (T*), that is, as a by-name type of a repeated type.

Translation Rules

If a parameter has a by-name repeated type => T* it matches an arbitrary number of actual arguments of type T. As usual for by-name parameters, the arguments are not evaluated at the point of call. Instead, all arguments are evaluated each time the parameter is referenced in the called method.

The same holds for an vararg argument of the form e: _*. The argument expression e is evaluated each time the parameter is referenced in the called method.

odersky added a commit to dotty-staging/dotty that referenced this issue Apr 24, 2015
@odersky odersky mentioned this issue Apr 24, 2015
@DarkDimius
Copy link
Contributor

Instead, all arguments are evaluated each time the parameter is referenced in the called method.

So => T* means Function0[Seq[T]].
Is there an intention to allow (=> T)* which would mean Seq[Function0[T]]?

@odersky
Copy link
Contributor Author

odersky commented Apr 24, 2015

@DarkDimius No intention to provide both.

@nafg
Copy link

nafg commented Apr 24, 2015

@DarkDimius what's the benefit of the latter?

@DarkDimius
Copy link
Contributor

In some cases, you could be interested in knowing number of arguments without forcing the actual arguments.
Lets say you want to implement a function, that prints progress of evaluating its arguments.
Ie given a call

exec(expr1, expr2, expr3, expr4)

you want to see output

[timestamp] 4 commands scheduled for execution
[timestamp] Running command 1 out of 4
[timestamp] Running command 2 out of 4
[timestamp] Running command 3 out of 4
[timestamp] Running command 4 out of 4
[timestamp] Done

I do not have a strong opinion on (=> T)*, as it does not play well with e: _*. Presence of both forms could also be a source of confusion.

@odersky
Copy link
Contributor Author

odersky commented Apr 24, 2015

I think it would be oonfusing. Also, we'd have to the somehow say that mentioning a by-name
parameter in a function does sometimes not force the expression to be evaluated. Looks messy.

@nafg
Copy link

nafg commented Apr 24, 2015

@DarkDimius could you just do something like:

implicit class ByNameWrapper[A](a: =>A) { def theA = a }

def exec[A](as: ByNameWrapper[A]*)

@nafg
Copy link

nafg commented Apr 24, 2015

Seems to work (in 2.11.6): http://scastie.org/9184

@DarkDimius
Copy link
Contributor

@nafg indeed. No reason to treat it specially than.

@retronym
Copy link
Member

Would these avoid evaluating the arguments?

def foo(a: => Any*) = ()
def bar(a: => Any*) = foo(a : _*)
def baz(a: => Seq[Any]) = foo(a : _*)
bar(???, ???)
baz(Seq(???, ???))

@odersky
Copy link
Contributor Author

odersky commented Apr 26, 2015

None of them should evaluate the arguments.

DarkDimius added a commit to dotty-staging/dotty that referenced this issue Apr 30, 2015
@odersky odersky closed this as completed May 3, 2015
@nafg
Copy link

nafg commented Dec 8, 2016 via email

@SethTisue
Copy link
Member

Naftoli's implicit class workaround works in Scala 2, but it does not work in Scala 3: https://scastie.scala-lang.org/yJ14pr86TMOxM59smJSGLg

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

5 participants