5 Semantic names

Package wyz.code.offensiveProgramming enforces semantic naming to offer great functionalities. Semantic naming come at the cost of few conditions. It has to be used for

  1. function parameters names
  2. function return type definition
  3. test case definitions

5.1 What is semantic naming?

I call semantic naming, the fact that a named object used in the code should provide much more information than a dumb name.

5.1.1 Naming recommendation

Naming conventions are recommendations. You may follow them strictly or lazily. This has some consequences on the checks you will have to run as you will have to know under which mode you work.

Package wyz.code.offensiveProgramming defines a few naming recommendations to declare class, function, function parameters and code variable names. Table below shows them and exposes the underlying philosophy.

name category philosophy pattern to comply with
class starts with upper-cased letter, camel-cased [A-Z][a-ZA-Z0-9]*
function starts with lower-cased letter, camel-cased [a-z][a-ZA-Z0-9]*
function parameter See below next chapter
code variable snake-cased [a-z]+([a-z]+)*

5.1.2 Semantic naming

Semantic naming is required on function parameter names and on return type names. Each semantic name must comply with one of the following patterns.

  1. <variableNameCamelCase>_<typeInformation>_<lengthConstraint>
  2. <variableNameCamelCase>_<lengthConstraint>_

First pattern is to be used for monomorphic types. Second one for polymorphic types.

Monomorphic types are types that are homogeneous. A string, a double, a MyObject are good example of such monomorphic types. Pattern allows to not only express concisely the type, but also to express some length constraints if needed.

Polymorphic types are useful as soon as your input or output can take many types, according to your context. For example, a R function may return a double, or a warning, or an error. Polymorphic types always end with ’_’ in their names, to make them easy to identify.

5.1.2.1 Type part of semantic naming

The type information part of the pattern has to match one suffix of the recorded entries of the type factory.

5.1.2.2 Length part of semantic naming

The length constraint part of the pattern follows the PERL pattern ([1-9][0-9]*(l|m|n)?). Letters mean respectively less or equal, more or equal, 1 or n. The length constraint part is optional.

5.1.2.3 Examples of semantic names

Look at following table to get more intuitive traction of semantic names. That’s easy to understand and to use.

input name meaning
x_s an unconstrained vector of strings - might contain no entries
x_s_3 a vector of strings with 3 entries
x_s_3l a vector of strings with 3 or less entries
x_s_3m a vector of strings with 3 or more entries
x_s_3n a vector of strings with 3 entries or 1 entry
flag_b_1 a vector of booleans with 1 entry - a.k.a a boolean scalar
z_ an unconstrained polymorphic type vector named z - Nothing more is known about its content
z_2_ a polymorphic type vector named z of length 2 - Nothing more is known about its content

It is often advised when programming to use meaningful variable names. That’s hold true with semantic naming, but is far less critical. Here I used x or z as variable names, without any sacrifice of semantic naming due to the patterns I used. Indeed, using more contextually meaningful names should have even been a greater approach.

5.2 Verifying names

5.2.1 Verifying a function parameter or return type declaration

The function getTypeDescription from the type factory turns your semantic name into a human readable definition. It is a convenient way to verify your definition matches your need. It is also used to generate documentation for function parameter names.

5.2.2 Verifying a class name

Simply use function verifyClassName. Remind to set parameter strict according to your compliance to semantic naming. Use TRUE for strict compliance, FALSE for mazy compliance.

5.2.3 Verifying a function name

Simply use function verifyFunctionName. Remind to set parameter strict according to your compliance to semantic naming. Use TRUE for strict compliance, FALSE for mazy compliance.

5.2.4 Get naming balance from an R object

Use function verifyObjectNames to get the results of a full semantic naming compliance analysis of names for the provided object. This analysis tries both strict and lazy compliance to provide results.

source(system.file('code-samples/both-defs/good/full/AdditionTCFIG1.R', 
                   package = 'wyz.code.offensiveProgramming'))
