I’ve been trying to do something which, when reduced, looks a little like this:
def lazyCount(is: (=> Int)*): Int =
is.length
Aside from crashing the compiler when CC is enabled , this does not compile:
By-name parameter type => Int not allowed here.
def lazyCount(is: (=> Int)*): Int =
^^^^^^
I wonder if there’s a particular reason for that, especially given that we can relatively easily get the same feature with context functions:
trait Dummy
object Dummy:
given Dummy {}
def lazyCount(is: (Dummy ?=> Int)*): Int =
is.length
This compiles and exhibits the expected behaviour (well, expected by me at least):
// Only used to show that none of the arguments to lazyCount are evaluated.
def log(i: Int) =
println(s"Creating $i")
i
println(lazyCount(log(1), log(2), log(3)))
// 3
Your use case is mentioned here:
opened 03:51PM - 24 Apr 15 UTC
closed 02:52PM - 03 May 15 UTC
stat:fix available
itype:language enhancement
## Motivation
Scala so far does not allow by-name repeated parameters. But I ca… n'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.
I’m reminded by the old ticket
opened 06:10PM - 10 May 12 UTC
closed 11:33PM - 13 Apr 20 UTC
language spec
enhancement
fixed in Scala 3
This is edge-use-case, but:
```scala
scala> def m(a:Int,bs: =>Int*) = 7
<conso… le>:1: error: ')' expected but identifier found.
def m(a:Int,bs: =>Int*) = 7
^
scala> def n(is: (=>Int)*) = 7
<console>:1: error: no by-name parameter type allowed here
def n(is: (=>Int)*) = 7
^
scala> def q(is: =>(Int *)) = 5 // not my intention
<console>:1: error: no * parameter type allowed here
def q(is: =>(Int *)) = 5
```
Am I the only one who experiences a cognitive hiccup every time I have to disambiguate "named parameter" and "by-name parameter?" Internally (to myself), I've started calling (denoting) params that have call-by-name semantics "eval params" because of the loose notion that they are evaluated on reference. ("Deferred params" conveys the idea that evaluation is deferred, but people get confused about deferred to when, especially under partial application, and deferred doesn't suggest multiple evaluation. I hope Paul reads this and has a better word for it -- besides "evil params", of course.)
I haven't thought closely about this, except my terminology hangup, but the Seq[=>T] view might be a reason to ignore the use case.
that it was SIP-24 which FSR wound up in SIP limbo.
main ← add-epeated-byname
opened 07:22AM - 09 Jun 22 UTC
This pull request has been automatically created to import proposals from scala/… docs.scala-lang
3 Likes
EDIT: sorry didnt realize you wanted a sequence of lazy values, as opposed to a lazy sequence…
Going by martin’s comments, this seems to work fine for me if I remove the parens in the def site arg type annotation. That crash also disappears.
def method(a: => A*): Unit = ()
class A:
println("initialized A") // <- never gets called
method(A(), A())
println("asdf")
1 Like
I think this works because you’re ignoring a entirely. If you update your code so that method interacts with it, you’ll see that you will get things printed: Scastie - An interactive playground for Scala.
Which, to me, says that a: => A* is a by-name list of A, not a list of by-name As, although I might very well be wrong.
As the song says, “You may be wrong, but you may be right.”
1 Like