Announcement

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

  • Syntax parsing error when trying to use a program option

    Dear statalist users,

    I want to write a small program that just takes integers as input values ​​and then does something with them. What exactly is irrelevant to the description of my problem.
    I would also like to define an option with which I can define the name of the returned local.

    According to Stata psyntax help I can only use varlist|namelist|anything as arguments. Isn't there actually an option to use numlist here too?

    Since I couldn't find this option, I now used anything as input, which works somehow.
    BUT:
    If I use the additional option local(name) and write the comma that separates the option from the argument directly after the argument, then it is not parsed correctly, but the comma is read as part of the argument. If I write a space before the options comma, everything works.

    Code:
    program define tinytest
        syntax anything(everything)[, Local(name)]
        args number
        if !missing(`"`local'"') display as result in smcl `"Option defined: `local'"'
         // lets calculate something just for illustration
        display as result in smcl `number'^2
    
    end
    This is what happens in different situations:
    Code:
    . tinytest 5
    25
    
    .  tinytest 5 , local(name)
    Option defined: name
    25
    
    .  tinytest 5, local(name)
    Option defined: name
    5 ^2 invalid name
    r(198);
    So what am I doing wrong here and how can I correctly specify the program syntax?
    Thanks in advance for your help!
    Benno Schönberger

  • #2
    Thanks for everyone who was already trying to help, i got it. After hours ;-)

    Code:
    program define tinytest
        syntax anything(name=number)[, Local(name)]
        if !missing(`"`local'"') display as result in smcl `"Option defined: `local'"'
        // lets calculate something just for illustration
        display as result in smcl `number'^2              
    
    end
    But the first question remains: what is the easiest way to ensure that only integers are accepted as input?

    Comment


    • #3
      Anything could be anything, so I would add a test to make sure that the user gives you what you expect.

      Code:
      program define tinytest
           syntax anything(name=number)[, Local(name)] 
           confirm integer number `number'
      end
      Alternatively, and that is the way most Stata users will expect your program to work, you can give a number to a program through options. Given your previous program, I will assume that the number is not optional. Now the syntax command will do the checking for us, so we don't need the confirm command. However the main advantage is that most Stata users would expect a variable list before the comma.

      Code:
      program define tinytest
           syntax [, Local(name)]  number(integer)
      
      end
      ---------------------------------
      Maarten L. Buis
      University of Konstanz
      Department of history and sociology
      box 40
      78457 Konstanz
      Germany
      http://www.maartenbuis.nl
      ---------------------------------

      Comment


      • #4
        Depending on details, here is how I would set this up
        Code:
        program define tinytest
            
            version 18 // <- don't forget the version statement!
            
            gettoken number 0 : 0 , parse(" ,") quotes
            syntax [ , Local(name) ]
            
            confirm integer number `number' // <- confirm the argument type
            
            ...
            
        end
        You might want to change
        Code:
        Local(name)
        to
        Code:
        Local(name local)
        to allow local macro names, which might start with a number.


        Edit: Crossed with Maarten's reply. I tend to agree that implementing this as an option is the more Stata-ish way here; even if it requires a little more typing on the user's end.
        Last edited by daniel klein; 23 Jul 2024, 04:28.

        Comment


        • #5
          Originally posted by Benno Schoenberger View Post
          If I use the additional option local(name) and write the comma that separates the option from the argument directly after the argument, then it is not parsed correctly, but the comma is read as part of the argument.
          Just to be clear: Stata parses correctly! It is documented, albeit a little hidden, in [P] syntax that
          Arguments are defined by the spaces that separate them. “X*3+cat” is one argument, but if we had typed “X*3 + cat”, that would have been three arguments
          Granted even this documentation might be slightly misleading because you might incorrectly assume that double quotes are typed; they are not. Had double quotes been typed,
          Code:
          "X*3 + cat"
          would still be one argument. Anyway, args does not consider the comma a separator of arguments.

          Comment


          • #6
            Originally posted by Maarten Buis View Post

            Alternatively, and that is the way most Stata users will expect your program to work, you can give a number to a program through options. Given your previous program, I will assume that the number is not optional. Now the syntax command will do the checking for us, so we don't need the confirm command. However the main advantage is that most Stata users would expect a variable list before the comma.

            Code:
            program define tinytest
            syntax [, Local(name)] number(integer)
            
            end
            Dear Maarten,
            thanks a lot for sharing you thoughts.
            I also thought about inputting it as an option and using statas check routines but as the integer is the only input I need, this seems quite laborious and I would prefer being able to just type progname number and thats it.


            Originally posted by daniel klein View Post
            Depending on details, here is how I would set this up
            Code:
            program define tinytest
            
            version 18 // <- don't forget the version statement!
            
            gettoken number 0 : 0 , parse(" ,") quotes
            syntax [ , Local(name) ]
            
            confirm integer number `number' // <- confirm the argument type
            
            ...
            
            end
            Thanks also to Daniel for sharing his knowledge.
            What is the advantage of manually parsing the input using gettoken here?
            If I understood correctly, when using syntax anything (name=number) the content of the macro `0' would also simply be renamed to number, right? So the result should be the same.

            Comment


            • #7
              Originally posted by Benno Schoenberger View Post
              What is the advantage of manually parsing the input using gettoken here?
              In this scenario, there is no advantage. Indeed,

              Code:
              syntax anything(name=number) [ , Local(name) ]
              confirm integer number `number'
              is better code. It is shorter, better readable, and produces better error messages.

              Added: By the way, even better would be
              Code:
              syntax anything(id="integer number" name=number)
              confirm integer number `number'
              Last edited by daniel klein; 23 Jul 2024, 05:08.

              Comment

              Working...
              X