TypeCheck v0.2.0 TypeCheck.Macros View Source

Contains the @spec!, @type!, @typep!, @opaque! macros to define runtime-checked function- and type-specifications.

Usage

This module is included by calling use TypeCheck. This will set up the module to use the special macros.

Usually you'll want to use the module attribute-style of the macros, like @spec! and @type!. Using these forms has two advantages over using the direct calls:

  1. Syntax highlighting will highlight the types correctly and the Elixir formatter will not mess with the way you write your type.
  2. It is clear to people who have not heard of TypeCheck before that @type! and @spec! will work similarly to resp. @type and @spec.

Avoiding naming conflicts with TypeCheck.Builtin

If you want to define a type with the same name as one in TypeCheck.Builtin, (which is not particularly recommended), you should hide those particular functions from TypeCheck.Builtin by adding import TypeCheck.Builtin, except: [...] below use TypeCheck manually.

Calling the explicit implementations

In case you are working in an environment where the @/1 is already overridden by another library, you can still use this library, by simply adding import TypeCheck.Macros, except: [@: 1] to your module and calling the direct versions of the macros instead.

Link to this section Summary

Functions

Define a opaque type specification.

Define a function specification.

Define a public type specification.

Define a private type specification.

Link to this section Functions

Link to this macro

opaque!(typedef)

View Source (macro)

Define a opaque type specification.

Usually invoked as @opaque!

This behaves similarly to Elixir's builtin @opaque attribute, and will create a type whose name is public but whose structure is private.

Calling this macro will:

  • Fill the @opaque-attribute with a Typespec-friendly representation of the TypeCheck type.
  • Add a (or append to an already existing) @typedoc detailing that the type is managed by TypeCheck, and containing the name of the TypeCheck type. (not the definition, since it is an opaque type).
  • Define a (hidden) public function with the same name (and arity) as the type that returns the TypeCheck.Type as a datastructure when called. This makes the type usable in calls to:

opaque!/1 accepts the same typedef expression as type!/1.

Link to this macro

spec!(specdef)

View Source (macro)

Define a function specification.

Usually invoked as @spec!

A function specification will wrap the function with checks that each of its parameters are of the types it expects. as well as checking that the return type is as expected.

Usage

The syntax is essentially the same as for built-in @spec attributes:

@spec! function_name(type1, type2) :: return_type

It is also allowed to introduce named types:

@spec! days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer

Note that TypeCheck does not allow the when keyword to be used to restrict the types of recurring type variables (which Elixir's builtin Typespecs allow). This is because:

  • Usually it is more clear to give a recurring type an explicit name.
  • The when keyword is used instead for TypeCheck's type guards'. (See TypeCheck.Builtin.guarded_by/2 for more information.)
Link to this macro

type!(typedef)

View Source (macro)

Define a public type specification.

Usually invoked as @type!

This behaves similarly to Elixir's builtin @type attribute, and will create a type whose name and definition are public.

Calling this macro will:

  • Fill the @type-attribute with a Typespec-friendly representation of the TypeCheck type.
  • Add a (or append to an already existing) @typedoc detailing that the type is managed by TypeCheck, and containing the full definition of the TypeCheck type.
  • Define a (hidden) public function with the same name (and arity) as the type that returns the TypeCheck.Type as a datastructure when called. This makes the type usable in calls to:

Usage

The syntax is essentially the same as for the built-in @type attribute:

@type! type_name :: type_description

It is possible to create parameterized types as well:

@type! dict(key, value) :: [{key, value}]

Named types

You can also introduce named types:

@type! color :: {red :: integer, green :: integer, blue :: integer}

Not only is this nice to document that the same type is being used for different purposes, it can also be used with a 'type guard' to add custom checks to your type specifications:

@type! sorted_pair(a, b) :: {first :: a, second :: b} when first <= second
Link to this macro

typep!(typedef)

View Source (macro)

Define a private type specification.

Usually invoked as @typep!

This behaves similarly to Elixir's builtin @typep attribute, and will create a type whose name and structure is private (therefore only usable in the current module).

  • Fill the @typep-attribute with a Typespec-friendly representation of the TypeCheck type.
  • Define a private function with the same name (and arity) as the type that returns the TypeCheck.Type as a datastructure when called. This makes the type usable in calls (in the same module) to:

typep!/1 accepts the same typedef expression as type!/1.