Announcement

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

  • Stata syntax to compile a global macro name using loop arguments

    In the following loop, in line 4, I would like Stata to print the value stored in the global macro created in line 3 but the correct syntax continues to escape me.

    The macro list command following the loop verifies that $a_w thru $d_z are created with the intended content.

    * ========== start loop
    foreach x in a b c d {
    foreach a in w x y z {
    glo `x'_`a' = runiform()
    di `"$`x'_`a'"'
    }
    }
    macro list
    * ========== end loop

    Thanks in advance for any advice (particularly, the logic involved).

    Best,

    r



  • #2
    The problem is that Stata orders evaluation of global macros ($) before evaluation of local macros, whereas to do what you want you need the reverse. You can force the other ordering with the use of braces {}:

    Code:
    foreach x in a b c d {
        foreach a in w x y z {
            glo `x'_`a' = runiform()
            di `"${`x'_`a'}"'
        }
    } 
    macro list
    will do what you want.

    That said, the use of global macros is an inherently unsafe coding practice and should be avoided except where absolutely necessary. Needless to say the wholesale production of global macros is even more dangerous. What will you be doing with these global macros that you cannot do with local macros?

    Comment


    • #3
      Thanks, that is very helpful. I wanted the macros to be available even after drops and clears and preserve-restore operations later in the same do file. I can try using locals instead and see if that works.

      I am re-reading the chapter on Programming again (albeit slowly as time permits). Found the bit about braces, not yet found the bit about the order of evaluation or on the downside of creating many globals. A quick pointer to the discussion of the why and wherefore of this would be most helpful as well.

      Best,

      r

      Comment


      • #4
        Rajib: That is a good question on the perils of globals. It's just general programming folklore to minimise global settings: I am not sure where it's written up... it's known globally, so no-one writes it down locally.

        Jesting aside, here's a thought experiment. You're thinking it is a good idea to set lots of globals. If so, someone else in the Stata world might equally think it was a good idea to set lots of globals. If you use their programs, however, which typically call other programs, which call other programs, and so on, you are obliged to check that absolutely none of those programs raises a conflict between globals with the same name (which necessarily are the same global).

        Turn this round, and you will see that it's not so good an idea.

        Things are better than this, largely because the people at StataCorp know to write with very few globals, and you can see what they are with

        Code:
        macro list
        but -- still - watch out that you don't get clobbered by your own code.




        Last edited by Nick Cox; 20 May 2016, 08:31.

        Comment


        • #5
          Nick,

          Thanks for the explanation. In essence my objective is to generate several strings and values once from a large "parent" data set and store them for repeated and varied later uses with other other data sets. Is there an alternative to storing these values in macros?

          I would prefer a relatively "simple" solution appropriate for non-programmers since I'm working with business analysts and trying to convince them to use Stata instead of Excel for safe-and-simple diagnostics and charting of large data sets. They already get that Stata will do much more than Excel readily can and are excited about its potential. Anything to minimize the overhead of "learning programming" (which to be honest, as working professionals, they don't have much time for) will only help them dig in deeper into the task.

          r

          Comment


          • #6
            So, in response to #3, local macros remain in scope for the duration of the do-file that defines them unless they are explicitly removed. They are not removed by -drop- (except for -macro drop-). And -clear- does not remove them either (although -clear*- does). The usual way of eliminating a local macro when you want to do that is to just overwrite it with a null string: -local my_undesired_macro-.

            When you need macros to persist across several do-files that use common definitions of things, the trick is to not define them in any of the do-files involved, but rather to define them separately in a file of their own:

            Code:
            -----file macro_definitions.do----
            local my_macro1 abc def ghi
            local my_macro2 "rajib doogar" "clyde schechter"
            -----end file macro_definitions.do----
            Then when you want to use these local macros in other do files:

            Code:
            ----file production_do_file_1.do---
            /*stuff*/
            /* need the macros now */
            include macro_definitions.do
            /* go ahead and use them*/
            /*other stuff*/
            ----end file production_do_file_1.do----
            
            
            ----file production_do_file_2.do
            /*stuff*/
            /*need the same macros as in production_do_file_1.do*/
            include macro_definitions.do
            /* go ahead and use them*/
            /* other stuff*/
            ----end file production_do_file_2.do---
            
            // ETC.
            The key is the -include- command which causes Stata to read the -include-d file directly into the current do file. All of the code in the -include-d do-file acts as if it had originally been typed into the file that -include-s it. Note that you can not accomplish this with -run macro_definitions.do- or -do macro_definitions.do-. The -run- and -do- commands transfer control to the file that is called, thereby creating a new scope for local macro definitions, which then evaporates on return. But -include- actually copies the code in (virtually) and does not create a new scope.

            By the way, this can be used not just to define local macros but also to encode the creation of new variables or other calculations that need to be done exactly the same way across several different do-files.

            Try it. You'll like it! I use this frequently.

            Comment


            • #7
              I think Clyde's answer covers #5 very nicely.

              Comment


              • #8
                - include - is indeed the perfect resolution for my present purposes. Thank you, Clyde!

                r

                Comment

                Working...
                X