Announcement

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

  • Options parsing in syntax

    Dear All, consider the following example code:

    Code:
    clear all
    version 16.0
    program define foobar
       version 16.0
       syntax varlist , [count(integer 30) *]
       display `"`count'"'
       keep if (_n<`count')
       scatter `varlist', `options'
    end
    
    sysuse auto
    foobar price weight, count(50.005) 
    // end of file
    Stata's documentation states literally the following
    The macro contains the integer specified by the user, or else it contains the default value.
    with regards to optional integer parameter. This explains why Stata
    • doesn't stop with an error on parsing the syntax (my preferred action);
    • doesn't round the value to e.g. 50 (agree, there could be different ways of rounding).
    I have no problem with this. Yet I don't understand why Stata still keeps the option count() in the list of other options, which makes it stumble later on the scatter command. The logical way of handling this would have been to eliminate it from the `options' macro.

    At this time I declare the option to be real, then confirm manually whether it is integer. This however defies the purpose of having the integer option declaration and is tedious in the case of many such integer options.

    Is there any simple way to purge all so duplicated options from the `options' macro?

    (Duplicated because the syntax appears to be something like :
    Code:
    foobar price weight, count(30) count(50.5)
    where the first count() is used in the code of foobar and the second is passed to the scatter.

    Interestingly, this behavior does not apply to integer numeric lists, where Stata happily stops with an error on encountering a non-integer value, such as in:
    Code:
     syntax varlist , [count(numlist integer max=1) *]
    yet I can't find a way to put a default value of the optional list into the syntax.

    Thank you, Sergiy Radyakin



  • #2
    I note that you get the desired behavior if you remove the asterisk from your syntax command.

    The output of help syntax tells us

    If you also specify *, any remaining options are collected and placed, one after the other in `options'. If you do not specify *, an error is returned if the user specifies any options that you do not list.
    It is arguable that count(50.5) having a non-integer argument is not an option you list - you list a count() option with an integer argument - so it includes it in the residual list `options'.

    Of course, it's treatment of the numlist variant is inconsistent with this. I'm guessing it only checks for a "numlist" to decide if it's an option you have described, where it should check for a numlist of integers with a maximum of one member in the list.

    Comment


    • #3
      Dear William,

      thank you for looking at the question and posting the advice.

      The star (*) in my example is essential. The example I posted is a primitive example, solely to illustrate the point. But it is based on a real situation. The other options caught by the star are to control graphing command which needs to be available for customization (axes, legend, colors, all sort of stuff).


      You also wrote:
      It is arguable that count(50.5) having a non-integer argument is not an option you list - you list a count() option with an integer argument - so it includes it in the residual list `options'.
      I would argue that the options should be identified by option-name only. Not by a combination of the option-name and option-value. From the top of my head I can't recollect any command that would have meaningfully declared

      Code:
      syntax , opt1(string) opt1(real)
      Although this is a legal syntax definition in Stata:
      Code:
      clear all
      program define foobar
         syntax , opt1(string) opt1(real)
         
          display "`opt1'"
      end
      foobar, opt1("A") opt1(2)
      Works. But as expected: a named option may only have ONE value, unless you start manually tokenizing the command. I believe graphing commands are making use of this, but it is a very non-transparent usage.

      Regards, Sergiy

      Comment


      • #4
        Interestingly, this behavior does not apply to integer numeric lists, where Stata happily stops with an error on encountering a non-integer value, such as in:
        Code:
        syntax varlist , [count(numlist integer max=1) *]
        yet I can't find a way to put a default value of the optional list into the syntax.
        Sergiy Radyakin (I guess you already know this): Going on your second suggestion, how about adding an if command in the program?

        Code:
        clear all
        version 16.0
        cap program drop foobar
        program define foobar
           version 16.0
           syntax varlist , [count(numlist integer max=1) *]
           if ("`count'" == "") {
              local count 30
           }
           display `"`count'"
           keep if (_n<`count')
           scatter `varlist', `options'
        end
        
        sysuse auto
        foobar price weight, count(50.005)
        The graphing command will use the last specified repeated option as long as no error is thrown.
        Last edited by Andrew Musau; 10 Apr 2020, 00:57.

        Comment


        • #5
          Hi, Andrew,
          I wrote
          yet I can't find a way to put a default value of the optional list into the syntax.
          meaning
          I can't find a way to put a default value of the optional list into the syntax statement so that it cuts out the option count().

          Clearly I can do what you are showing, but it doesn't prevent the option count() from being passed to the graphing command later, which will break it down. The error and the problem is with handling the star-`options' pair, not with the count() option itself.

          Thank you, Sergiy

          Comment


          • #6
            OK, I understand. Reversing the order seems to work for me.

            Code:
            syntax varlist , [* count(integer 30)]
            EDIT: Sorry, it's the same as in your code in #1.
            Last edited by Andrew Musau; 10 Apr 2020, 10:39.

            Comment

            Working...
            X