Statalist The Stata Listserver


[Date Prev][Date Next][Thread Prev][Thread Next][Date index][Thread index]

Re: st: Help needed to understand behavior of Mata's


From   wgould@stata.com (William Gould, Stata)
To   statalist@hsphsun2.harvard.edu
Subject   Re: st: Help needed to understand behavior of Mata's
Date   Wed, 17 May 2006 08:44:44 -0500

About Mata, Joseph Coveney <jcoveney@bigplanet.com> asked, 

>       : if (1 == 1) "do nothing";;
>         do nothing
>
>       : // Why are two semicolons needed?

The short answer is because Mata is a compiler and the syntax diagram 
for -if- is 

                if (<exp>} <stmt> [else <stmt>]

The short answer continues, this arises only interactively.  In a program, 
one can code 

        function ...() 
        {
                ...
                if (1==1) "do nothing"
                ...
        }

and no semicolons are necessary, although they would not hurt.

This issue only arises when using -if- interactively, and since 
the only people who use -if- interactively are people trying to better
understand how Mata works, few people ever run into this.


The long answer
---------------

Let's type -if (1 == 1) "do nothing";;- a little at a time and let me 
explain to you what is happening inside Mata.  Let's start here:

        : _

At this point, Mata is trying to figure out what element of the overall 
Mata syntax diagram you are typing.  You've typed nothing, and every 
element of the syntax diagram is available:

                   |  <exp> = <exp>
                   |  for (<exp>;<exp>;<exp>) <stmt>
                ---+  while (<exp) <stmt>
              /|\  |  do <stmt> while (<exp>)
               |   |  if (<exp>) <stmt> [else <stmt>]
               |
          Mata is here


In the above, I show only a few of the possible syntax diagrams; there are 
lots more.

Now you type

        : if _

At this point, Mata can identify a syntax diagram.  The situation looks 
like this


                      if   (<exp>) <stmt> [else <stmt>]
                        /|\
                         |
                    Mata is here

Let's continue, 

        : if (1 == 1)

and we have 

                      if (<exp>)   <stmt> [else <stmt>]
                                /|\
                                 |
                            Mata is here

Let's add our then clause:
 
        : if (1 == 1) "do nothing"

The diagram is, 

                      if (<exp>) <stmt> [else <stmt>]
                                  /|\
                                   |
                              Mata is here

Note well, Mata is in the midst of <stmt>, not at the end of it.  Maybe 
-"do nothing"- is a complete statement, and maybe there is more to come.
Perhaps the complete statment will be -"do nothing" + ", we are done"-.
We add a semicolon (or press Enter), an Mata knows the statement is done:

        : if (1 == 1) "do nothing" ;

The diagram is, 

                      if (<exp>) <stmt>    [else <stmt>]
                                       /|\
                                        |
                                   Mata is here

Now Mata is waiting to find out whether there is an else clause.  Even if 
we press Enter, Mata will be waiting to hear if there is an else clause, 
because the -else- might appear on the next line.

Instead, we type a second semicolon,

        : if (1 == 1) "do nothing" ;;

and the diagram is

                      if (<exp>) <stmt>  [else <stmt>]
                                                         /|\
                                                          |
                                                     Mata is here

Now we press Enter, what wew have typed is a complete statement, and 
Mata executes it:
                                         

        : if (1 == 1) "do nothing" ;;
          do nothing


Why this issue does not arise in programs
-----------------------------------------

Consider the following program


        function ourfunc() 
        {
                ...
                if (1==1) "do nothing"
                y = (1,2)
                ...
        }

Note that there are NO semicolons in this program.  Given what I just 
said, how did Mata understand it?

Let's pick up the story when Mata is between (1==1) and "do nothing".


                             Mata is here
                                  |
                                 \|/
          Input line:   if (1==1)    "do nothing"

          Mata state:   if (<exp>)   <stmt> [else <stmt>]
                                 /|\
                                  |
                             Mata is here

Mata picks up the next piece:

                                           Mata is here
                                                |
                                               \|/
          Input line:   if (1==1) "do nothing"

          Mata state:   if (<exp>) <stmt>   [else <stmt>]
                                         /|\
                                          |
                                    Mata is here

There is nothing more on the input line, so Mata goes to the next input
line:

                 Mata is here
                      |
                     \|/
          Input line:   y = (1,2)

          Mata state:   if (<exp>) <stmt>   [else <stmt>]
                                         /|\
                                          |
                                    Mata is here

Now Mata picks up the next little bit, 


                     Mata is here
                          |
                         \|/
          Input line:   y    = (1,2)

          Mata state:   if (<exp>) <stmt>   [else <stmt>]
                                         /|\
                                          |
                                    Mata is here

Does -y- match -else-?  No: 

                     Mata is here
                          |
                         \|/
          Input line:   y    = (1,2)

          Mata state:   if (<exp>) <stmt> [else <stmt>]
                                                         /|\
                                                          |
                                                    Mata is here

That line is finished, so now Mata compiles the completed line and resets its
state to the beginning of all syntax diagrams, and finds the one that matches:

                     Mata is here
                          |
                         \|/
          Input line:   y    = (1,2)

          Mata state:   <exp>    = <exp>
                             /|\
                              |
                         Mata is here

And the story continues.


An extension of the long answer
-------------------------------

Semicolons in Mata serve two purposes:  they can separate statements 
that appear on the same line, such as 

                i = 1 ; y = (i, i+1)

and they can be used to indicate the null statement:

                ;

When we typed 

                if (1==1) "do nothing" ;;

we used both types of semicolons.  The first semicolon separated one 
statement from the next.  The second semicolon specified the null statement,
making clear we did not have an else clause.

Sometimes there are uses for null statements.  For instance, in a program,
we might code 

                if (<exp>) ;
                else {
                        ...
                }

I think better style would be, 

                if (!(<exp>)) {
                        ...
                }

but either construction will work and both are equally efficient.

Here's a required use of the null-statement semicolon:

        function trythis()
        {
                for (i=1; i<=10; i++)
                i
        }

What will -trythis()- do?  Will it list the numbers from 1 to 10, or will
it list the single number 11?  

If we really wanted to list the numbers from 1 to 10, it would be better style
to write

        function trythis()
        {
                for (i=1; i<=10; i++) i
        }

or to write, 

        function trythis()
        {
                for (i=1; i<=10; i++) {
                        i
                }
        }

because both make our intention clearer.

What should we write if we want to make clear the other intention?  The answer
is,

        function trythis()
        {
                for (i=1; i<=10; i++) ;
                i
        }

The semicolon at the end of the for (...) makes clear we want the null 
statement.

By the way, -trythis()- as we originally wrote it lists the numbers 1 to 10.
The above lists the single number 11.

Now wanting to execute 

                for (i=1; i<=10; i++) ; 

is pretty silly; surely it would be better simply to set i to 11.
But -for- statements without a body are sometimes useful, such as

                for (i=1; doanother(i, ...); i++) ; 

In the above, function doanother() returns 0 when it has done enough.


-- Bill
wgould@stata.com
*
*   For searches and help try:
*   http://www.stata.com/support/faqs/res/findit.html
*   http://www.stata.com/support/statalist/faq
*   http://www.ats.ucla.edu/stat/stata/



© Copyright 1996–2014 StataCorp LP   |   Terms of use   |   Privacy   |   Contact us   |   What's new   |   Site index