title: What is the meaning of a type declaration without definition in an object?
body: <p>Scala allows to define types using the <code>type</code> keyword, which usually have slightly different meaning and purpose depending on when they are declared.</p>
  
  <p>If you use <code>type</code> inside an object or a package object, you'd define a type alias, i.e. a shorter/clearer name for another type:</p>
  
  <pre><code>package object whatever {
    type IntPredicate = Int =&gt; Boolean
  
    def checkZero(p: IntPredicate): Boolean = p(0)
  }
  </code></pre>
  
  <p>Types declared in classes/traits are usually intended to be overridden in subclasses/subtraits, and are also eventually resolved to a concrete type:</p>
  
  <pre><code>trait FixtureSpec {
    type FixtureType
    def initFixture(f: FixtureType) = ...
  }
  
  trait SomeSpec extends FixtureSpec {
    override type FixtureType = String
  
    def test(): Unit = {
      initFixture("hello")
      ...
    }
  }
  </code></pre>
  
  <p>There are other uses for abstract type declarations, but anyway they eventually are resolved to some concrete types.</p>
  
  <p>However, there is also an option to declare an <em>abstract</em> type (i.e. without actual definition) inside an <em>object</em>:</p>
  
  <pre><code>object Example {
    type X
  }
  </code></pre>
  
  <p>And this compiles, as opposed to e.g. abstract methods:</p>
  
  <pre><code>object Example {
    def method: String  // compilation error
  }
  </code></pre>
  
  <p>Because objects cannot be extended, they can never be resolved to concrete types.</p>
  
  <p>I assumed that such type definitions could be conveniently used as phantom types. For example (using Shapeless' tagged types):</p>
  
  <pre><code>import shapeless.tag.@@
  import shapeless.tag
  
  type ++&gt;[-F, +T]
  
  trait Converter
  
  val intStringConverter: Converter @@ (String ++&gt; Int) = tag[String ++&gt; Int](...)
  </code></pre>
  
  <p>However, it seems that the way the type system treats these types is different from regular types, which causes the above usage of "abstract" types to fail in certain scenarios.</p>
  
  <p>In particular, when looking for implicit parameters, Scala eventually looks into implicit scope associated with "associated" types, i.e. types which are present in the type signature of the implicit parameters. However, it seems that there is some limitation on nesting of these associated types when "abstract" types are used. Consider this example setup:</p>
  
  <pre><code>import shapeless.tag.@@
  
  trait Converter
  
  type ++&gt;[-F, +T]
  
  case class DomainType()
  
  object DomainType {
    implicit val converter0: Converter @@ DomainType = null
    implicit val converter1: Converter @@ Seq[DomainType] = null
    implicit val converter2: Converter @@ (Seq[String] ++&gt; Seq[DomainType]) = null
  
  }
  
  // compiles
  implicitly[Converter @@ DomainType]
  // compiles
  implicitly[Converter @@ Seq[DomainType]]
  // fails!
  implicitly[Converter @@ (Seq[String] ++&gt; Seq[DomainType])]
  </code></pre>
  
  <p>Here, the first two implicit resolutions compile just fine, while the last one fails with an error about a missing implicit. If I define the implicit in the same scope as the <code>implicitly</code> call, it then compiles:</p>
  
  <pre><code>implicit val converter2: Converter @@ (Seq[String] ++&gt; Seq[DomainType]) = null
  // compiles
  implicitly[Converter @@ (Seq[String] ++&gt; Seq[DomainType])]
  </code></pre>
  
  <p>However, if I change the <code>++&gt;</code> definition to be a <code>trait</code> rather than <code>type</code>:</p>
  
  <pre><code>trait ++&gt;[-F, +T]
  </code></pre>
  
  <p>then all <code>implicitly</code> calls above compile just fine.</p>
  
  <p>Therefore, my question is, what exactly is the purpose of such type declarations? What problems they are intended to solve, and why are they not prohibited, like other kinds of abstract members in objects?</p>