What does this line: `T=C/2=INT(C/2)` do? Why is it valid syntax?

I do not understand line 80 of the short Applesoft BASIC program below. Didn't even know it was possible to have a single instruction be T=C/2=INT(C/2). Naturally, I tried breaking this line up / various dissections, all of which broke the program and didn't help me learn what this is really doing.

10  S=4
20  HOME : GR
30  FOR C=0TO15 : COLOR=C
40  FOR X=0TO1
50  VLIN 0,39 AT X+S
60  NEXT X
70  HTAB S+1 : VTAB 21+T : PRINT C;
80  T=C/2=INT(C/2)
90  S=S+2
100 NEXT C

Would appreciate learning from everyone's collective knowledge. When I get back to my big computer, I will cite the Apple II, IIe 'graphics' book where I found this low-res colorbar BASIC program.

• Apparently, the two = symbols are parsed differently: the first as assignment and the second as equality test. Here, C would have used == for the latter. May 29 '21 at 12:56
• I first learned about boolean values in Applesoft by reading Beagle Bros programs. I don't think this behavior is documented in the Apple manuals. Multiplication can be handy, e.g. Y = (x > 7) * 10 will set Y to 0 or 10 based on the value of X. You can do a similar thing in C, though you have to be careful with older implementations. May 29 '21 at 14:46
• This seems to be COLOR DEMO 2, distributed on a tape bundled with the Apple II kit, at least judging by the output: the Apple II BASIC manual contains an identical screenshot (p. 32). May 30 '21 at 7:58
• not having distinct equality and assignment operators was a mistake. May 31 '21 at 11:06
• Having only one = operator does mean that you can't use some constructs popular in other programming language like multiple assignment (a = b = 0) or assignments as part of loop conditions (while ((c = f()) >= 0)), but these can be easily worked around. Jun 8 '21 at 23:49

Explaining what this line does is easy enough: it checks if C is even by dividing it by 2 and comparing the result to its floor, then stores the result of the comparison in the variable T. Comparisons are expressions like any other: they return a non-zero value (in the Applesoft dialect, 1) if the relation holds and zero otherwise. The IF statement evaluates an expression, and if it returns non-zero, executes the statement given after the THEN keyword. The line can thus be re-written like this:

T = (C/2 = INT(C/2))

or this:

T = 0 : IF C/2 = INT(C/2) THEN T = 1

and remain functionally the same.

Interestingly (as @another-dave points out), it was not always a feature of BASIC that relational operators could appear in any expression. The original Dartmouth BASIC did not allow it: the fourth edition manual (1968) defines a ‘formula’ to contain arithmetic operations only (§1.2, pp. 11–15), while an IF statement could perform a single comparison between two such ‘formulas’ (§1.2, p. 15; §1.7.5, p. 35). There were no logical connectives like AND, OR or NOT either. Dartmouth BASIC also included simultaneous assignment to multiple variables in a single statement: LET A = B = 2 would assign 2 to both A and B (§1.7.1, p. 33).

One of the earliest BASIC dialects that unified relational and arithmetic expressions was HP Time-Shared BASIC (1976). Doing so introduced a grammar ambiguity with multiple assignment, resolved in the manual as follows (‘LET Statement’, p. 11-46):

The rule that the equal sign (“=”) is an assignment operator only holds as long as numeric variables occur in the replacement list. If a numeric constant appears, followed by an equal sign, that equal sign is treated as a relational operator. For example, in A=2=B the first “equal sign” (=) is treated as an assignment operator and the second is treated as a relational operator.

(Presumably parentheses would also do the trick.)

Apple’s Integer BASIC (1977) followed suit in unifying arithmetic and relational expressions (pp. 56–58 in the manual), though it omitted multiple assignment. Microsoft dialects (1975) did similarly, though in the latter truth was usually represented as −1; this allowed logical connectives to perform double duty as bitwise operators. In those dialects, the ambiguity is instead resolved by the strict dichotomy between statements and expressions: if an = appears in statement position, it means assignment, while in expression position it refers to comparison. As lone expressions are not statements, unlike for example in C, the meaning of = is unambiguous.

• Comments are not for extended discussion; this conversation has been moved to chat. May 30 '21 at 15:13

The line in question is T=C/2=INT(C/2)

The first '=' is a variable assignment.

The second '=' is part of the expression and is an equality test.

The expression returns a boolean result, which is stored in T. The expression means 'is it true that C/2 is equal to the integer result of C/2'. In other words, is C a multiple of 2.

The values used for Boolean 'true' and 'false' vary between programming languages but are often the integer values 0 and 1.

A trick I saw along the same lines in an early BASIC was the line A=A=0.

This would toggle A between 0 and 1. If A was 0, then the Boolean test expression A=0 returned 1. If A was 1, then A=0 returns 0.

This is a compact and space-saving form in machines tight for RAM. But these days, clarity is more important in the more generously RAM systems we're often using or embedding.

• A=A=0 more commonly toggles between 0 and -1, though on Sinclair BASIC it does 0 & 1. May 29 '21 at 19:08
• @scruss In ZX81 BASIC I would write LET A=NOT A anyway, as that only takes 5 bytes, which is less than the 7 bytes simply for the numeric constant 0.
– Neil
May 31 '21 at 13:28

Line 80 appears to be equivalent to the PHP short logic example in the following small program to output from a function;

<?php

function ternary (\$C) {

\$T = ( is_int( \$C / 2 ) ) ? 1 : 0 ;

return (\$T);

}

echo ternary (0);

echo ternary (1);

echo ternary (1.1);

?>

The above example will output:

100

80 T=C/2=INT(C/2)

In the original program the variable T is set to logical True or False based on the evaluation of a test for even/odd in C/2=INT(C/2). The evaluants are equal when C is an even number and rational so T is set to logical True. When C is odd or a decimal it evaluates to False and T is set to False.

The original program is approximately equivalent to:

IF C/2 = INT(C/2) THEN T=1 ELSE T=0

Probably the handling of the case of a negative value for C is dependant on the specific operating system.

In the example program we perform the same test by comparing \$C in an evaluation with integer. If we simply compare \$C we find is_int(\$C) is true for every rational number, by dividing by 2 as is_int(\$C/2) we find the test is only true in the case of all rational even numbers. In both the original program and the example program the output of the evaluation is logical True or False and the variable is assigned this value.