Announcement

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

  • Problem with the use of a global

    Dear All,

    I am having a problem with the following code:

    Code:
    clear all
    version 17.0
    
    program define foobar
        global framename=""
        display `"Frame name is: ${framename}"'
        if ("${framename}"!="") {
            frame ${framename} {
                describe
            }
        }
    end
    
    set trace on
    foobar
    
    /* end of file */
    When this code is executed in Stata v17.0 (Windows), for some reason Stata objects the highlighted line resulting in error message:

    program error: code follows on the same line as open brace
    r(198);


    This is strange, because the line should not be executed, and the trace indicates this as well:

    Click image for larger version

Name:	foobar.png
Views:	1
Size:	5.1 KB
ID:	1715706



    I believe the code should be working as Stata's manual says "...braces ({ }) can be used to clarify meaning and to form nested constructions." (see help macro).

    Any guidance on this or a confirmation of a bug is much appreciated.

    Thank you, Sergiy Radyakin

  • #2
    I don't think it's a bug, per se. I can see potentially two syntax errors. (Note, I am testing on Stata 18, and can reproduce the output shown above.)

    The program -foobar- fails to set a name for a frame into global -framename-. As such, one expects macro expansion to effectively omit those references. But I can see where you might want this behaviour to set a default frame name, so fair enough and you should be able to program around this case. Though I think you have done this for illustrative purposes, it's a better idea to use a local over a global, and this would no longer be an issue.

    If, as intended, the global is empty, then I think the interpreter gets tripped up over the two sets of curly braces ({}) on the same line. This does not happen if you supply a valid frame name.

    Code:
    cap progam drop foobar
    program define foobar
        global framename="myframe"
        display `"Frame name is: ${framename}"'
        if ("${framename}"!="") {
            frame ${framename} {
                describe
            }
        }
    end
    
    foobar
    Result

    Code:
    . foobar
    Frame name is: myframe
    frame myframe not found
    The way around this is to omit the curly braces to reference global macro names (that is, $framename instead of ${framename}). This is the syntax to reference global macros shown in Section 18.3.2 of [U] Programming Stata. The use of curly braces in referencing global macros is explained later on in the same chapter under "Advanced global macro manipulation" where you might have need to dynamically generate the name for a global macro.

    Comment


    • #3
      Dear Leonardo Guizzetti ,

      thank you for your reply and, please, see my comments to you message in BLUE below.

      Best, Sergiy

      Originally posted by Leonardo Guizzetti View Post
      I don't think it's a bug, per se. I can see potentially two syntax errors. (Note, I am testing on Stata 18, and can reproduce the output shown above.)
      Thank you very much for reproducing in v18.

      The program -foobar- fails to set a name for a frame into global -framename-.
      This is done for illustrative purposes. The actual code derives that value from user-supplied parameters and an [irrelevant] algorithm, which may result in a blank.

      As such, one expects macro expansion to effectively omit those references.
      Macro expansion should not be triggered at all in this case as the line containing the reference to a global is shielded with an if-condition.

      But I can see where you might want this behaviour to set a default frame name, so fair enough and you should be able to program around this case.
      Negative. I do not expect the default frame to be set. If the framename is empty, the if-condition doesn't let the statement to be executed, so there is no expectation that it will do anything meaningful. It should be disregarded.

      Though I think you have done this for illustrative purposes, it's a better idea to use a local over a global, and this would no longer be an issue.
      The use of a global is dictated by external requirements. I understand though, that I could get away with local z `"${framename}"' and using the local in the subsequent code in this particular case.
      See also this thread.


      If, as intended, the global is empty, then I think the interpreter gets tripped up over the two sets of curly braces ({}) on the same line. This does not happen if you supply a valid frame name.

      Code:
      cap progam drop foobar
      program define foobar
      global framename="myframe"
      display `"Frame name is: ${framename}"'
      if ("${framename}"!="") {
      frame ${framename} {
      describe
      }
      }
      end
      
      foobar
      Result

      Code:
      . foobar
      Frame name is: myframe
      frame myframe not found
      Negative. Emptiness of the value is irrelevant here. The parser still gets tripped up even if there is a non-empty content in the macro. Consider the following:

      Code:
      capture program drop foobar
      
      program define foobar
          global framename="FORBIDDEN"
          display `"Frame name is: ${framename}"'
          if ("${framename}"!="FORBIDDEN") {
              frame ${framename} {
                  describe
              }
          }
      end
      
      foobar


      still results in:
      Code:
      Frame name is: FORBIDDEN
      program error:  code follows on the same line as open brace
      r(198);
      Somehow the interpreter decides "hey, there is another line, I don't need to execute it, but I will try to understand it anyways, it may be using some globals, but let me forget about this for a moment, since I don't need to execute it, I can do it, right? oh, too bad, there are too many braces, I am lost".

      If the interpreter expanded the macro and didn't execute the line - would be ok. If the interpreter didn't expand the macro and disregarded the line - would be ok. But not the current mode.


      The way around this is to omit the curly braces to reference global macro names (that is, $framename instead of ${framename}).
      This is exactly what I ended up doing for the moment, but I see no reason for having this being forced by the parser.

      This is the syntax to reference global macros shown in Section 18.3.2 of [U] Programming Stata. The use of curly braces in referencing global macros is explained later on in the same chapter under "Advanced global macro manipulation" where you might have need to dynamically generate the name for a global macro.
      Which is exactly the motivation for using curly braces to delineate the macro name.

      Comment

      Working...
      X