Интересный вопрос.
Является ли поведение в большей степени «Я хочу убедиться, что я реализую все необходимое», чем «Я хочу, чтобы все знали, что я реализую все необходимое»?
Мое понимание таковочто поведение - это контракт между автором модуля и пользователем этого модуля, который говорит: «Я ожидаю, что вы предоставите мне модуль, который может делать все эти вещи».Поэтому ответственность за это лежит на пользователе модуля.
Тот факт, что ключевым словом для функции поведения является @callback
, мне кажется, говорит о том, что обычно модуль, определяющий поведение, также является тем модулем, который будет использовать это поведение (другими словами, вызывая обратный вызов).).Похоже, что ответственность за реализацию поведения лежит на том, кто реализует поведение, с проверкой во время компиляции, чтобы помочь им, но нет никакой помощи во время выполнения для пользователя модуля, которому требуется поведение для выполненияЯ уверен, что они действительно предоставили правильную реализацию.
Ваше решение для предоставления предупреждения во время выполнения выглядит хорошо для меня - однако возможно реализовать поведение без предоставления атрибута @behaviour
, поэтому оно не будет работать вэтот случай.
Существует немного более полезное сообщение об ошибке, если разработчик поведения объявил @behaviour
в своем коде, но проигнорировал предупреждение компилятора:
предупреждение: требуется функция foo / 0по поведению ExpectBehaviour не реализовано (в модуле ClaimsItImplementsButDoesNot)
iex> ExpectBehaviour.use_behaviour(ClaimsItImplementsButDoesNot)
** (UndefinedFunctionError) function ClaimsItImplementsButDoesNot.foo/0 is undefined or private,
but the behaviour ExpectBehaviour expects it to be present
Однако это не тот случай, если вы просто передаете несвязанный модуль, который не реализует поведение:
iex> ExpectBehaviour.use_behaviour(DoesNotImplementOrClaimTo)
** (UndefinedFunctionError) function DoesNotImplementOrClaimTo.foo/0 is undefined or private
Есть ли способ использовать поведение как тип вtypespecs?
Поведение - это не тип, это спецификация набора функций, и модуль может реализовывать несколько поведений, поэтому я не думаю, что это имеет смысл.Как упомянуто выше, кажется разумным ограничивать использование обратных вызовов поведения ограниченным модулем, в котором он определен.