0

I have this code:

object Peek { implicit def traversableToPeek[A](underlying: Traversable[A]) = new Peek(underlying) } class Peek[A](underlying: Traversable[A]) { /** * Java-style peek method */ def peek(func: A => Unit): Traversable[A] = { underlying.foreach(func) underlying } } 

while lets me write things like List(1,2,3).peek(println).map(_+1).peek(println) which prints 1,2,3 and then 2,3,4 (after import Peek._)

However, the compile-time value of that expression is Traversable[Int]. This means that while this code compiles:

val l = List(1,2,3) val l2 = 4 :: l 

this code does not:

val l = List(1,2,3).peek(println) val l2 = 4 :: l 

since :: is not defined on Traversable. The intent of peek is to allow side-effect only operations without requiring somewhat ugly constructs like l.map(e => println(e); e)

I tried adding a second generic parameter T <: Traversable or T[A] <: Traversable[A] but could not get it compile in a manner where the implicit conversion worked.

I feel this should be possible, but I am not familiar enough with Scala to get the syntax correct.

2 Answers 2

2

The second generic parameter is the correct approach:

implicit class Peek[C[X] <: Traversable[X], A](underlying: C[A]) { def peek(func: A => Unit): C[A] = { underlying.foreach(func) underlying } } 

(in Scala 2.13, replace deprecated Traversable with Iterable).

In case you have a type extending Traversable[Something] which isn't itself generic, the above won't work, but

implicit class Peek[C <: Traversable[A], A](underlying: C with Traversable[A]) { def peek(func: A => Unit): C = { underlying.foreach(func) underlying } } 

should.

Sign up to request clarification or add additional context in comments.

3 Comments

We are still in Scala 2.12.
So the X is a type that only exists for define C fully?
Yes. You could write C[A] <: Traversable[A] with the same meaning but this would be a different A from Peek's own type parameter.
0

I don't see much difference than above, here is another alternative using CanBuildFrom

import scala.collection.generic._ import scala.language.higherKinds implicit class CollWrapper[Coll[X] <: Traversable[X], A](coll:Coll[A]) { def peek(f:A => Unit)(implicit cbf:CanBuildFrom[Coll[A], A, Coll[A]]):Coll[A] = { val builder = cbf(coll) coll.foreach{elem => builder += elem; f(elem) } coll } } List(1,2,3,4).peek(println).map(x => x * 3) println("--") List("One", "Two", "Three").peek(println).map(x => x + "!") println("--") List('c', 'd', 'e').peek(println).map(x => x + 3) println("--") Set("Nine", "Ten", "Twelve").peek(println).map(x => x + "!") println("--") Map(1 -> "One", 2 -> "Two", 3 -> "Three").peek(println).map{case (k,v) => (k, v + "!")}.toMap println("--") 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.