Scala: Are assertions acceptable outside of test context?
In short: yes, assertions make perfect sense outside testing and can raise the confidence that the code is actually correct.

Design by contract

What you like to assert, namely, that "dataOption must be defined if tpe does not represent a subtype of Option[Any]" can be considered a precondition of your method. That is, a condition over the parameters (and fields and global state) that needs to hold in order for your method to run successfully. The method implementer states such conditions and can then rely on them, whereas the caller is responsible for ensuring that they hold. The dual concept are postconditions, where the caller gets the guarantee which the implementer must ensure.

Languages such as Eiffel and Spec# natively support this so-called design by contract approach to programming. Natively, because contract elements such as preconditions, postconditions and invariants are built into the language. There is a significant difference, however, when the contracts are looked at. Eiffel checks contracts at run-time, which is quite similar to testing in the sense that only concrete executions are considered. Spec#, on the other hand, verifies contracts statically, which means that it tries to assert that the contract holds for all possible executions. The latter is very challenging and not always possible, but it yields much stronger guarantees in case it is. The former is easier, but gives you weaker guarantees.

Other languages lack native support for such contracts, for example Java or C#. In order to design by contract, Java developers can use JML and C# developers can use Code Contracts. JML is based on Java annotations and can be used for static verification and run-time checking, as can Code Contracts be, but they are implemented as a regular library.

Scala

Scala also lacks built-in support for contracts, but there are quite a few projects that try to work around this. Amongst others, there are:


Very simple run-time checked pre- and postconditions described in the paper Contracts for Scala
Static verification of functional Scala code with Leon
Run-time checking of Scala with a Code-Contracts-like library (project report)
Static verification of possibly non-functional Scala code (project description, the report will be only soon)


The answer

Back to your question: You use assertions (and the control flow) to check the precondition of your method, hence, you kind of do design by contract - which is good, because it makes it more likely that errors are detected close to where they are caused. These checks are basically like small unit tests and thus can increase the confidence in your code.

In order to make the method's precondition as explicit as possible, I would move the assertion to the begin of the method

private def convertData(dataOption: Option[ByteString], tpe: Type): Any = {
  assert(tpe.&lt;:&lt;(typeOf[Option[Any]]) || dataOption.isDefined,
         "&lt;put helpful error message here&gt;")

  ...
}


You could also put assertions at all return points of the method in order to mimic postconditions.

In case you worry about performance, you can use the fact the assert is annotated as @elidable and thus can be removed by the compiler, for example, for a production build.