Проблема
Когда я работаю с библиотеками, поддерживающими программирование на уровне, я часто нахожу, что пишу комментарии, подобные следующим (из пример представленный Paul Snively at Strange Loop 2012):
// But these invalid sequences don't compile:
// isValid(_3 :: _1 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: _5 :: HNil)
// isValid(_3 :: _4 :: _5 :: _8 :: _8 :: _2 :: _8 :: _6 :: HNil)
Или это, из пример в Shapeless:
/**
* If we wanted to confirm that the list uniquely contains `Foo` or any
* subtype of `Foo`, we could first use `unifySubtypes` to upcast any
* subtypes of `Foo` in the list to `Foo`.
*
* The following would not compile, for example:
*/
//stuff.unifySubtypes[Foo].unique[Foo]
Это очень грубый способ указать некоторый факт о поведении этих методов, и мы могли бы предположить, что хотим сделать эти утверждения более формальными - для тестирования единиц или регрессий и т.д.
Чтобы дать конкретный пример того, почему это может быть полезно в контексте библиотеки типа Shapeless, несколько дней назад я написал следующее как быструю первую попытку ответа на этот вопрос:
import shapeless._
implicit class Uniqueable[L <: HList](l: L) {
def unique[A](implicit ev: FilterAux[L, A, A :: HNil]) = ev(l).head
}
Если намерение заключается в том, что это будет скомпилировано:
('a' :: 'b :: HNil).unique[Char]
Пока это не будет:
('a' :: 'b' :: HNil).unique[Char]
Я с удивлением обнаружил, что эта реализация типа unique
для HList
не работает, потому что Shapeless с радостью найдет экземпляр FilterAux
в последнем случае. Другими словами, следующее компиляция, хотя вы, вероятно, ожидаете, что это не будет:
implicitly[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]
В этом случае то, что я видел, было ошибка - или, по крайней мере, что-то ошибка - и это с тех пор было исправлено.
В более общем плане, мы можем предположить, что хотите проверить тип инварианта, который был скрыт в моих ожиданиях относительно того, как FilterAux
должен работать с чем-то вроде unit test - как ни странно, поскольку может показаться, что речь идет о типе тестирования, как и этот, со всеми недавними дебатами об относительном достоинстве типов против тестов.
Мой вопрос
Проблема в том, что я не знаю какой-либо структуры тестирования (для любой платформы), которая позволяет программисту утверждать, что что-то не должно компилироваться.
Один подход, который я могу себе представить для случая FilterAux
, - использовать старый трюк с неявным аргументом с нулевым значением:
def assertNoInstanceOf[T](implicit instance: T = null) = assert(instance == null)
Что бы вы могли написать следующее в unit test:
assertNoInstanceOf[FilterAux[Char :: Char :: HNil, Char, Char :: HNil]]
Следующее было бы более удобным и выразительным:
assertDoesntCompile(('a' :: 'b' :: HNil).unique[Char])
Я хочу это. Мой вопрос: знает ли кто-нибудь о какой-либо тестовой библиотеке или фреймворке, которая поддерживает что-либо удаленно, как это - идеально подходит для Scala, но я соглашусь на что-нибудь.