About Mata, Joseph Coveney <[email protected]> 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
[email protected]
*
* 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/