verifyObjectNames(AdditionTCFIG1())
#> $class_name_compliance
#> AdditionTCFIG1 
#>           TRUE 
#> 
#> $function_name_compliance
#>       addDouble      addInteger  addMultiDouble addMultiInteger    divideByZero 
#>            TRUE            TRUE            TRUE            TRUE            TRUE 
#>   generateError generateWarning 
#>            TRUE            TRUE 
#> 
#> $parameter_name_compliance
#>       function_name parameter_name name_compliance_check semantic_naming_check
#>  1:       addDouble            x_d                  TRUE                  TRUE
#>  2:       addDouble            y_d                  TRUE                  TRUE
#>  3:      addInteger            x_i                  TRUE                  TRUE
#>  4:      addInteger            y_i                  TRUE                  TRUE
#>  5:  addMultiDouble            ...                  TRUE                  TRUE
#>  6: addMultiInteger            x_i                  TRUE                  TRUE
#>  7: addMultiInteger            ...                  TRUE                  TRUE
#>  8:    divideByZero            x_n                  TRUE                  TRUE
#>  9:   generateError           <NA>                  TRUE                  TRUE
#> 10: generateWarning             x_                  TRUE                  TRUE
#> 
#> $classname
#> [1] "AdditionTCFIG1"
#> 
#> $owns_function_return_type_information
#> [1] TRUE
#> 
#> $owns_test_case_definitions
#> [1] TRUE
#> 
#> $supports_strict_compliance
#> [1] TRUE
#> 
#> $supports_lazy_compliance
#> [1] TRUE
#> 
#> $can_be_typed_checked
#> [1] TRUE
#> 
#> $is_function_fully_instrumented
#> [1] TRUE
#> 
#> $missing_functions
#> [1] "none"
#> 
#> $is_test_case_fully_instrumented
#> [1] TRUE
#> 
#> $missing_test_cases
#> [1] "none"
#> 
#> $sof
#> $sof$frt
#> [1] TRUE
#> 
#> $sof$tcd
#> [1] TRUE
#> 
#> $sof$instrumented_fn
#>      function_name return_value
#> 1:       addDouble          x_d
#> 2:      addInteger          x_i
#> 3:  addMultiDouble          x_d
#> 4:    divideByZero          x_d
#> 5: addMultiInteger          x_i
#> 6: generateWarning          x_w
#> 7:   generateError         x_er
#> 
#> $sof$instrumented_tc
#>       function_name standard_evaluation type_checking_enforcement
#>  1:       addDouble             correct                   correct
#>  2:       addDouble             correct                   correct
#>  3:       addDouble             correct                   correct
#>  4:       addDouble             correct                   correct
#>  5:       addDouble             correct                   correct
#>  6:       addDouble           erroneous                 erroneous
#>  7:       addDouble             correct                   failure
#>  8:       addDouble             correct                   failure
#>  9:       addDouble             correct                   failure
#> 10:      addInteger             correct                   correct
#> 11:      addInteger             correct                   correct
#> 12:      addInteger             correct                   correct
#> 13:      addInteger             correct                   correct
#> 14:      addInteger           erroneous                   failure
#> 15:      addInteger             correct                   failure
#> 16:      addInteger             correct                   failure
#> 17:      addInteger             correct                   failure
#> 18:      addInteger             correct                   failure
#> 19:    divideByZero             correct                   correct
#> 20:    divideByZero             correct                   correct
#> 21:    divideByZero             correct                   correct
#> 22: generateWarning             correct                   correct
#> 23:   generateError             failure                   failure
#> 24:  addMultiDouble             correct                   correct
#> 25:  addMultiDouble             correct                   correct
#> 26:  addMultiDouble             correct                   correct
#> 27: addMultiInteger             correct                   correct
#> 28: addMultiInteger             correct                   failure
#> 29: addMultiInteger             correct                   correct
#>       function_name standard_evaluation type_checking_enforcement
#>                test_case
#>  1: <TestCaseDefinition>
#>  2: <TestCaseDefinition>
#>  3: <TestCaseDefinition>
#>  4: <TestCaseDefinition>
#>  5: <TestCaseDefinition>
#>  6: <TestCaseDefinition>
#>  7: <TestCaseDefinition>
#>  8: <TestCaseDefinition>
#>  9: <TestCaseDefinition>
#> 10: <TestCaseDefinition>
#> 11: <TestCaseDefinition>
#> 12: <TestCaseDefinition>
#> 13: <TestCaseDefinition>
#> 14: <TestCaseDefinition>
#> 15: <TestCaseDefinition>
#> 16: <TestCaseDefinition>
#> 17: <TestCaseDefinition>
#> 18: <TestCaseDefinition>
#> 19: <TestCaseDefinition>
#> 20: <TestCaseDefinition>
#> 21: <TestCaseDefinition>
#> 22: <TestCaseDefinition>
#> 23: <TestCaseDefinition>
#> 24: <TestCaseDefinition>
#> 25: <TestCaseDefinition>
#> 26: <TestCaseDefinition>
#> 27: <TestCaseDefinition>
#> 28: <TestCaseDefinition>
#> 29: <TestCaseDefinition>
#>                test_case