I’m using a technique using a contravariant type class to stop the compiler from implicitly resolving to a Nothing type, based off this blog post.
@implicitNotFound("Nothing was inferred")
sealed trait NotNothing[-T]
object NotNothing {
implicit object notNothing extends NotNothing[Any]
//We do not want Nothing to be inferred, so make an ambigous implicit
implicit object `\n The error is because the type parameter was resolved to Nothing`
extends NotNothing[Nothing]
}
It seems to work fine, but part of me is wondering if there’s a more elegant solution, and if it’s a reasonable thing to provide a library that makes use of this:
trait Logger {
// ...
def semantic[MessageType: NotNothing]: SemanticLogger[MessageType]
}
logger.semantic.info("Will not compile, because message type is nothing")
I use wartremover in most of my projects, which is a compiler plugin to catch several types of common problems or disallow certain features. One of the options does exactly this, it gives a compile time error or warning (depending on configuration), if the compiler infers Nothing.
It can’t be used as selectively as your approach, but in my experience, the cases where I want Nothing to be inferred are so rare, that I’d rather add a type annotation there than changing the signature of my types everywhere else.
I’m aware of the WartRemover, but that requires people to add it in their own projects. I haven’t released this library yet, so there’s no cost to me adding this to the method signatures.
Ah, sorry, I misunderstood. I thought your question was if it was reasonable to create a library providing the NotNothing typeclass. So it’s more to make the type argument to semantic mandatory, right?
In that case, I don’t see any downsides to using this, as the client of the library shouldn’t really see a difference except in cases where you don’t want it to compile.