lewinfox / foodwebr

Function dependency graphs in R
http://www.lewinfox.com/foodwebr/
Other
20 stars 2 forks source link

`foodweb()` cannot differentiate identically-named functions and variables #2

Open lewinfox opened 3 years ago

lewinfox commented 3 years ago

If a variable in a function has the same name as another function, a link will be erroneously created.

f1 <- function() {
  1
}

f2 <- function() {
  f1 <- 10 # This variable `f1` will be confused with the function `f1()`
  2
}

# The foodweb mistakenly believes that function `f2()` calls function `f1()`
foodweb()
#> # A `foodweb`: 2 nodes and 1 edges
#> digraph 'foodweb' {
#>   f1()
#>   f2() -> { f1() }
#> }

We need to differentiate between the symbol f1 and the call f1().

raneam commented 2 years ago

Hey, is there a minimal reproducible example that you have? I can have a look to see if I understand anything.

This is what I tried.

f1 <- function() {
  1
}

f2 <- function() {
  f1 <- 10 # This variable `f1` will be confused with the function `f1()`
  2
}

foodweb <- function() {
  f1()
  f2() -> f1
}
foodweb() # Runs okay
f1() # Still returns 1
lewinfox commented 2 years ago

Hi @raneam! Thanks for taking an interest.

I think there's some confusion - you don't want to override the foodweb() function like you've done there. foodweb()'s job is to map out the interdependencies of all the functions in the environment and give you a graph of how they relate to one another.

This may be clearer - plot(foodweb()) will draw the call graph for you:

f1 <- function() {
  1
}

f2 <- function() {
  f1 <- 10 # This variable `f1` will be confused with the function `f1()`
  2
}

# The foodweb mistakenly believes that function `f2()` calls function `f1()`
plot(foodweb())

The problem isn't with what the functions themselves return, it's a problem with the foodweb graph. If you run the example at the top here you see that within function f2() the algorithm sees a variable f1 and assumes this is the same as the function f1().

The graph output then shows that f2() calls f1() when in reality it doesn't.

The correct output of foodweb() for the example would be

#> # A `foodweb`: 2 nodes and 1 edges
#> digraph 'foodweb' {
#>   f1()
#>   f2()
#> }

i.e. two totally unconnected functions. My ASCII art skills are limited but plot(foodweb()) should give you two blobs with no connecting lines at all.

+------+    +------+
| f1() |    | f2() |
+------+    +------+

Does that make sense?