Sometimes I read about stackoverflow users are happy (
e.g.
[1]) about grapping new ideas for their own standard library which is included in all their projects.
I also have a package util
where I keep all usefull stuff that isn´t included in the scala standard library but makes my life much easier.
For example the pipe operator. So, I imagine that everyone has at least some small extensions common to all their projects.
I am (and I guess others too) interested in the most useful extensions of the community here, so one can collect nice ideas to fresh up minds.
For example, the common Pipe Operator (slightly adapted):
object Pipe {
class Piped[T] (value: T) {
def |> [R] (f: T => R ): R = f(value)
def |>> (f: T => Any): T = { f(value); value }
}
}
implicit def toPiped[T](value: T) = new Pipe.Piped[T](value)
Usage (REPL):
scala> { if (math.random > 0.5) "Hi" else "Bye" } |> (_.toUpperCase + " John")
res0: java.lang.String = BYE John
scala> { math.random > 0.5 } |>> { require(_) }
res1: Boolean = true
Piped
in Pipe
? - Jean-Philippe Pellet
object Functional
. - Peter Schmitz
use
and effect
, respectively, since I find it easier to remember that effect
causes side effects than that |>>
does. - Rex Kerr
|>>
evolves out of my needs and I haven´t seen it before: The fact that you're also using it, is a good indication that it is useful and no coincidence. Good point about effect
vs |>>
. - Peter Schmitz
A classical — the “on-loan” pattern:
def withResource[T <: { def close(): Unit }, R](resource: T)(work: T => R): R = {
try {
// do the work
work(resource)
} finally {
// dispose resource
resource.close()
}
}
Reference: http://scala.sygneca.com/patterns/loan
I do a lot of microbenchmarking, which makes the following methods very useful:
// Do something n times
def lots[F](n: Int)(f: => F): F = if (n>1) { f; lots(n-1)(f) } else f
// Time something
def time[F](f: => F) = {
var t0 = System.nanoTime
val ans = f
(ans , System.nanoTime - t0)
}
// Time something and tell us how long it took
def ptime[F](f: => F) = {
val ta = time(f)
printf("Elapsed: %.3f s\n",1e-9*ta._2)
ta._1
}
def benchmark[T]...
instead of def time[F]...
. - Peter Schmitz
Do you ever want the nice copying features of a case class except that you don't want equality or matching to pay attention to that entry? Well, enter the:
// These can be placed in case classes without changing equality, sort of like a comment
class Caseless[A](private[Utility] val a: A) {
override def hashCode = 0
override def equals(o: Any) = o.isInstanceOf[Caseless[_]]
override def toString = "_"
def value = a
}
implicit def anything_is_caseless[A](a: A) = new Caseless(a)
implicit def caseless_is_anything[A](c: Caseless[A]) = c.a
where you can now do things like
case class Pony(name: String, creationTime: Caseless[Long]) {}
val blaze = new Pony("Blaze", System.currentTimeMillis)
Thread.sleep(10)
val blaze2 = new Pony("Blaze", System.currentTimeMillis)
blaze == blaze2 // true
blaze2.creationTime - blaze.creationTime // 10 or more
val spirit = blaze.copy(name = "Spirit") // Rename blaze
spirit == blaze // false, they have different names
blaze.creationTime.value - spirit.creationTime.value // Zero
so you can safely carry along information in your case class without it affecting equality. (If you're matching, you do still need to throw in an extra _.)
I use this one all the time when doing anything like batch processing. It's essentially a small implementation of MapReduce, usable on any Traversable
object RichTraversable {
implicit def traversable2RichTraversable[A](t: Traversable[A]) = new RichTraversable[A](t)
}
class RichTraversable[A](t: Traversable[A]) {
def reduceBy[B, C](f: A => B, g: A => C, reducer: (C, C) => C): Map[B, C] = {
def reduceInto(map: Map[B, C], key: B, value: C): Map[B, C] =
if (map.contains(key)) {
map + (key -> reducer(map(key), value))
}
else {
map + (key -> value)
}
t.foldLeft(Map.empty[B, C])((m, x) => reduceInto(m, f(x), g(x)))
}
//here are some common specializations, many more elided
def sumBy[B, C: Numeric](f: A => B, g: A => C): Map[B, C] = reduceBy(f, g, implicitly[Numeric[C]].plus(_: C, _: C))
def maxBy[B, C: Ordering](f: A => B, g: A => C): Map[B, C] = reduceBy(f, g, implicitly[Ordering[C]].max(_: C, _: C))
}
val test = Set("foo", "bar", "barangus")
println(test.sumBy(_.charAt(0), _.length)) //prints Map('f'->3, 'b'->11)
println(test.maxBy(_.charAt(0), _.length)) //prints Map('f'->3, 'b'->8)
More for better code readability than making coding easier:
package net.uniscala.scala
private[scala] class OptionIfDefinedExtension[A](val self:Option[A])
extends Proxy {
def ifDefined[B](f:A=>B):Option[B] = self.map[B](f)
def otherwise[B>:A](default: =>B):B = self.getOrElse(default)
}
object OptionIfDefinedImplicits {
implicit def toOptionIfDefinedExtension[A](option:Option[A])
= new OptionIfDefinedExtension(option)
}
Usage:
import net.uniscala.scala.OptionIfDefinedImplicits._
val topt:Option[T] = ...
topt ifDefined { t:T => ... } otherwise { ... }
if ... else
, renaming the else
to otherwise
... And you gain almost nothing above just writing if (topt.isDefined) { ... } else { ... }
. - Jesper
get
on topt
yourself. Still I find it ugly to use an alternative word for else
. - Jesper
object DoWhile {
class Doing[T](f: () => T) {
def While(b: T => Boolean): T = {
var t = f()
while (b(t)) { t = f() }
t
}
}
def Do[T](f: () => T) = new Doing(f)
}
Usage (REPL):
scala> DoWhile.Do {
| () => math.random
| } While (_ < 0.5)
res0: Double = 0.8574303051236236
var
for holding the result before the loop which messes up the scope. I am not a friend of having var
s in scope that should be val
after the loop. - Peter Schmitz
f: () => T
instead of just f: => T
? Anyway, I just use Iterator.continually(math.random).dropWhile(_ < 0.5).next
. - Rex Kerr
Iterator.continually...
! And anyway, I should fix that () => T
in my lib. Thanks. - Peter Schmitz
I often use:
class RichTraversableOnce[A](val t: TraversableOnce[A]) {
def mkStr = t.mkString(",")
def mkStrln = t.mkString("\n","\n","\n")
}
class RichTraversable[A](t: Traversable[A]) {
def toMapBy[B](f: A => B): Map[B,A] = {
// no duplicate keys compared to library method groupBy
val res = t.map{ e => (f(e),e) }.toMap
require(res.size == t.size, "\n%s\n%s\n".format(res.mkStrln,t.mkStrln))
res
}
}
import scala.collection.mutable.{Map => MutMap, Buffer}
class RichSeq[A](val seq: Seq[A]) {
def isDistinct: Boolean = seq.distinct sameElements seq
def isDistinctBy[B](f: A => B): Boolean = seq.distinctBy(f) sameElements seq
def distinctBy[B](f: A => B): Seq[A] = {
seq.foldLeft {(Buffer[A](),MutMap[B,A]())} {
case ((b,m),x) if m contains f(x) => (b,m)
case ((b,m),x) =>
m += f(x) -> x
b += x
(b,m)
}._1
}
def sameElementsOrderless(s: Seq[A]): Boolean = {
// sameElements takes order into account
seq.size == s.size && seq.toSet.subsetOf(s.toSet) &&
s.toSet.subsetOf(seq.toSet)
}
}
class RichSet[A](val set: Set[A]) {
def isDisjunct(s: Set[A]): Boolean = {
(set intersect s).isEmpty // (set union s).size == set.size + set.size
}
def sameElementsOrderless(s: scala.collection.Set[A]): Boolean = {
// sameElements takes order into account
s.subsetOf(set) && set.subsetOf(s)
}
}
Of course implicit conversions to Rich...
are necessary.
Tuples are missing a couple of extremely useful (to me) methods that I add back in (for small sizes of tuples). I could call each
map
, but after using collections I find that I expect all the types to be the same, which is not true here. One could also prefer multiple argument lists instead of the two arguments in one argument list.
// Methods for 2-element tuples
class PairWrapper[A,B](ab: (A,B)) {
def each[Y,Z](fl: A=>Y, fr: B=>Z) = (fl(ab._1),fr(ab._2))
def fold[Z](f: (A,B)=>Z) = f(ab._1,ab._2)
}
implicit def pair_has_utility[A,B](ab: (A,B)) = new PairWrapper(ab)
// Methods for 3-element tuples
class TrioWrapper[A,B,C](abc: (A,B,C)) {
def each[X,Y,Z](fl: A=>X, fc: B=>Y, fr: C=>Z) = (fl(abc._1),fc(abc._2),fr(abc._3))
def fold[Z](f: (A,B,C)=>Z) = f(abc._1,abc._2,abc._3)
}
implicit def trio_has_utility[A,B,C](abc: (A,B,C)) = new TrioWrapper(abc)
...
def map[C,D](f: ((A,B)) => ((C,D))): Tuple2[C,D] = f(t)
and def mapFirst [C](f: A => C) = (f(t._1), t._2 )
and def mapSecond[D](f: B => D) = ( t._1 ,f(t._2))
... on class RichTuple2[A,B](t: Tuple2[A,B])
What do you think? - Peter Schmitz
mapFirst
and mapSecond
look reasonable. You already have your original map. It's called |>
, and it's even more powerful. I have f: (A,B) => Z
for a reason, namely that you don't have to take apart the tuple. - Rex Kerr