switch_lang() dispatches clauses based on the subtype of call, as determined by lang_type_of(). The subtypes are based on the type of call head (see details).

switch_lang(.x, ...)

coerce_lang(.x, .to, ...)

lang_type_of(x)

Arguments

.x, x

A language object (a call). If a formula quote, the RHS is extracted first.

...

Named clauses. The names should be types as returned by lang_type_of().

.to

This is useful when you switchpatch within a coercing function. If supplied, this should be a string indicating the target type. A catch-all clause is then added to signal an error stating the conversion failure. This type is prettified unless .to inherits from the S3 class "AsIs" (see base::I()).

Details

Calls (objects of type language) do not necessarily call a named function. They can also call an anonymous function or the result of some other expression. The language subtypes are organised around the kind of object being called:

  • For regular calls to named function, switch_lang() returns "named".

  • Sometimes the function being called is the result of another function call, e.g. foo()(), or the result of another subsetting call, e.g. foo$bar() or foo@bar(). In this case, the call head is not a symbol, it is another call (e.g. to the infix functions $ or @). The call subtype is said to be "recursive".

  • A special subset of recursive calls are namespaced calls like foo::bar(). switch_lang() returns "namespaced" for these calls. It is generally a good idea if your function treats bar() and foo::bar() similarly.

  • Finally, it is possible to have a literal (see is_expr() for a definition of literals) as call head. In most cases, this will be a function inlined in the call (this is sometimes an expedient way of dealing with scoping issues). For calls with a literal node head, switch_lang() returns "inlined". Note that if a call head contains a literal that is not function, something went wrong and using that object will probably make R crash. switch_lang() issues an error in this case.

The reason we use the term node head is because calls are structured as tree objects. This makes sense because the best representation for language code is a parse tree, with the tree hierarchy determined by the order of operations. See pairlist for more on this.

Examples

# Named calls: lang_type_of(~foo())
#> [1] "named"
# Recursive calls: lang_type_of(~foo$bar())
#> [1] "recursive"
lang_type_of(~foo()())
#> [1] "recursive"
# Namespaced calls: lang_type_of(~base::list())
#> [1] "namespaced"
# For an inlined call, let's inline a function in the head node: call <- quote(foo(letters)) call[[1]] <- base::toupper call
#> (function (x) #> { #> if (!is.character(x)) #> x <- as.character(x) #> .Internal(toupper(x)) #> })(letters)
lang_type_of(call)
#> [1] "inlined"