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