Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • New on SSC: -preserve_globals-

    Thanks to Kit Baum, a new command, preserve_globals, is now available from the SSC.

    The command does what its name implies: it preserves global macros, i.e., protects global macros from being overwritten. Earlier versions of preserve_globals appeared in a discussion started by Clyde Schechter. To quote his problem statement:

    Originally posted by Clyde Schechter View Post
    The danger of global macros arises from the fact that their contents can be modified anywhere, including places that may not even be visible to the programmer when side effects of the modification arise. This makes for intractable bugs. On the other hand, I do appreciate that global macros can be more convenient to use than local macros.
    preserve_globals is a suggested solution to this problem.

    Here is a silly example that first illustrates the problem, then demonstrates the solution. Suppose, there is a program:

    Code:
    program global_data_star_trek
        global data "a character from Star Trek: The Next Generation"
        display "Data is ${data}"
    end
    that we want to call from within a do-file. Suppose the do-file reads:

    Code:
    // store the path to the dataset in a global macro
    global data "C:\mydata"
    
    // call a command
    global_data_star_trek
    
    // reference the global macro; expect to see the path to the dataset
    display "data is ${data}"
    The output is

    Code:
    . // define a global macro for the path to the dataset
    . global data "C:\mydata"
    
    . 
    . // call a command
    . global_data_star_trek
    Data is a character from Star Trek: The Next Generation
    
    . 
    . // reference the global macro
    . display "data is ${data}"
    data is a character from Star Trek: The Next Generation
    Here is how we solve the problem:

    Code:
    // define a global macro for the path to the dataset
    global data "C:\mydata"
    
    // call a command; but presreve global macros
    preserve_globals global_data_star_trek // <- modified line
    
    // reference the global macro
    display "data is ${data}"
    The output:

    Code:
    . // define a global macro for the path to the dataset
    . global data "C:\mydata"
    
    . 
    . // call a command; presreve global macros
    . preserve_globals global_data_star_trek // <- modified line
    Data is a character from Star Trek: The Next Generation
    
    . 
    . // reference the global macro
    . display "data is ${data}"
    data is C:\mydata

  • #2
    Terrific, thank you!

    Comment


    • #3
      Thanks again to Kit Baum, an updated version of preserve_globals is now available from the SSC.

      I have made two more changes. Neither change is expected to break existing code as long as you declare version and as long as you update preserve_globals before Stata 18.1 (or 19, whichever is next).

      For those interested and willing to read on, I will explain.

      The first change is just an added option: strict. The full syntax diagram is now

      Code:
      preserve_globals [ , strict : ] command
      and it is fully compatible with the old syntax diagram. When option strict is specified, any new global macros that command defines, are deleted once command concludes. By default, new globals that command defines will persist. Here is an illustrating example:

      Code:
      . display "${foo}"
      
      
      . preserve_globals , strict : global foo "bar"
      
      . display "${foo}"
      
      
      . preserve_globals /* nostrict */ global foo "bar"
      
      . display "${foo}"
      bar


      The second change concerns Stata's version control. In previous versions, preserve_globals would not pass thru the caller's version. This is best illustrated by a silly example:

      Code:
      . version 17 : preserve_globals version
      version 16.1
      That is, preserve_globals will call command with version set to 16.1, regardless of the version you set, say in a do-file. If you want to call command with another version, you need to be explicit:

      Code:
      . version 17 : preserve_globals version 17 : version
      version 17.0
      For most commands, this won't make a difference, but for some it does. Although I like being explicit in terms of code, given preserve_globals is supposed to prevent hard-to-trace bugs, I am not happy with this situation. Thus, the new version of preserve_globals will pass thru the caller's version -- starting with the first version of Stata following version 18. By the time you will eventually type

      Code:
      version 19 : preserve_globals version
      you will get

      Code:
      version 19.0
      Obviously, you cannot do that today:

      Code:
      . version 19 : preserve_globals version
      this is version 18.0 of Stata; it cannot run version 19.0 programs
           You can purchase the latest version of Stata by visiting https://www.stata.com.
      r(9);
      But once Stata 19 is there, you can. You can still (and I recommend to) be explicit:

      Code:
      version 19 : preserve_globals version 17 : version
      will continue to produce

      Code:
      version 17.0

      The point is that code you have written now, declaring version 18 or less, implicitly or explicitly, will continue to work and produce the same results.

      Comment


      • #4
        Thanks for these updates, and the deep thought about the issues that underlies them.

        Comment

        Working...
        X