Announcement

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

  • Stata evalautes what comes after an if statement that it's not true

    Hi all,

    I have a do-file (Testing ceqef.do, attached) which I'm using to test an ado-file (ceqef.ado, attached). For the sake of simplicity, I copy the relevant part of the ado-file:

    Code:
                        if (wordcount("`tax_`rw'_`cc''")>0 | wordcount("`ben_`rw'_`cc''")>0){ ;  //  #1
                                *impact effectiveness;
                                /*if wordcount("`benef'")>0{;
                                    ceqbenstar [w=`w'], endinc(``cc'') ben(`benef');
                                };
                                if wordcount("`taxesef'")>0{;
                                    ceqtaxstar [w=`w'], endinc(``cc'') taxes(`taxesef');
                                };*/
                                if (wordcount("`tax_`rw'_`cc''")>0 & wordcount("`ben_`rw'_`cc''")>0) {; //  #2
                                    tempvar ystar;
                                    gen double `ystar'=``rw'';
                                    *set trace on ;
                                    ceqtaxstar `pw', startinc(``rw'') taxes(`taxesef');    
                                    *set trace off ;
                                    local twarn = 0 ; 
                                    if r(t_gr) == 1{ ;
                                        nois `dit'  "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local warning `warning'  "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local twarn = r(t_gr) ; 
                                    } ;
                                    else if r(t_0) == 1{ ;
                                        nois `dit'  "Sum of `tname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local warning `warning'  "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local twarn = r(t_0) ; 
                                    } ;
                                
                                    ceqbenstar `pw', startinc(``rw'') ben(`benef');
                                    local bwarn = 0 ;
                                    if r(b_gr) ==1 { ;
                                        nois `dit' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for ``rw'' to ``cc'' excludes benefits or is not produced" ;
                                        local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for ``rw'' to ``cc'' excludes benefits or is not produced" ;
                                        local bwarn = r(b_gr) ;
                                    } ;
                                    else if r(b_0) ==1 { ;
                                        nois `dit' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for ``rw'' to ``cc'' excludes benefits or is not produced" ;
                                        local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for ``rw'' to ``cc'' excludes benefits or is not produced" ;
                                        local bwarn = r(b_0) ;
                                    } ;
                                    
                                    if `bwarn' == 0 & `twarn' == 0 { ;
                                        replace `ystar'=____ybenstar if ____id_benstar==1 & ____id_taxstar!=1;
                                        replace `ystar'=____ytaxstar if ____id_taxstar==1 & ____id_benstar!=1;
                                        tempvar temptax;
                                        gen double    `temptax'=``rw''-    ____ytaxstar if ____id_benstar==1 & ____id_taxstar==1;            
                                        tempvar tempben;
                                        gen double    `tempben'=    ____ybenstar - ``rw'' if ____id_benstar==1 & ____id_taxstar==1;
                                        replace `ystar'=``rw'' - `temptax' +`tempben' if ____id_benstar==1 & ____id_taxstar==1;            
                                        cap drop ____ytaxstar ____ybenstar ____id_benstar ____id_taxstar ;
                                        cap drop `temptax' `tempben';
                                    };
                                    else  { ;
                                        local bwarn = 1 ;
                                        local twarn = 1 ;
                                    };
                                };
                                if (wordcount("`tax_`rw'_`cc''")>0 & wordcount("`ben_`rw'_`cc''")==0) {;  // #3
                                    *set trace on;
                                    ceqtaxstar `pw' , startinc(``rw'') taxes(`taxesef') ;
                                    *set trace off;
                                    local twarn = 0 ;
                                    if  r(t_gr) ==1 { ;
                                        nois `dit' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local warning `warning' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;                                
                                        local twarn = r(t_gr) ; 
                                    } ;
                                    else if  r(t_0) ==1 { ;
                                        nois `dit' "Sum of `tname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local warning `warning' "Sum of `tname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;                                
                                        local twarn = r(t_0) ; 
                                    } ;
                                    else !(r(t_0) == 1 | r(t_gr) == 1) {;
                                        tempvar ystar;
                                        gen double `ystar'=____ytaxstar;
                                        cap drop ____ytaxstar ____ybenstar ____id_benstar ____id_taxstar;
                                    };
                                };
                                if (wordcount("`tax_`rw'_`cc''")==0 & wordcount("`ben_`rw'_`cc''")>0) {;  // #4
                                    ceqbenstar `pw', startinc(``rw'') ben(`benef');        
                                    local bwarn = 0 ;
                                    if r(b_gr) == 1 { ;
                                        nois `dit' "Sum of `bname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local bwarn = r(b_gr) ;
                                    } ;
                                    else if r(b_0) == 1 { ;
                                        nois `dit' "Sum of `bname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from ``rw'' to ``cc''" ;
                                        local bwarn = r(b_0) ;
                                    } ;
                                    if !(r(b_0) == 1 | r(b_gr) == 1) {;            
                                        tempvar ystar;
                                        gen double `ystar'=____ybenstar;
                                        cap drop ____ytaxstar ____ybenstar ____id_benstar ____id_taxstar;
                                    };
                            };
                        
                               
                                if (!( "`bwarn'" == "1" & "`twarn'" == "1" )) { ; // #5
                                    covconc ``cc'' `pw'; //gini of column income;
                                    local g1_`cc'=r(gini);
                                    di "`rw' ``rw''";
                                    covconc ``rw'' `pw'; //gini of row income;
                                    local g2_`rw'=r(gini);
                                    covconc `ystar' `pw'; //gini of star income;
                                    local g_star=r(gini);
                                    local imef=(`g2_`rw''-`g1_`cc'')/(`g2_`rw''-`g_star');
                                    matrix `rw'_ef[1,`_`cc'']=`imef';
                                };
    Where I've numbered what I think are the 5 most important -if- statements and the #1 continues after #5 is closed. My problem is that when running the do-file, there are certain cases in which `tax_`rw'_`cc'' and `ben_`rw'_`cc'' don't exist and therefore -if- #1 should be false and I would expect Stata to skip everything inside the brackets corresponding to that -if-. However, even though I've confirmed that, in fact, Stata evaluates -if- #1 as false and skips #2 and #3, it runs -if- #4 and #5 (and since there are variables that are not created when the -if- #1 is false, Stata runs into an error and stops running). You can see this in the relevant part of the log-file that I now copy:


    - if (wordcount("`tax_`rw'_`cc''")>0 | wordcount("`ben_`rw'_`cc''")>0){ // #1
    = if (wordcount("")>0 | wordcount("")>0){ // #1
    if (wordcount("`tax_`rw'_`cc''")>0 & wordcount("`ben_`rw'_`cc''")>0) { // #2
    tempvar ystar
    gen double `ystar'=``rw''
    ceqtaxstar `pw', startinc(``rw'') taxes(`taxesef')
    local twarn = 0
    if r(t_gr) == 1{
    nois `dit' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from
    > ``rw'' to ``cc''"
    local warning `warning' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not
    > produced from ``rw'' to ``cc''"
    local twarn = r(t_gr)
    }
    else if r(t_0) == 1{
    nois `dit' "Sum of `tname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' t
    > o ``cc''"
    local warning `warning' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not
    > produced from ``rw'' to ``cc''"
    local twarn = r(t_0)
    }
    ceqbenstar `pw', startinc(``rw'') ben(`benef')
    local bwarn = 0
    if r(b_gr) ==1 {
    nois `dit' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for ``rw'' to ``c
    > c'' excludes benefits or is not produced"
    local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for
    > ``rw'' to ``cc'' excludes benefits or is not produced"
    local bwarn = r(b_gr)
    }
    else if r(b_0) ==1 {
    nois `dit' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for ``rw'' to ``c
    > c'' excludes benefits or is not produced"
    local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator for
    > ``rw'' to ``cc'' excludes benefits or is not produced"
    local bwarn = r(b_0)
    }
    if `bwarn' == 0 & `twarn' == 0 {
    replace `ystar'=____ybenstar if ____id_benstar==1 & ____id_taxstar!=1
    replace `ystar'=____ytaxstar if ____id_taxstar==1 & ____id_benstar!=1
    tempvar temptax
    gen double `temptax'=``rw''- ____ytaxstar if ____id_benstar==1 & ____id_taxstar==1
    tempvar tempben
    gen double `tempben'= ____ybenstar - ``rw'' if ____id_benstar==1 & ____id_taxstar==1
    replace `ystar'=``rw'' - `temptax' +`tempben' if ____id_benstar==1 & ____id_taxstar==1
    cap drop ____ytaxstar ____ybenstar ____id_benstar ____id_taxstar
    cap drop `temptax' `tempben'
    }
    else {
    local bwarn = 1
    local twarn = 1
    }
    }
    if (wordcount("`tax_`rw'_`cc''")>0 & wordcount("`ben_`rw'_`cc''")==0) { // #3
    ceqtaxstar `pw' , startinc(``rw'') taxes(`taxesef')
    local twarn = 0
    if r(t_gr) ==1 {
    nois `dit' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not produced from
    > ``rw'' to ``cc''"
    local warning `warning' "Sum of `tname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not
    > produced from ``rw'' to ``cc''"
    local twarn = r(t_gr)
    }
    else if r(t_0) ==1 {
    nois `dit' "Sum of `tname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' t
    > o ``cc''"
    local warning `warning' "Sum of `tname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced
    > from ``rw'' to ``cc''"
    local twarn = r(t_0)
    }
    else !(r(t_0) == 1 | r(t_gr) == 1) {
    tempvar ystar
    gen double `ystar'=____ytaxstar
    cap drop ____ytaxstar ____ybenstar ____id_benstar ____id_taxstar
    }
    }
    - if (wordcount("`tax_`rw'_`cc''")==0 & wordcount("`ben_`rw'_`cc''")>0) { // #4
    = if (wordcount("")==0 & wordcount("")>0) {
    ceqbenstar `pw', startinc(``rw'') ben(`benef')
    local bwarn = 0
    if r(b_gr) == 1 {
    nois `dit' "Sum of `bname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' t
    > o ``cc''"
    local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not
    > produced from ``rw'' to ``cc''"
    local bwarn = r(b_gr)
    }
    else if r(b_0) == 1 {
    nois `dit' "Sum of `bname_`rw'_`cc'' is 0, so impact effectiveness indicator not produced from ``rw'' t
    > o ``cc''"
    local warning `warning' "Sum of `bname_`rw'_`cc'' exceed ``rw'', so impact effectiveness indicator not
    > produced from ``rw'' to ``cc''"
    local bwarn = r(b_0)
    }
    if !(r(b_0) == 1 | r(b_gr) == 1) {
    tempvar ystar
    gen double `ystar'=____ybenstar
    cap drop ____ytaxstar ____ybenstar ____id_benstar ____id_taxstar
    }
    }
    - assert !( "`bwarn'" == "1" & "`twarn'" == "1" )
    = assert !( "" == "1" & "" == "1" )
    - pause: pause2
    pause: : pause2
    -> . q
    execution resumes...
    - if (!( "`bwarn'" == "1" & "`twarn'" == "1" )) { // #5
    = if (!( "" == "1" & "" == "1" )) {
    - covconc ``cc'' `pw'
    = covconc OI [pw = __000001]
    - local g1_`cc'=r(gini)
    = local g1_mp=r(gini)
    - di "`rw' ``rw''"
    = di "m OI"
    - covconc ``rw'' `pw'
    = covconc OI [pw = __000001]
    - local g2_`rw'=r(gini)
    = local g2_m=r(gini)
    - covconc `ystar' `pw'
    = covconc [pw = __000001]
    varlist required
    local g_star=r(gini)
    local imef=(`g2_`rw''-`g1_`cc'')/(`g2_`rw''-`g_star')
    matrix `rw'_ef[1,`_`cc'']=`imef'
    }


    Since I set the trace on, you can clearly see which -if- statements run. I really don't understand why. I've checked multiple times if all the -if- statements were properly closed, and as far as I can tell, they are. Can you think of another reason why this -if- statement is not working as it should (others in the ado-file work perfectly fine)?

    Many thanks in advance for your help!
    Attached Files

  • #2
    (Wrong answer overwritten.)
    Last edited by Nick Cox; 31 Mar 2020, 09:55.

    Comment


    • #3
      Sorry, Nick Cox, I didn't understand your comment.

      Comment


      • #4
        I posted an answer, realized that it was irrelevant to your problem, and could not think of a better one.

        Comment


        • #5
          Nick means he posted a response but then found fault with it, so he edited the post and replaced his original text with the apology.

          Comment


          • #6
            My reaction here -- others might differ - is that you've presented quite a large chunk of code, and have a lot of extraneous stuff embedded (comments and your own error message content). Also, I find that the way you describe your problem "buries the lead," and leaves us to work some to understand the problem. My suggestion would be to see if you can present a smaller piece of code that shows the problem, with comments and your own error messages and the like stripped out. Also, getting some help to develop a more direct statement of the problem would help.

            Comment


            • #7
              Thank you all for your comments! and Mike Lacy, I definitely agree with you. It found it difficult to explain without posting such a long code, mainly because I was afraid of omitting something important, so I opted to do it. But I certainly agree with you and will try to think of a simpler way of explaining it. Many thanks for your suggestion.

              Comment


              • #8
                Mike Lacy captured the essence of my reaction to your post as well. I have an additional suggestion. Troubleshooting code is usually much easier if you provide example data to run it on. So please use the -dataex- command and include some when you post your simplified problem.

                Comment


                • #9
                  I just noticed the following line in your #3 section:
                  Code:
                  else !(r(t_0) == 1 | r(t_gr) == 1) {;
                  You meant to have an "if" following the "else".

                  My hypothesis is that Stata, in skipping over the code surrounded by #1, does not throw a syntax error on this line because it wasn't meant to be executed. However, Stata effectively ignores the line and the left brace on it, so that further down the right brace that matches it is used instead to close out the #1 if. And so #4 and #5 are not within #1 and are executed.

                  Comment


                  • #10
                    Thank you all for your suggestions! I'm pretty new at the forum, so it really helps me any input and suggestion to be clearer and a better forum participant!

                    William Lisowski, you are absolutely right! I can't thank you enough for finding this!!

                    Do you know if there is a way of detecting when braces are matched and when they are not? Because something that was misleading was that in the do-file editor I could get an idea of the lines contained in between braces with the plus/minus (+7-) sign on the left, which shows/hides the lines, and when I pressed the one corresponding to the else line you highlighted, it did hide the lines between braces. Thus, it made think that the two braces were properly matched.

                    Comment


                    • #11
                      Your braces were properly matched. The problem was that your syntax error caused your opening brace on the else statement to be ignored by Stata. The do-file editor would have to do full syntax checking to catch the fact that there was a syntax error on your else statement. I can't begin to guess what Stata was thinking when it parsed that command.
                      It's unfortunate that Stata ignored the open brace, but I would not want to claim I could do any better.

                      What I started to write, before I saw the error, was to suggest that you comment out the #2 and #3 blocks entirely and see if #4 and #5 continued to be run. The answer, it turns out, is that they would not have been run, and that at least would have given you an idea to look closely at #2 and #3. Or to add #2 back in and see that it didn't make #4 and #5 run, narrowing the search to #3. And then just leave the if and not the else - and at that point you would have seen the error.

                      But realistically this is one of the primary problems of programming - when we review our code, we read what we meant to type, not what we actually typed. That's one of the reasons behind the recommendation that the best example is the smallest reproducible example that exhibits the problem. On the way to pruning your code to that point, you'll often see what you missed before.

                      Comment


                      • #12
                        I have one other thought: I started my programming life in Pascal, where the ";" is required and (to me) clear. However, I don't find the ";" very useful or clear in Stata, a perspective I think is widely shared. Use of the ";" seems uncommon among experienced Stata coders. This suggests two things to me: 1) Maybe there's more than a local cultural preference at work here, i.e., maybe Stata code *is* objectively less readable with the semicolon delimiter; and 2) Even if that's not true, most of the Stata programmers that could help you would (I'm guessing from my own experience) find code relying extensively on the ";" delimiter to be confusing. On these counts I'd encourage you to consider switching to the no-semi-colon style

                        Comment


                        • #13
                          I think Mike Lacy is right. Programming experience does affect people's attitude and aptitude when reading code. I started in Fortran (then usually called FORTRAN) which certainly didn't use (even allow) semi-colons as delimiters (at least at that time: 1973 on). I also have experience of languages in which semi-colons are allowed or even predominant style.

                          In Stata, however, almost everyone starts with the command-line interface and commands on single lines. Programmers who use semi-colons are in a small minority, which is not to say that they are wrong, but I find Stata code with semi-colons harder to read.

                          Just to be confusing, on occasion I will happily use semi-colons in Mata, but usually for a string of very short statements with a kind of family relationship, say

                          Code:
                          min = 0 ; max = 1

                          Comment


                          • #14
                            I'm really grateful for all your comments and suggestions!!

                            William Lisowski I completely relate to what you say of seeing what meant to type and want I actually did. So, I find extremely useful the procedure that you suggest to pin down the cause of the error. Many thanks again!!

                            Mike Lacy and Nick Cox, I completely agree with you. Since these are codes I've inherited I have no alternative but to keep working with the semi-colon delimiter but I also find the code a lot harder to read, especially, considering I'm already way too used to programming with commands on single lines. But I thought it was the other way around and that experienced programmers such as you did use it and I had to adjust to that. So, your comments on this are really helpful! Thanks!!

                            Comment

                            Working...
                            X