Announcement

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

  • Question about invoking global macros

    Hello,

    I am using Stata 16.1 and I have a question about how to invoke global macros when multiple programs are involved.

    I have two programs written within my do-file (I call them mini-programs for ease of reference). The specific nature of what the programs are doing is not too important, so I have provided a simplified version using the sample auto dataset. The "foreach" loop at the bottom would normally have additional variables, so that is why it may look trivial in this context. I have bolded the lines that I believe comprise the issue. The main issue I am experiencing is that I store a global macro in the first mini-program, which is a p-value that takes the name `1'_p based on the input to the mini-program. When I try to invoke this global macro in the second mini-program, I get an error.

    The point at which the second mini-program reaches an error is the line "if $`x'_p <= 0.1" . The specific error is an r(198) "<=0.1 invalid name".

    My code is pasted below. The first mini-program takes as an input a piece of text that corresponds to both a pre and a post variable.

    clear all
    sysuse auto.dta, clear

    program define TABLE_PCT
    *** CREATE CHANGE VARIABLE
    qui gen chg = `1'_post - `1'_pre

    *** SIGNIFICANCE TESTING
    ttest chg == 0
    global `1'_p = round(r(p),.001)
    di "2-sided p-value of " $`1'_p
    drop chg
    end

    program define ADDASTERISKS

    if $`x'_p <=0.1 {
    di "SOMEWHAT SIGNIFICANT"
    }
    if $`x'_p <=0.05 {
    di "SIGNIFICANT"
    }
    if $`x'_p <=0.01 {
    di "VERY SIGNIFICANT"
    }

    end

    gen headroom_pre = headroom
    gen headroom_post = headroom^2

    TABLE_PCT headroom

    foreach x in headroom{

    ADDASTERISKS

    }


    It is possible that I am simply using the wrong syntax to invoke the p-value global. Or maybe my use of the foreach loop is causing conflicts. But please let me know what the best recourse is. Thanks!


  • #2
    The issue is not with globals, but with locals. In ADDASTERISKS you refer to local x -- which is never defined in your code in a way that ADDASTERISKS can see -- but changing the call

    Code:
    ADDASTERISKS
    to

    Code:
    ADDASTERISKS `x'
    will presumably help. The wider issue is that it is perfectly legal to go

    Code:
    foreach x in headroom {
    
    
    }
    and never refer to the macro x inside the loop. So, again, that is legal, but it is not usually what you want. Other way round, there is no implied way that x in the foreach call is supplied to statements in the body of the loop. If you want that, and you usually do, It must be explicit.

    Code:
    forval j = 1/3 {
        di "Three cheers for Stata!"
        di "NB -- not STATA"
    }
    is an example of a loop in which the inside of the loop doesn't need to be told the value of the local macro, but that's unusual.

    However, there is more. Although you should feed the value of the local to ADDASTERISKS it won't know that you elsewhere named it x (it's in a different namespace, given that is a local elsewhere.) But an initial statement in ADDASTERISKS

    Code:
    args x
    will set up a mapping.

    This is just what I spotted and other problems may lurk.
    Last edited by Nick Cox; 28 Jan 2021, 11:22.

    Comment


    • #3
      Thank you, Nick! I modified the ADDASTERISKS program so that it takes `x' as an input, allowing the loop to run successfully.

      Comment

      Working...
      X