A=B=C=D in BASIC and C

Chet Simpson posted this in the Color Computer Facebook group recently:

Some folks understand it, some folks are confused by it, and I decided to be inspired by it to write this article.

In the C programming language, you can do that assignment:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
int a,b,c,d;

a = 0;
b = 1;
c = 2;
d = 3;

a = b = c = d = 4;

printf ("a=%d b=%d c=%d d=%d\n", a, b, c, d);

return EXIT_SUCCESS;
}

That program will produce the following output:

a=4 b=4 c=4 d=4

You can try this program online, if you want.

In BASIC, the “=” works a bit differently because it can be both an assignment (A=5) or a test (IF A=5 THEN). For example:

REM ASSIGNMENT
A=5

REM TEST
IF A=5 THEN PRINT "A IS 5"

Perhaps this is why there was a keyword LET in early BASIC. When you use LET (it is supported on the CoCo), it tells BASIC you are assigning a variable:

LET A=5

Perhaps if LET was required for an assignment, those BASICs could treat the “=” when seen not after a LET as a test. Anyone know the history of LET?

In C, this is solved by having “=” be an assignment, and “==” being a test:

a = 5; // assignment

if (a == 5) { ... } // test

BASIC could have used “LET” to me “=”, and no LET to mean “==”, but it doesn’t. Saying “the BASIC parser doesn’t work like that” is an accurate answer, but it did bring to mind some things I never knew back when I was learning BASIC.

What is A=B?

You cannot answer that, without seeing more context. “IF A=B THEN” is a test. “LET A=B” or just “A=B” is an assignment.

When is it a test? After IF.

IF A=5 THEN PRINT "A IS 5!"

It is also a test after a PRINT:

PRINT A=5

Or after an assignment:

Z=A=5

To make this cleared, the “test” part (after the initial assignment) could be put in parentheses is like this:

Z=(A=5)

But, the parents are optional in this case, but can matter when doing certain things, such as math.

I am sure I have discussed this in an earlier article, but to recap, when things are a test, they return either -1 if TRUE, or 0 if FALSE. For example:

A=1
B=1
PRINT A=B
-1

A=0
B=1
PRINT A=B
0

The result of any test in BASIC is either 0 or -1. BASIC treats 0 as FALSE, and anything else as TRUE:

IF 0 THEN PRINT "FALSE"
IF -1 THEN PRINT "TRUE"
IF 1 THEN PRINT "TRUE"
IF 42 THEN PRINT "TRUE"

Here’s a simple program that shows this:

10 FOR A=-2 TO 2
20 PRINT A,;:IF A THEN PRINT "TRUE" ELSE PRINT "FALSE"
30 NEXT

BASIC returns either -1 (TRUE) or 0 (FALSE) from a comparison, but IF only cares about “not zero” as true, and treats only 0 as false. That logic makes sense. “IF condition is true THEN do something”.

If you were trying to specifically test for 0 or -1, you would have a different result:

IF A=0 THEN PRINT "FALSE" ELSE IF A=-1 THEN PRINT "TRUE"

That would not catch anything that wasn’t a 0 or -1, so you’d really want to add a bit more:

IF A=0 THEN PRINT "FALSE" ELSE IF A=-1 THEN PRINT "TRUE" ELSE PRINT "UNKNOWN"

I’ll mention this again in a moment…

Let’s see what the BASIC parser is trying to do when it sees something like this:

A=B=4

What does that mean? A= tells us there is an assignment, then after that, then B=4 is what we’d like for it to be, and B=4 is a test. In Chet’s case…

A=B=C=D=4

We might feel all variables would come back as 4, but the variables appear to be completely left alone:

10 A=0:B=1:C=2:D=3
20 A=B=C=D=4
30 PRINT A;B;C:D

Running that will print…

 0  1  2  3

The key part is “appear to be completely left alone”. There is something happening that we are not seeing. If you change the code to set the variables to 1, 2, 3 and 4, and then try to set all of them to 5, you now see more of what is going on:

10 A=1:B=2:C=3:D=4
20 A=B=C=D=5
30 PRINT A;B;C:D

Running THAT version will print:

 0  2  3  4

Now we can see that A, which starts out as 1, is getting set to 0. Something is being assigned after all. If you break it down, here it what you see:

