18

Sometimes I read about stackoverflow users are happy (e.g.) 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.

13

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
9

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

6

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
}
3

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)
3

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 _.)

2
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
2

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 { ... } 
1

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)

...
1

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.