Parallel Assignments

The Wikipedia entry for the Extended Euclidean Algorithm includes this bit in it's Pseudocode section:
For simplicity, the following algorithm (and the other algorithms in this article) uses parallel assignments. In a programming language which does not have this feature, the parallel assignments need to be simulated with an auxiliary variable. For example…

(old_r, r) := (r, old_r - quotient *r)

is equivalent to
prov := r;
r := old_r - quotient * prov;
old_r := prov;
and similarly for the other parallel assignments.

What the author could have said was that by the syntax

( var1, var2, … varN ) := ( expr1, expr2, … exprN )
he means that all expr are to be evaluated using values of the vars as they were prior to the statement and the vars are updated after all the exprs are evaluated. Technically, his example doesn't really say that, we must infer the generalization from the two-variable example.

The Rexx equivalent seems more natural to me.

PARSE VALUE expr1 expr2exprN WITH var1 var2varN
makes it clear that all the expressions are evaluated before the template is applied.

The "pseudocode" in the article can be converted line for line to correct Rexx.

function extended_gcd(a, b)
    s := 0;    old_s := 1
    t := 1;    old_t := 0
    r := b;    old_r := a
    while r ≠ 0
        quotient := old_r div r
        (old_r, r) := (r, old_r - quotient * r)
        (old_s, s) := (s, old_s - quotient * s)
        (old_t, t) := (t, old_t - quotient * t)
    output "Bézout coefficients:", (old_s, old_t)
    output "greatest common divisor:", old_r
        
extended_gcd: procedure; a=arg(1); b=arg(2)
 s = 0; old_s = 1
 t = 1; old_t = 0
 r = b; old_r = a
 DO WHILE r \= 0
    quotient = old_r % r
    PARSE VALUE r old_r − quotient * r WITH old_r r
    PARSE VALUE s old_s − quotient * s WITH old_s s
    PARSE VALUE t old_t − quotient * t WITH old_t t
 END
 RETURN old_s old_t old_r

Multiple Assignment

"Parallel Assignment" is just a special case of
PARSE VALUE … WITH template
since template can include "directives" that allow one template to define more variables than there are expressions between VALUE and WITH. For example just the "position" directive with position=1 allows a construction such as:
PARSE VALUE tmid(visitor.sch.g) tmid(home.sch.g) vscr.sch.g hscr.sch.g typ.sch.g ,
       WITH vid                 hid              vscr       hscr       typ       ,
          1 vid.g               hid.g            .
Ex 1
which makes two copies of the first two expressions and single copies copies of the next three with "simplified" names. The first two expressions define new variables and the other three are there just to make copies of (stem).sch.g that can be referenced just as (stem)

Such a construction could be called "multiple parallel assignment." I use continuation and whitespace to make the assignment part of "parallel assignment" easier to read.

Pseudocode shorthand and even some formal languages include constructions like

x = y = z = t = value
as a form of multiple assignment of value to each of variables x, y, z and t. In Rexx that is an expression that evaluates to x = 0 for every value other than 0 for which it evaluates to x = 1. The variables y, z and t are unchanged by the statement.

The intended result is

 x = value; y = value; z = value; t = value
which is correctly expressed in Rexx by
PARSE VALUE value WITH x 1 y 1 z 1 t 1 .

Assignment in General

File 'Comp.txt' contains the following fields separated by the ASCII horizontal tab character:

 IX BUCK MCNT TIEBRK BORDA BRANK PWRNK TNAME AVGRANK GEOMEAN HARMEAN 
and the first line consists of those "column names" similarly separated by tabs. (Think of a spreadsheet.)

The following makes a list of the ranked teams (key.i), sets a flag for each team that is in the list (ranked?.tid) and saves the values of BUCKRANK, BRANK, AVGRANK, GEOMEAN and HARMEAN for each ranked team.

 tab = '09'x 
 key. = ''
 ranked?. = 0
 discard = LINEIN('Comp.txt') /* file has a header line */
 DO i=1 WHILE LINES('Comp.txt') > 0
    PARSE VALUE LINEIN('Comp.txt') ,
           WITH . (tab) buckrank (tab) . (tab) . (tab) . (tab) brank (tab) tname (tab) avgrank (tab) geomean (tab) harmean (tab) .
    PARSE VALUE tmid(tname) 1             buckrank      brank      avgrank      geomean      harmean ,
           WITH tid         ranked?.tid   buckrank.tid  brank.tid  avgrank.tid  geomean.tid  harmean.tid ,
              1 key.i       .
 END
 key.0 = i-1 /* account for the increment before the WHILE test that terminates the loop */
 z = STREAM('Comp.txt','C','CLOSE')
Ex 2
The first PARSE just allows the relevant fields from the record to be referenced as variables. The second uses one of them to calculate the index that allows other parts of the program to access them by team, sets a flag (by team) that indicaates the values exist, and then saves the values using that index. The second is equivalent to:
 tid = tmid(tname)
 ranked?.tid = 1
 buckrank.tid = buckrank
 brank.tid = brank
 avgrank.tid = avgrank
 geomean.tid = geomean
 harmean.tid = harmean
 key.i = tid
Performance comparisons of PARSE to the equivalent number of assignment statements are ambiguous. Separate assignment of the same literal to multiple variables is slightly faster than the equivalent PARSE VALUE constant WITH 1 var1 1 var2 1 … but the more "work" performed by the template the more likely PARSE VALUE … WITH is faster.


† Note that the first "=" in x = y = z = t = value is an assignment and the remainder are comparison operators. Assuming x, y, z and t are uninitialized before the statement, it is evaluated as follows:
 x = ( y = z ) = t = value
 x = ( 0 = t ) = value
 x = ( 0 = value )
which is "x = 0" unless value is 0 in which case it is "x = 1".