Skip to content

Commit 47da9ea

Browse files
committed
@unroll/@unrollAll
1 parent c3ae803 commit 47da9ea

File tree

1 file changed

+34
-55
lines changed

1 file changed

+34
-55
lines changed

content/unroll-default-arguments.md

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ can be applied to methods `def`s, `class` constructors, or `case class`es to gen
185185
customName: String = null,
186186
customDoc: String = null,
187187
@unroll sorted: Boolean = true,
188-
nameMapper: String => Option[String] = Util.kebabCaseNameMapper
188+
@unroll nameMapper: String => Option[String] = Util.kebabCaseNameMapper
189189
): Either[String, T] = ???
190190
```
191191

@@ -238,7 +238,7 @@ parameter that was added (in this case, `b: Boolean = true`)
238238
import scala.annotation.unroll
239239

240240
object Unrolled{
241-
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l
241+
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l
242242
}
243243
```
244244

@@ -248,10 +248,8 @@ These forwarders do nothing but forward the call to the current implementation,
248248
given default parameter values:
249249

250250
```scala
251-
import scala.annotation.unroll
252-
253251
object Unrolled{
254-
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l
252+
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l
255253

256254
def foo(s: String, n: Int, b: Boolean) = foo(s, n, b, 0)
257255
def foo(s: String, n: Int) = foo(s, n, true, 0)
@@ -262,15 +260,27 @@ As a result, old callers who expect `def foo(String, Int, Boolean)` or `def foo(
262260
can continue to work, even as new parameters are added to `def foo`. The only restriction is that
263261
new parameters can only be added on the right, and they must be provided with a default value.
264262

263+
If multiple default parameters are added at once (e.g. `b` and `l` below) you can also
264+
choose to only `@unroll` the first default parameter of each batch, to avoid generating
265+
unnecessary forwarders:
266+
267+
```scala
268+
object Unrolled{
269+
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l
270+
271+
def foo(s: String, n: Int) = foo(s, n, true, 0)
272+
}
273+
```
274+
265275
If there are multiple parameter lists (e.g. for curried methods or methods taking implicits) only one
266276
parameter list can be unrolled (though it does not need to be the first one). e.g. this works:
267277

268278
```scala
269279
object Unrolled{
270280
def foo(s: String,
271281
n: Int = 1,
272-
@unroll b: Boolean = true,
273-
l: Long = 0)
282+
@unroll b: Boolean = true,
283+
@unroll l: Long = 0)
274284
(implicit blah: Blah) = s + n + b + l
275285
}
276286
```
@@ -282,8 +292,8 @@ object Unrolled{
282292
def foo(blah: Blah)
283293
(s: String,
284294
n: Int = 1,
285-
@unroll b: Boolean = true,
286-
l: Long = 0) = s + n + b + l
295+
@unroll b: Boolean = true,
296+
@unroll l: Long = 0) = s + n + b + l
287297
}
288298
```
289299

@@ -295,19 +305,15 @@ Class constructors and secondary constructors are treated by `@unroll` just like
295305
other method:
296306

297307
```scala
298-
import scala.annotation.unroll
299-
300-
class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0){
308+
class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0){
301309
def foo = s + n + b + l
302310
}
303311
```
304312

305313
Unrolls to:
306314

307315
```scala
308-
import scala.annotation.unroll
309-
310-
class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0){
316+
class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0){
311317
def foo = s + n + b + l
312318

313319
def this(s: String, n: Int, b: Boolean) = this(s, n, b, 0)
@@ -318,12 +324,10 @@ class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0){
318324
### Unrolling `class` secondary constructors
319325

320326
```scala
321-
import scala.annotation.unroll
322-
323327
class Unrolled() {
324328
var foo = ""
325329

326-
def this(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = {
330+
def this(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = {
327331
this()
328332
foo = s + n + b + l
329333
}
@@ -333,12 +337,10 @@ class Unrolled() {
333337
Unrolls to:
334338

335339
```scala
336-
import scala.annotation.unroll
337-
338340
class Unrolled() {
339341
var foo = ""
340342

341-
def this(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = {
343+
def this(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = {
342344
this()
343345
foo = s + n + b + l
344346
}
@@ -357,8 +359,6 @@ generates forwarders for those methods as well, based on the presence of the
357359
`@unroll` annotation in the primary constructor:
358360

359361
```scala
360-
import scala.annotation.unroll
361-
362362
case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){
363363
def foo = s + n + b
364364
}
@@ -367,9 +367,7 @@ case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){
367367
Unrolls to:
368368

369369
```scala
370-
import scala.annotation.unroll
371-
372-
case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0L){
370+
case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0L){
373371
def this(s: String, n: Int) = this(s, n, true, 0L)
374372
def this(s: String, n: Int, b: Boolean) = this(s, n, b, 0L)
375373

@@ -490,7 +488,7 @@ against different versions of each other (hence the varying number of parameters
490488

491489
```scala
492490
class Upstream{ // V2
493-
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l
491+
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, @unroll l: Long = 0) = s + n + b + l
494492
}
495493
```
496494

@@ -624,48 +622,29 @@ using the same implementation and same user-facing semantics.
624622
## Minor Alternatives:
625623

626624

627-
### `@unrollOnly`
625+
### `@unrollAll`
628626

629-
Currently, `@unroll` generates forwarders for every default parameter to the right of the one
630-
annotated. This is not always necessary, e.g. if multiple parameters are added at once, we
631-
should only need a single forwarder for the entire set. This can be supported by requiring
632-
supporting an `@unrollOnly` is provided for every default parameter that needs a forwarder generated. That
633-
would mean generating two forwarders would look like this:
627+
Currently, `@unroll` generates a forwarder only for the annotated default parameter;
628+
if you want to generate multiple forwarders, you need to `@unroll` each one. In the
629+
vast majority of scenarios, we want to unroll every default parameters we add, and in
630+
many cases default parameters are added one at a time. In this case, an `@unrollAll`
631+
annotation may be useful, a shorthand for applying `@unroll` to the annotated default
632+
parameter and every parameter to the right of it:
634633

635634
```scala
636635
object Unrolled{
637-
def foo(s: String, n: Int = 1, @unrollOnly b: Boolean = true, @unrollOnly l: Long = 0) = s + n + b + l
636+
def foo(s: String, n: Int = 1, @unrollAll b: Boolean = true, l: Long = 0) = s + n + b + l
638637
}
639638
```
640639
```scala
641640
object Unrolled{
642-
def foo(s: String, n: Int = 1, @unrollOnly b: Boolean = true, @unrollOnly l: Long = 0) = s + n + b + l
641+
def foo(s: String, n: Int = 1, b: Boolean = true, l: Long = 0) = s + n + b + l
643642

644643
def foo(s: String, n: Int, b: Boolean) = foo(s, n, b, 0)
645644
def foo(s: String, n: Int) = foo(s, n, true, 0)
646645
}
647646
```
648647

649-
And generating one forwarder would look like this:
650-
651-
```scala
652-
object Unrolled{
653-
def foo(s: String, n: Int = 1, @unrollOnly b: Boolean = true, l: Long = 0) = s + n + b + l
654-
}
655-
```
656-
```scala
657-
object Unrolled{
658-
def foo(s: String, n: Int = 1, @unrollOnly b: Boolean = true, l: Long = 0) = s + n + b + l
659-
660-
def foo(s: String, n: Int) = foo(s, n, true, 0)
661-
}
662-
```
663-
664-
`@unrollOnly` would provide a more granular replacement for `@unroll`. This probably does not
665-
make a huge difference in most cases, but it could be useful in scenarios where there
666-
are a large number of default parameters being added every version, as it would minimize the
667-
amount of generated code.
668-
669648

670649
### Abstract Methods
671650

0 commit comments

Comments
 (0)