4 The type factory

The types that you wish to control are managed by a type factory, named FunctionParameterTypeFactory. Instantiating an object of this class allows you to

  1. discover what are the already recorded types, available for reuse
  2. register your own types so they can be checked dynamically wherever and whenever required
  3. understand the verification logic for each type

4.1 Get recorded types inventory

Simply use retrieveFactory and getRecordedTypes function. It returns a data.table, that you can filter out conveniently.

Here is an example.

f <- retrieveFactory()
f$getRecordedTypes()
#>     suffix             type verify_function         category
#>  1:      a            array      <function>   data structure
#>  2:      b          boolean      <function>             math
#>  3:      c          complex      <function>          numeric
#>  4:     ca             call      <function>         language
#>  5:     ch        character      <function>            basic
#>  6:     cm     complex-math      <function>             math
#>  7:      d           double      <function>          numeric
#>  8:     da             date      <function>             date
#>  9:     dc          POSIXct      <function>             date
#> 10:     df       data.frame      <function>   data structure
#> 11:     dl          POSIXlt      <function>             date
#> 12:     dm      double-math      <function>             math
#> 13:     dt       data.table      <function>   data structure
#> 14:      e      environment      <function>            basic
#> 15:     er            error      <function> error management
#> 16:     ex       expression      <function>         language
#> 17:      f         function      <function>            basic
#> 18:     fa           factor      <function>            basic
#> 19:      i          integer      <function>          numeric
#> 20:     im     integer-math      <function>             math
#> 21:      l             list      <function>   data structure
#> 22:     lo          logical      <function>            basic
#> 23:      m           matrix      <function>   data structure
#> 24:      n          numeric      <function>          numeric
#> 25:     na               na      <function>            basic
#> 26:     ni negative integer      <function>             math
#> 27:     nm             name      <function>         language
#> 28:     nr    negative real      <function>             math
#> 29:      o           object      <function>            basic
#> 30:     pi positive integer      <function>             math
#> 31:     pr    positive real      <function>             math
#> 32:      r        real-math      <function>             math
#> 33:     ra              raw      <function>            basic
#> 34:     rm  real-math alias      <function>             math
#> 35:      s           string      <function>            basic
#> 36:      t            table      <function>   data structure
#> 37:     ui unsigned integer      <function>             math
#> 38:     ur    unsigned real      <function>             math
#> 39:      w          warning      <function> error management
#>     suffix             type verify_function         category

4.2 Understanding the model

A type is defined by three elements

  1. a unique suffix
  2. a unique name
  3. a function that returns a boolean value, TRUE when examining a value that matches the type

For example, you might wonder what means ui as a suffix

What is the function related to suffix ui?

4.3 Register your own type

Type registration is achieved by providing a type suffix, a type name and a verification function. Registration will be tagged automatically as user-defined. Here is a typical sequence to register your own type

Note that no implementation of the class is required. It is purely declarative registration. You told the type factory to record the type MyClass under the suffix mc, with the verification function you provided. Here verification function is quite simple. Notice that it takes a single object as argument.

4.4 Get access to verification functions

Implementation of verification function can range from quite simple to as complex as required. This allows you to manage functional scopes much more easily, whatever you work and organization context.

For example, if you want to see at a glance the differences between a boolean and a logical, here is the sequence you could use

From the two definitions, you can deduce the differences between the two types. A boolean is a 2-value boolean, either TRUE or FALSE. A logical, is a R logical value, that is a 3-value boolean, so it may take value NA.

Note that arguments to the function getVerificationFunction can be either a registered suffix or a registered type.

4.5 Some hints

There is currently no way to remove one recorded type. This need is indeed very specific and arise only when there is a name collision and you wish to use an already taken name for your own purpose.

Solution is quite simple, use another name. Provided types are the most commons, and the current suffixes have been chosen for ease of use and for intuitive usage.

Whenever you need to register a new type, ask yourself ‘what is the suffix I wish to use for the new type?’. My advice is to use short suffixes, made of 2 or 3 letters. That’s clearly sufficient to distinguish your type from others. Know that there is not limitation to the length of the suffix you can use. Simply, comply with KISS, as you will have to type it several times, probably.

If you come from another programming language, you may consider to create aliased types by recording new entries. Let’s look at a concrete case.

You asked to add two new entries in the type factory, and they share the same verification function. First add fails, second one succeeds. The reason is that ui suffix is already defined and you cannot redefine an already defined suffix.

Now, ui and ul are aliases of the same verification function. Notice that this is true now, and cannot be changed once created. Indeed, you always have the opportunity to create a new type factory to match your new need. You can use as many type factories as you want.

The term alias shall not be understood, as an authorization to use one name for the other, but rather as an ability to define quickly new types to ease functional scope management.