# 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

- discover what are the already recorded types, available for reuse
- register your own types so they can be checked dynamically wherever and whenever required
- 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

- a unique suffix
- a unique name
- 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

```
f$getRecordedTypes()[suffix == 'ui']
#> suffix type verify_function category
#> 1: ui unsigned integer <function> math
```

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

```
f$addSuffix('mc', 'MyClass', function(o_1_) is(o_1_, 'MyClass'))
#> [1] TRUE
f$getRecordedTypes()[suffix == 'mc']
#> suffix type verify_function category
#> 1: mc MyClass <function> user defined
```

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

```
f$getVerificationFunction('b')
#> function(o_1_) is.logical(o_1_) && !is.na(o_1_)
#> <bytecode: 0x000000001a674cc0>
#> <environment: 0x000000001a737758>
f$getVerificationFunction('logical')
#> function (x) .Primitive("is.logical")
```

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.

```
f$addSuffix('ui', 'unsigned integer', function(o_1_) f$getVerificationFunction('i')(o_1_) && o_1_ >= 0L)
#> [1] FALSE
f$addSuffix('ul', 'unsigned long' , f$getVerificationFunction('ui'))
#> [1] TRUE
f$getRecordedTypes()[suffix %in% c('ui', 'ul')]
#> suffix type verify_function category
#> 1: ui unsigned integer <function> math
#> 2: ul unsigned long <function> user defined
```

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.

## 4.6 Enforcing use of your own type factory

When you customized your own type factory, you need a way to tell wyz.code.offensiveProgramming to use it.
To do so, simply create your type factory and assign it to a R variable, and set environment variable **OP_TYPE_FACTORY** to point to the name of this R variable.
Let’s see an example

```
ff <- FunctionParameterTypeFactory()
ff$addSuffix('wo', "wo class", function(o_) is(o_, "wo"))
#> [1] TRUE
ff$addSuffix('yo', "yo class", function(o_) is(o_, "yo"))
#> [1] TRUE
ff$addSuffix('zo', "zo class", function(o_) is(o_, "zo"))
#> [1] TRUE
Sys.setenv("OP_TYPE_FACTORY" = "ff")
fg <- retrieveFactory() # retrieves the factory pointed by R variable ff
fg$getRecordedTypes()[suffix %in% c('wo', 'yo', 'zo')] # right behavior !
#> suffix type verify_function category
#> 1: wo wo class <function> user defined
#> 2: yo yo class <function> user defined
#> 3: zo zo class <function> user defined
# wrong behavior as retrieveFactory will provide the default factory and not yours!
Sys.setenv("OP_TYPE_FACTORY" = "")
fh <- retrieveFactory() # retrieves the default factory
fh$getRecordedTypes()[suffix %in% c('wo', 'yo', 'zo')]
#> Empty data.table (0 rows and 4 cols): suffix,type,verify_function,category
```