A=1:B=2:C=3:D=4
PRINT A=B
0
PRINT B=C
0
PRINT C=D
0

Individually, each of those tests returns 0 for FALSE. Since we see that A is getting set to 0, it is getting assigned the result of the first test after it: B=C. If you try this, you would get the same result in A:

A=1:B=2:C=3
A=(B=C)
PRINT A
0

That makes sense. And if the parser is just going through the line, automatically grouping the tests, perhaps something like this:

A=1:B=2:C=3:D=4
A=(B=(C=D))

And THAT looks exactly like what we are getting.

  • C=D returns 0, false.
  • B=0 (the result of C=D) returns 0, false.
  • Then A is assigned 0.

Could it be as simple as that? Somehow BASIC has to know if something is an assignment or a test, and perhaps as it scans forward, finding an additional “=” is enough to start it looking for tests rather than assignments. (I bet William Astle already knows how this works, and maybe he will see this and comment.)

Chet’s code shows BASIC does not work like we might expect, especially if we are used to how things work in languages like C. In C, it would look like this:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
int a,b,c,d;

a=1;
b=2;
c=3;
d=4;

a=b==c==d;

printf ("a=%d b=%d c=%d d=%d\n", a, b, c, d);

return EXIT_SUCCESS;
}

Notice the use of double equals “==” in the assignment line. If you run that in C, you get the same results as BASIC:

a=0 b=2 c=3 d=4

The thing C does differently is that when you have an assignment, that code block returns the value of the assignment, since it knows it is an assignment:

printf ("a=1 returns: %d\n", a=1);
printf ("b=2 returns: %d\n", b=2);
printf ("c=3 returns: %d\n", c=3);
printf ("d=4 returns: %d\n", d=4);

That would print:

a=1 returns: 1
b=2 returns: 2
c=3 returns: 3
d=4 returns: 4

And in BASIC, the “a=1” if being seen as a test will return either -1 (if false) or 0 (true).

In C, we have “==” to change the behavior from assignment to test:

a=1;
b=2;
c=3;
d=4;

printf ("a==1 returns: %d\n", a==1);
printf ("b==2 returns: %d\n", b==2);
printf ("c==3 returns: %d\n", c==3);
printf ("d==4 returns: %d\n", d==4);

Above, that prints:

a==1 returns: 1
b==2 returns: 1
c==3 returns: 1
d==4 returns: 1

In C, 1 is true, and 0 is false. Had the variables been initialized to something that made the tests for 1, 2, 3 and 4 invalid…

a=42;
b=42;
c=42;
d=42;

printf ("a==1 returns: %d\n", a==1);
printf ("b==2 returns: %d\n", b==2);
printf ("c==3 returns: %d\n", c==3);
printf ("d==4 returns: %d\n", d==4);

…you would see that the value returned from the “a==1” test would be 0 for false.

a==1 returns: 0
b==2 returns: 0
c==3 returns: 0
d==4 returns: 0

If BASIC forced the use of LET for an assignment, or used “==” for test instead of “=”, then it could figure out what we mean when we try “A=B=C=D=5″” or whatever. BASIC would know that “D=4” is an assignment, and to return 4, versus “D==4” being a test, and returning true 0 or false -1.

But it doesn’t.

Happy new year!

3 thoughts on “A=B=C=D in BASIC and C

  1. William Astle

    LET was actually required originally simply because every statement had to have a keyword associated with it. It has nothing to do with identifying assignment vs comparison. It just turns out not to be necessary since the absence of any other keyword at the start of the statement unambiguously means assignment. Imagine there’s an invisible LET before the assignment statement – that’s easentially how Color Basic works. LET doesn’t come until Extended Basic and it literally just jumps to the assignment handler in Color Basic.

    The primary difference between C and Basic is that in C, assignment is an operator that returns a value. In Basic, assignment is a statement. Any case that isn’t assignment is comparison. That means there is no ambiguity for the interpreter. An assignment statement looks like “[LET] = “. Anything evaluated inside must necessarily be an operator, and, thus is comparison. Same for the IF condition or arguments to PRINT.

    The sequential comparisons are actually evaluated left to right as well because they have the same precedence. So it actually evaluates B=C first.

    Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.