title: How to take out Nothing out of inferred type
body: <p>The idea comes from this video: <a href="https://www.youtube.com/watch?v=BfaBeT0pRe0&amp;t=526s" rel="nofollow noreferrer">https://www.youtube.com/watch?v=BfaBeT0pRe0&amp;t=526s</a>, where they talk about implementing type safety through implementation of custom types.</p>
  <p>And a possible trivial implementation is</p>
  <pre><code>trait Col[Self] { self: Self =&gt;
  }
  
  trait Id extends Col[Id]
  object IdCol extends Id
  
  trait Val extends Col[Val]
  object ValCol extends Val
  
  trait Comment extends Col[Comment]
  object CommentCol extends Comment
  
  case class DataSet[Schema &gt;: Nothing](df: DataFrame) {
  
    def validate[T1 &lt;: Col[T1], T2 &lt;: Col[T2]](
        col1: (Col[T1], String),
        col2: (Col[T2], String)
    ): Option[DataSet[Schema with T1 with T2]] =
      if (df.columns
            .map(e =&gt; e.toLowerCase)
            .filter(
              e =&gt;
                e.toLowerCase() == col1._2.toLowerCase || e
                  .toLowerCase() == col2._2.toLowerCase
            )
            .length &gt;= 1)
        Some(DataSet[Schema with T1 with T2](df))
      else None
  }
  
  object SchemaTypes extends App {
  
    lazy val spark: SparkSession = SparkSession
      .builder()
      .config(
        new SparkConf()
          .setAppName(
            getClass()
              .getName()
          )
      )
      .getOrCreate()
  
    import spark.implicits._
  
    val df = Seq(
      (1, &quot;a&quot;, &quot;first value&quot;),
      (2, &quot;b&quot;, &quot;second value&quot;),
      (3, &quot;c&quot;, &quot;third value&quot;)
    ).toDF(&quot;Id&quot;, &quot;Val&quot;, &quot;Comment&quot;)
  
    val myData =
      DataSet/*[Id with Val with Comment]*/(df)
        .validate(IdCol -&gt; &quot;Id&quot;, ValCol -&gt; &quot;Val&quot;)
  
    myData match {
      case None =&gt; throw new java.lang.Exception(&quot;Required columns missing&quot;)
      case _    =&gt;
    }
  }
  </code></pre>
  <p>The type for myData is <code>Option[DataSet[Nothing with T1 with T2]]</code>. It makes sense since the constructor is called w/o any type parameter, but in the video they show the type to be in line with <code>DataSet[T1 with T2]</code>.</p>
  <p>Of course, changing the invocation by passing explicity type takes <code>Nothing</code> out, but it is redundant to specify the type parameter value since the types are already included in the arg list.</p>
  <pre><code>val myData =
    DataSet[Id with Val with Comment](df).validate(IdCol -&gt; &quot;Id&quot;, ValCol -&gt; &quot;Val&quot;)
  </code></pre>