futureverse / futureverse/globals

findGlobals(): Distinguish between functions and non-functions

Open
#95 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
R
Stars
29
Forks
3
PR merge metrics
No merged PRs in 30d

Description

Below is an example, where a local numeric variable `sum` is picked up by `globalsOf()`, despite the expression uses a function `sum()`.

```r
sum <- 42
expr <- quote( sum(1:10) )

names <- globals::findGlobals(expr)
print(names)
#> "{" "sum" ":"

objs <- globals::globalsOf(expr)
str(objs)
#> List of 3
#> $ { :.Primitive("{")
#> $ sum: num 42
#> $ : :.Primitive(":")
#> - attr(*, "where")=List of 3
#> ..$ { :
#> ..$ sum:
#> ..$ : :
#> - attr(*, "class")= chr [1:2] "Globals" "list"
```

Ideally, `globalsOf()` would pick up `base::sum()` instead. For that to happen, we need to refine `globals::findGlobals()` to record whether symbol `sum` refers to a function or not. That could be achieved by `findGlobals()` inspect the language object that `sum` is part of. For instance, from:

```
expr <- quote( sum(1:10) )
str(list(first = expr[[1]], class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 4
#> $ first : symbol sum
#> $ class : chr "call"
#> $ typeof: chr "language"
#> $ length: int 2

expr <- quote( sum )
str(list(class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 3
#> $ class : chr "name"
#> $ typeof: chr "symbol"
#> $ length: int 1

## But it's not that easy

expr <- quote( sum + 2 )
str(list(first = expr[[1]], class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 4
$ first : symbol +
#> $ class : chr "call"
#> $ typeof: chr "language"
#> $ length: int 3

expr <- quote( -sum )
str(list(first = expr[[1]], class = class(expr), typeof = typeof(expr), length = length(expr)))
#> List of 4
$ first : symbol -
#> $ class : chr "call"
#> $ typeof: chr "language"
#> $ length: int 2
```

we see that we can infer when symbol `sum` is the name of a function call or not.

One could have `findGlobals(expr, annotate = TRUE)` return this information as well, e.g. as attributes. But, is that shoehorning the original design of **globals** to much, which is basically an enhancement of **codetools**? It would be worth investigating if there are better AST tools for what's trying to be achieved. OTH, the above improvement might be good enough for 99% of the use cases.

Contributor guide

Open the contributing guide

Research direction

Start by reading the existing findGlobals() and globalsOf() entry points and tracing how symbols in quoted calls are classified. Compare function-position symbols with value-position symbols using the sum(), sum, sum + 2, and -sum examples from the issue. Done means the function call resolves to base::sum() without incorrectly treating a same-named local numeric variable as the global function.

Written by the indexing model from the issue text.

Assessment

Tech stack
r
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.