7 Running functions

Our goal is to run a R instrumented function, under a given evaluation mode. To do so, some prerequisites have to be met, prior to use some wyz.code.offensiveProgramming utilities to proceed to the function execution with context capture and human-readable feedback generation.

7.1 Prerequisites

To run a R function is has to be instrumented. Two requirements have to be met

  1. the function must comply with semantic parameter naming
  2. the function return type must be specified

7.2 Function return types definition verification

To verify function return types definition you may use the low level function verifyFunctionReturnTypesDefinition or the higher level one named retrieveFunctionReturnTypes. Indeed, this approach requires persistent instrumentation of the code.

7.3 Transient invocations

Transient means instrumentation is done dynamically and not persisted anywhere. Here is a typical case. That’s a convenient way to discover and to play with package wyz.code.offensiveProgramming.

7.3.1 Nominal case

To get the definition for ‘emo’ variable, please refer to 6.

Semantically, function h takes a vector of strings as argument and returns a vector of strings. As provided parameter ‘neonira’ is a vector of type character, parameter_type_checks succeed. As returned value is a vector of type character, function_return_type_check also succeeds.

7.3.1.1 Wrong parameter type

Let’s change the provided argument from ‘neonira’ to pi value.

We now face a case where function specification is unchanged but provided argument is not complying to specification. Impact is parameter_type_checks failure and function_return_type_check failure.

7.3.1.2 Change expected return type

Let’s change the expected function return type, to be double x_d.

We now face a case where function specification is unchanged but expected return type is expected to be a double. Provided argument is not complying to specification. Impact is parameter_type_checks failure.

7.3.3 Object function call

What if the function you desire to call is an object function? In such a case, be sure to pass the object as first parameter of the list of parameters, as shown by example below, based on a S3 object. A priori, all kind of R objects are supported: S3, S4, RC, R6 and environment objects.

library(data.table)
source(file.path(system.file(package = 'wyz.code.offensiveProgramming'), 'code-samples',
       'both-defs/good/partial', 'Addition_TCFI_Partial_S3.R'), encoding = 'UTF-8')
a <- Addition_TCFI_Partial_S3()
runTransientFunction(addInteger.Addition_TCFI_Partial_S3, list(a, 3L, 4L), emo$type, 'x_i')
#> $status
#> [1] FALSE
#> 
#> $value
#> [1] 7
#> 
#> $mode
#> [1] "type_checking_enforcement"
#> 
#> $parameter_type_checks
#>    parameter_name            parameter_value validity
#> 1:     object_o_1 <Addition_TCFI_Partial_S3>    FALSE
#> 2:            x_i                          3     TRUE
#> 3:            y_i                          4     TRUE
#>                                      message
#> 1: wrong length, was expecting [1] , got [3]
#> 2:                       good type in values
#> 3:                       good type in values
#> 
#> $function_return_type_check
#>    parameter_name parameter_value validity             message
#> 1:            x_i               7     TRUE good type in values

runTransientFunction(addInteger.Addition_TCFI_Partial_S3, list(NULL, 3L, 4L), emo$type, 'x_i')
#> $status
#> [1] FALSE
#> 
#> $value
#> [1] 7
#> 
#> $mode
#> [1] "type_checking_enforcement"
#> 
#> $parameter_type_checks
#>    parameter_name parameter_value validity
#> 1:     object_o_1                    FALSE
#> 2:            x_i               3     TRUE
#> 3:            y_i               4     TRUE
#>                                      message
#> 1: wrong length, was expecting [1] , got [0]
#> 2:                       good type in values
#> 3:                       good type in values
#> 
#> $function_return_type_check
#>    parameter_name parameter_value validity             message
#> 1:            x_i               7     TRUE good type in values

print(ls())
#>  [1] "a"                                        
#>  [2] "addDouble.Addition_TCFI_Partial_S3"       
#>  [3] "addInteger"                               
#>  [4] "addInteger.Addition_TCFI_Partial_S3"      
#>  [5] "Addition"                                 
#>  [6] "Addition_TCFI_Partial_S3"                 
#>  [7] "AdditionTCFIG1"                           
#>  [8] "addNumeric"                               
#>  [9] "addNumeric.Addition_TCFI_Partial_S3"      
#> [10] "divideByZero.Addition_TCFI_Partial_S3"    
#> [11] "em"                                       
#> [12] "emo"                                      
#> [13] "f"                                        
#> [14] "ff"                                       
#> [15] "fg"                                       
#> [16] "fh"                                       
#> [17] "g"                                        
#> [18] "generateError"                            
#> [19] "generateError.Addition_TCFI_Partial_S3"   
#> [20] "generateWarning.Addition_TCFI_Partial_S3" 
#> [21] "generateWarning2"                         
#> [22] "generateWarning2.Addition_TCFI_Partial_S3"
#> [23] "h"                                        
#> [24] "MathOperation"                            
#> [25] "mo"

#runTransientFunction(addInteger, list(a, 3L, 4L), emo$type, 'x_i')

7.4 Persistent invocations

Transient invocations are convenient but limited. Especially, when you create classes, they do not appear to be as friendly and useful as necessary. When dealing with your own class code, you may opt for an easier and more industrial approach that is class instrumentation. Prerequisite remains the same, but you may fulfill them much more easily by defining a variable named function_return_type in your class. Let’s see an example.