Search code examples
scalapackagesingletonshapelessfunction-definition

Why not define functions as singleton functions?


Consider definition of a singleton function found in shapeless repo:

/** Polymorphic function selecting an arbitrary element from a non-empty `Set`. */
object choose extends (Set ~> Option) {
  def apply[T](s : Set[T]) = s.headOption 
}

Contrast it with the traditional def syntax in the following example:

package utils

object UtilWithASingleMethod {
  def isSatisfyingSomePredicate(foo: Foo): Boolean = ???
}

versus

package utils

object isSatisfyingSomePredicate extends (Foo => Boolean) {
  def apply(foo: Foo): Boolean = ???
}

Note how call-site now becomes

isSatisfyingSomePredicate(foo)

instead of

UtilWithASingleMethod.isSatisfyingSomePredicate(foo)

or

import UtilWithASingleMethod._

isSatisfyingSomePredicate(foo)

Personally, UtilWithASingleMethod package seems forced just to be able to use familiar def syntax but does not add any useful information.

Besides subjective downsides such as unfamiliarity, or confusion with object+apply style used in factory pattern, are there any technical downsides with singleton function definitions?


Solution

  • The reason why they had to create singleton objects in the file you linked is that those were not functions, but polymorphic functions, i.e. they had an apply[T](a: F[T]): G[T] method that is universally quantified by a type parameter T. This is simply not needed for ordinary functions, all it does is adding overhead of invoking the apply method on a singleton object foo instead of invoking the method foo directly. It doesn't help you "avoid" the packages and imports either, because you want to have this object in some package anyway, you don't want to dump it in the default root package.

    If you want to avoid the "forced" UtilWithASingleMethod namespace, then add the isSatisfyingSomePredicate directly to util:

    package object util {
      def isSatisfyingSomePredicate(foo: Foo): Boolean = ???
    }
    

    This method becomes available as soon as you import util._.