An easy thing to do in many languages but not in Scala is:
Define archetype 'Super', such that all implementations of 'Super' has to define a constructor 'create()'.
I found this constraint very important and is able to identify a lot of problems before runtime. However this feature is only partially enforced in Java (by defining an 'abstract' static method that always throws an error) and completely missing in Scala (companion object is completely detached from class and cannot be enforced in archetype).
is there a macro or tool that allows me to do this?
UPDATE Sorry my question was missing context and examples. Here is a formal use case in scala:
In project A, we define an interface that can be extended by all subprojects:
trait AbstractFoo {}
This interface should always have a default 0-parameter builder/constructor, so project A can initialize it on-demand, however, the implementation of each constructor is unknown to project A:
object AbstractFoo {
def default[T <: AbstractFoo: ClassTag](): T
}
So the problem becomes: How to rigorously define AbstractFoo, such that for all subprojects of A, any implementation(s) of AbstractFoo:
case class Foo(...) extends AbstractFoo
must satisfy:
'Foo' must have a 0-parameter builder/constructor defined (presumably in its companion object)
calling AbstractFoo.defaultFoo can invoke this 0-parameter builder/constructor
It should be noted that in an alternative conditions, a solution exists which is to define every companion object as an implicit type class:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
}
object AbstractFoo {
implicit object Foo extends FooBuilder[Foo] {
def default() = {...}
}
def default[T <: AbstractFoo: FooBuilder](): T = {
implicitly[FooBuilder[T]].default
}
}
Such that if the implicit object is undefined the compiler will give an implicit not found error (my code snippet may have some syntax error, the idea is from http://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala)
Unfortunately it's not always convenient, because this subproject of A is usually unknown to project A. Yet the default implicit builder cannot be redefined, this makes every invocation of default() more covoluted.
I believe scala is a very extendable language, so there should be at least 1 way to enforce it whether if using macro, annotation or other metaprogramming techniques. Is my question clear enough now?
UPDATE2: I believe I found the solution after carefully study Scaladoc, there is a comment hidden in a corner:
if there are several eligible arguments which match the implicit parameter’s type, a most specific one will be chosen using the rules of static overloading resolution (see Scala Specification §6.26.4):
...
Implicit scope of type arguments (2.8.0)
...
So all I need is to write an implicit function in FooBuilder:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
implicit def self = this
}
object Foo extends FooBuilder[Foo]
So everytime someone call:
default[Foo]
scala will refer to the scope of class Foo, which include object Foo, which contains the implicit value Foo, and eventually find the 0-parameter constructor.
I think this definition is better than defining it under object FooBuilder, since you can only define FooBuilder once, thus its not quite extendable. Would you agree with me? If so, could you please revise your answer so I can award you point?
AbstractFoo.default[ConcreteFoo]
. And in that case I think the implicit typeclass pattern fits perfectly... – Jasper-M