5 Semantic names
Package wyz.code.offensiveProgramming offers great functionalities at the cost of a few conditions
- semantic naming has to be used for function parameters names
- semantic naming has to be used for function return type definition
- semantic naming has to be used for 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.
Semantic naming in package wyz.code.offensiveProgramming defines a few patterns to declare class, function, function parameters and function return type names. Table below shows the related patterns and exposes the underlying philosophy.
name category | philosophy | pattern to comply with |
---|---|---|
class | java like, starts with upper-cased letter, camel-cased | [A-Z][a-ZA-Z0-9]* |
function | java like, starts with lower-cased letter, camel-cased | [a-z][a-ZA-Z0-9]* |
function parameter or function return type | R like, bearing information about type and length constraint | See below. |
Function parameter or return type names must comply with one of the following patterns
- <variableNameCamelCase>_<typeInformation>_<lengthConstraint>
- <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.
The type information part of the pattern has to match one of the recorded entries of the type factory.
The length constraint part ot 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.
Look at following table to get more intuitive traction on function parameter or function return type declarations.
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 |
As you can see, rather easy. An advice, when programming try to use meaningful variable names for first part of the pattern. It will ease your job.
5.2 Verifying a function parameter or return type declaration
Use simply dedicated function named getTypeDescription from the type factory.
sapply(c('x_s_3n', 'flag_b_1', 'z_2_'), function(e) f$getTypeDescription(FunctionParameterName(e)))
#> x_s_3n
#> "A constrained vector of string values. Vector length must be 1 or 3."
#> flag_b_1
#> "A constrained vector of boolean objects. Vector length must be 1."
#> z_2_
#> "A constrained vector of variable type objects. Vector length must be 2."
5.3 Verifying a class name
Simply use package eponymous function.
5.4 Verifying a function name
Simply use package eponymous function.
verifyFunctionName(c('alphaBetaGamma', 'AlphaBetaGamma', '.alphaBetaGamma'))
#> alphaBetaGamma AlphaBetaGamma .alphaBetaGamma
#> TRUE FALSE FALSE
verifyFunctionName(c('alphaBetaGamma', 'AlphaBetaGamma', '.alphaBetaGamma'), strict = FALSE)
#> alphaBetaGamma AlphaBetaGamma .alphaBetaGamma
#> TRUE TRUE TRUE
5.5 Get naming balance from an R object
Use package function verifyObjectNames to get the results of a full compliance analysis of names for the provided object.
source(system.file('code-samples/no-defs/Addition.R', package = 'wyz.code.offensiveProgramming'))
verifyObjectNames(Addition())
#> $class_name_compliance
#> Addition
#> TRUE
#>
#> $function_name_compliance
#> addDouble addInteger addNumeric divideByZero
#> TRUE TRUE TRUE TRUE
#> generateError generateWarning
#> TRUE TRUE
#>
#> $parameter_name_compliance
#> function_name parameter_name name_compliance_check
#> 1: addDouble x_d TRUE
#> 2: addDouble y_d TRUE
#> 3: addInteger x_i TRUE
#> 4: addInteger y_i TRUE
#> 5: addNumeric x FALSE
#> 6: addNumeric y_n TRUE
#> 7: divideByZero x_n TRUE
#> 8: generateError <NA> TRUE
#> 9: generateWarning x_ TRUE
#> semantic_naming_check
#> 1: TRUE
#> 2: TRUE
#> 3: TRUE
#> 4: TRUE
#> 5: FALSE
#> 6: TRUE
#> 7: TRUE
#> 8: TRUE
#> 9: TRUE
#>
#> $classname
#> [1] "Addition"
#>
#> $owns_function_return_type_information
#> [1] FALSE
#>
#> $owns_test_case_definitions
#> [1] FALSE
#>
#> $supports_strict_compliance
#> [1] FALSE
#>
#> $supports_lazy_compliance
#> [1] FALSE
#>
#> $can_be_typed_checked
#> [1] FALSE
#>
#> $is_function_fully_instrumented
#> [1] FALSE
#>
#> $missing_functions
#> [1] NA
#>
#> $is_test_case_fully_instrumented
#> [1] FALSE
#>
#> $missing_test_cases
#> [1] NA
#>
#> $sof
#> $sof$frt
#> [1] FALSE
#>
#> $sof$tcd
#> [1] FALSE
#>
#> $sof$instrumented_fn
#> NULL
#>
#> $sof$instrumented_tc
#> NULL
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
#> TRUE TRUE TRUE TRUE
#> divideByZero generateError generateWarning
#> TRUE TRUE TRUE
#>
#> $parameter_name_compliance
#> function_name parameter_name name_compliance_check
#> 1: addDouble x_d TRUE
#> 2: addDouble y_d TRUE
#> 3: addInteger x_i TRUE
#> 4: addInteger y_i TRUE
#> 5: addMultiDouble ... TRUE
#> 6: addMultiInteger x_i TRUE
#> 7: addMultiInteger ... TRUE
#> 8: divideByZero x_n TRUE
#> 9: generateError <NA> TRUE
#> 10: generateWarning x_ TRUE
#> semantic_naming_check
#> 1: TRUE
#> 2: TRUE
#> 3: TRUE
#> 4: TRUE
#> 5: TRUE
#> 6: TRUE
#> 7: TRUE
#> 8: TRUE
#> 9: TRUE
#> 10: 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