From 92c0bb9eead5b2ab5919e8f097f02f74aeed7e95 Mon Sep 17 00:00:00 2001 From: georg Date: Tue, 13 Apr 2021 09:28:54 +0200 Subject: [PATCH 1/8] Specialised Option.tapEach to preserve the type --- .../scala/scala/collection/next/package.scala | 11 ++++++++++ .../next/TestOptionOpsExtensions.scala | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala diff --git a/src/main/scala/scala/collection/next/package.scala b/src/main/scala/scala/collection/next/package.scala index db9e1a6..a14161d 100644 --- a/src/main/scala/scala/collection/next/package.scala +++ b/src/main/scala/scala/collection/next/package.scala @@ -19,4 +19,15 @@ package object next { col: IterableOnceOps[A, CC, C] ): NextIterableOnceOpsExtensions[A, CC, C] = new NextIterableOnceOpsExtensions(col) + + implicit final class OptionOpsExtensions[A](val v: Option[A]) extends AnyVal { + /** Apply the side-effecting function $f to the option's value, + * if it is nonempty. Otherwise, do nothing. + * + * @param f a function to apply to the option's value + * @tparam B the return type of f + * @return the option + */ + def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v } + } } diff --git a/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala b/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala new file mode 100644 index 0000000..81c0320 --- /dev/null +++ b/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala @@ -0,0 +1,21 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala.collection.next + +import org.junit.Assert._ +import org.junit.Test + +final class TestOptionOpsExtensions { + // Compile checks the return type, no need to run as test. + def tapEachReturnType(): Option[Int] = Option(5).tapEach(identity) +} From dba516c3e8fc0a4059ea85a4c4ed7ecff4af07e0 Mon Sep 17 00:00:00 2001 From: georg Date: Tue, 13 Apr 2021 16:26:18 +0200 Subject: [PATCH 2/8] fixed scaladoc comment --- src/main/scala/scala/collection/next/package.scala | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/scala/scala/collection/next/package.scala b/src/main/scala/scala/collection/next/package.scala index a14161d..3956f6e 100644 --- a/src/main/scala/scala/collection/next/package.scala +++ b/src/main/scala/scala/collection/next/package.scala @@ -21,13 +21,12 @@ package object next { new NextIterableOnceOpsExtensions(col) implicit final class OptionOpsExtensions[A](val v: Option[A]) extends AnyVal { - /** Apply the side-effecting function $f to the option's value, - * if it is nonempty. Otherwise, do nothing. - * - * @param f a function to apply to the option's value - * @tparam B the return type of f - * @return the option - */ + /** Apply the side-effecting function `f` to the option's value + * if it is nonempty. Otherwise, do nothing. + * + * @param f a function to apply to the option's value + * @return the option + */ def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v } } } From 92253317f5ec2b430e420f0c9de53170de7cc456 Mon Sep 17 00:00:00 2001 From: georg Date: Wed, 21 Apr 2021 08:45:13 +0200 Subject: [PATCH 3/8] Removed unnecessary imports --- .../scala/scala/collection/next/TestOptionOpsExtensions.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala b/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala index 81c0320..4cafaf8 100644 --- a/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala +++ b/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala @@ -12,9 +12,6 @@ package scala.collection.next -import org.junit.Assert._ -import org.junit.Test - final class TestOptionOpsExtensions { // Compile checks the return type, no need to run as test. def tapEachReturnType(): Option[Int] = Option(5).tapEach(identity) From d7ed4ad893fa0ba7108751a8eff160742cf9a071 Mon Sep 17 00:00:00 2001 From: georg Date: Fri, 23 Apr 2021 12:08:29 +0200 Subject: [PATCH 4/8] Moved OptionOpsExtensions from scala.collection.next to scala.next --- .../scala/scala/collection/next/package.scala | 10 -------- src/main/scala/scala/next/package.scala | 25 +++++++++++++++++++ .../next/TestOptionOpsExtensions.scala | 2 +- 3 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 src/main/scala/scala/next/package.scala rename src/test/scala/scala/{collection => }/next/TestOptionOpsExtensions.scala (93%) diff --git a/src/main/scala/scala/collection/next/package.scala b/src/main/scala/scala/collection/next/package.scala index 3956f6e..db9e1a6 100644 --- a/src/main/scala/scala/collection/next/package.scala +++ b/src/main/scala/scala/collection/next/package.scala @@ -19,14 +19,4 @@ package object next { col: IterableOnceOps[A, CC, C] ): NextIterableOnceOpsExtensions[A, CC, C] = new NextIterableOnceOpsExtensions(col) - - implicit final class OptionOpsExtensions[A](val v: Option[A]) extends AnyVal { - /** Apply the side-effecting function `f` to the option's value - * if it is nonempty. Otherwise, do nothing. - * - * @param f a function to apply to the option's value - * @return the option - */ - def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v } - } } diff --git a/src/main/scala/scala/next/package.scala b/src/main/scala/scala/next/package.scala new file mode 100644 index 0000000..8aecd39 --- /dev/null +++ b/src/main/scala/scala/next/package.scala @@ -0,0 +1,25 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala + +package object next { + implicit final class OptionOpsExtensions[A](val v: Option[A]) extends AnyVal { + /** Apply the side-effecting function `f` to the option's value + * if it is nonempty. Otherwise, do nothing. + * + * @param f a function to apply to the option's value + * @return the option + */ + def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v } + } +} diff --git a/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala b/src/test/scala/scala/next/TestOptionOpsExtensions.scala similarity index 93% rename from src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala rename to src/test/scala/scala/next/TestOptionOpsExtensions.scala index 4cafaf8..39b4630 100644 --- a/src/test/scala/scala/collection/next/TestOptionOpsExtensions.scala +++ b/src/test/scala/scala/next/TestOptionOpsExtensions.scala @@ -10,7 +10,7 @@ * additional information regarding copyright ownership. */ -package scala.collection.next +package scala.next final class TestOptionOpsExtensions { // Compile checks the return type, no need to run as test. From 45363181d789a35bf4e9717cf071ebcb7bea9850 Mon Sep 17 00:00:00 2001 From: georg Date: Fri, 23 Apr 2021 12:09:37 +0200 Subject: [PATCH 5/8] In the test for the Option.tapEach extension make sure the compiler can't coerce a specific implicit --- src/test/scala/scala/next/TestOptionOpsExtensions.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/scala/scala/next/TestOptionOpsExtensions.scala b/src/test/scala/scala/next/TestOptionOpsExtensions.scala index 39b4630..17dd535 100644 --- a/src/test/scala/scala/next/TestOptionOpsExtensions.scala +++ b/src/test/scala/scala/next/TestOptionOpsExtensions.scala @@ -14,5 +14,9 @@ package scala.next final class TestOptionOpsExtensions { // Compile checks the return type, no need to run as test. - def tapEachReturnType(): Option[Int] = Option(5).tapEach(identity) + def tapEachReturnType(): Option[Int] = { + // Don't return the Option directly, so the compiler is not able to coerce a specific implicit to be used. + val opt = Option(5).tapEach(identity) + opt.map(identity) + } } From 03e36fb50d136b791d4927896f5dde63df1c25ce Mon Sep 17 00:00:00 2001 From: georg Date: Fri, 23 Apr 2021 12:11:40 +0200 Subject: [PATCH 6/8] Fixed scaladoc comment style --- src/main/scala/scala/next/package.scala | 10 +++++----- .../scala/scala/next/TestOptionOpsExtensions.scala | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/scala/scala/next/package.scala b/src/main/scala/scala/next/package.scala index 8aecd39..95c38da 100644 --- a/src/main/scala/scala/next/package.scala +++ b/src/main/scala/scala/next/package.scala @@ -15,11 +15,11 @@ package scala package object next { implicit final class OptionOpsExtensions[A](val v: Option[A]) extends AnyVal { /** Apply the side-effecting function `f` to the option's value - * if it is nonempty. Otherwise, do nothing. - * - * @param f a function to apply to the option's value - * @return the option - */ + * if it is nonempty. Otherwise, do nothing. + * + * @param f a function to apply to the option's value + * @return the option + */ def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v } } } diff --git a/src/test/scala/scala/next/TestOptionOpsExtensions.scala b/src/test/scala/scala/next/TestOptionOpsExtensions.scala index 17dd535..2f7d74b 100644 --- a/src/test/scala/scala/next/TestOptionOpsExtensions.scala +++ b/src/test/scala/scala/next/TestOptionOpsExtensions.scala @@ -15,7 +15,7 @@ package scala.next final class TestOptionOpsExtensions { // Compile checks the return type, no need to run as test. def tapEachReturnType(): Option[Int] = { - // Don't return the Option directly, so the compiler is not able to coerce a specific implicit to be used. + // Don't return the option directly, so the compiler is not able to coerce a specific implicit to be used. val opt = Option(5).tapEach(identity) opt.map(identity) } From a22225367ba86985882b2a8bbeb488a396f62195 Mon Sep 17 00:00:00 2001 From: georg Date: Thu, 29 Apr 2021 17:26:12 +0200 Subject: [PATCH 7/8] Moved TestOptionOpsExtensions to scala.test to have the extension more closely to a user code scenario --- .../scala/scala/{next => test}/TestOptionOpsExtensions.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/test/scala/scala/{next => test}/TestOptionOpsExtensions.scala (93%) diff --git a/src/test/scala/scala/next/TestOptionOpsExtensions.scala b/src/test/scala/scala/test/TestOptionOpsExtensions.scala similarity index 93% rename from src/test/scala/scala/next/TestOptionOpsExtensions.scala rename to src/test/scala/scala/test/TestOptionOpsExtensions.scala index 2f7d74b..2ffcf21 100644 --- a/src/test/scala/scala/next/TestOptionOpsExtensions.scala +++ b/src/test/scala/scala/test/TestOptionOpsExtensions.scala @@ -10,7 +10,9 @@ * additional information regarding copyright ownership. */ -package scala.next +package scala.test + +import scala.next._ final class TestOptionOpsExtensions { // Compile checks the return type, no need to run as test. From 0eefc7b45011b0a89b7f8dd69e04841c46840ae5 Mon Sep 17 00:00:00 2001 From: gdiet Date: Tue, 11 May 2021 11:53:53 +0200 Subject: [PATCH 8/8] value of extension value class made private Co-authored-by: Julien Richard-Foy --- src/main/scala/scala/next/package.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scala/next/package.scala b/src/main/scala/scala/next/package.scala index 95c38da..fb21a9a 100644 --- a/src/main/scala/scala/next/package.scala +++ b/src/main/scala/scala/next/package.scala @@ -13,7 +13,7 @@ package scala package object next { - implicit final class OptionOpsExtensions[A](val v: Option[A]) extends AnyVal { + implicit final class OptionOpsExtensions[A](private val v: Option[A]) extends AnyVal { /** Apply the side-effecting function `f` to the option's value * if it is nonempty. Otherwise, do nothing. *