Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding Global Variables

I'd like to make a basic profiling tool that collects time stamps and produces run times with a note. The only problem is I'm having trouble figuring out how to do this without using global variables. What's the "correct" way to implement the functionality I'm trying to achieve? If R already has this functionality built in, that's awesome, but what I'm really trying to figure out here is how to avoid using global variables and write more robust code.

timeStamps = c()
runTimes = list()

appendRunTimes <- function(note) {
  if(length(timeStamps) < 1) {
    timeStamps <<- Sys.time()
  }
  else {
    timeStamps <<- c(timeStamps, Sys.time())
    diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
    runTimes <<- c(runTimes,  format(diff))
    names(runTimes)[length(runTimes)] <<-  note
  }

}


appendRunTimes('start')
Sys.sleep(4)
appendRunTimes('test')
like image 502
user1949984 Avatar asked Jan 04 '13 22:01

user1949984


People also ask

Should I avoid global variables Python?

Never write 'global'. Then you are sure you are not introducing any global variables. This is very good advice--you basically never need this keyword.

What should I use instead of global variables?

In a scenario, where you need one central global point of access across the codebase, singletons are a good alternative for global variables. We can call a singleton as a lazily initialized global class which is useful when you have large objects — memory allocation can be deferred till when it's actually needed.

Why are global variables so bad?

Non-const global variables are evil because their value can be changed by any function. Using global variables reduces the modularity and flexibility of the program. It is suggested not to use global variables in the program. Instead of using global variables, use local variables in the program.

What can be done in order to avoid creating global variables in JavaScript?

Solution(By Examveda Team) One way for a module to avoid the creation of global variables is to use an object as its namespace. Instead of defining global functions and variables, it stores the functions and values as properties of an object (which may be referenced to a global variable).


2 Answers

Here's your example rewritten using closures:

RTmonitor <- local({
  timeStamps = c()
  runTimes = list()

  list(
    appendRunTimes=function(note) {
      if(length(timeStamps) < 1) {
        timeStamps <<- Sys.time()
      }
      else {
        timeStamps <<- c(timeStamps, Sys.time())
        diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
        runTimes <<- c(runTimes,  format(diff))
        names(runTimes)[length(runTimes)] <<-  note
      }
    },
    viewRunTimes=function() {
      return(list(timeStamps=timeStamps,runTimes=runTimes))
    })
})


> RTmonitor$appendRunTimes("start")
> RTmonitor$appendRunTimes("test")
> RTmonitor$viewRunTimes()
$timeStamps
[1] "2013-01-04 18:39:12 EST" "2013-01-04 18:39:21 EST"

$runTimes
$runTimes$test
[1] "8.855587 secs"

Observe that the values are stored inside the closure, not in the global environment:

> timeStamps
Error: object 'timeStamps' not found
> runTimes
Error: object 'runTimes' not found
> RTmonitor$timeStamps
NULL
> RTmonitor$runTimes
NULL

More reading on closures and avoiding globals:

  • Closures as solution to data merging idiom
  • How does local() differ from other approaches to closure in R?
  • Why is using `<<-` frowned upon and how can I avoid it?
  • Examples of the perils of globals in R and Stata
like image 53
Ari B. Friedman Avatar answered Oct 25 '22 13:10

Ari B. Friedman


Here's now to do this using ReferenceClasses:

RTmonitor = setRefClass("RTmonitor",
  fields=list(
    timeStamps="POSIXct",
    runTimes = "list"
    ),
  methods=list(
    appendRunTimes=function(note){
      if(length(timeStamps)==0){
        timeStamps <<- Sys.time()
      }else{
        timeStamps <<- c(timeStamps, Sys.time())
        diff <- timeStamps[length(timeStamps) ] - timeStamps[length(timeStamps) - 1]
        runTimes <<- c(runTimes,  format(diff))
        names(runTimes)[length(runTimes)] <<-  note
      }
    }
    )
  )

Now you've defined a class, instantiate an object and use it:

> r = RTmonitor$new()
> r$appendRunTimes("start")
> r$appendRunTimes("test")
> r
Reference class object of class "RTmonitor"
Field "timeStamps":
[1] "2013-01-05 14:52:25 GMT" "2013-01-05 14:52:31 GMT"
Field "runTimes":
$test
[1] "5.175815 secs"

Very similar to the closure approach, but more formalised. I had to define the timeStamps field as POSIXct, for example. You can also create multiple RTmonitor objects this way and they work independently - you'd have to write a closure constructor that wrapped the closure to do that.

like image 43
Spacedman Avatar answered Oct 25 '22 14:10

Spacedman