[J3] Why is += missing?

Kurt W Hirchert hirchert at uiuc.edu
Mon Aug 30 20:32:42 UTC 2021


As often happens, this thread seems to have died out before I had my 
thoughts organized. Since a couple of my ideas seem to be ones no one 
else has expressed, I will go ahead and post this message. Read it or 
skip it as you feel appropriate.

_Random observations that may not be terribly significant_

If there were any chance of doing only += without the other /op/= 
variants, it might be worth noting that A-=B can be simulated by A+=-B.

The discussion about /= may be a bit of a tempest in a teapot. As far as 
I can tell, there is no ambiguity for compilers, and the confusion for 
human beings may not be that great. In the existing language, :, =, =>, 
/, and * all have varying meanings in different places, and that doesn’t 
seem to confuse people. Furthermore, in an expression, /= is a 
two-character representation of a single mathematical symbol, but the 
assignment version is likely to be perceived as just a specific example 
of a representation of an /op/followed by =, so the mental parsing may 
be quite different.

If instead of writing
a_long_and_or_complicated_identifier = 
a_long_and_or_complicated_identifier + more_stuff
you write
a_long_and_or_complicated_identifier = &
a_long_and_or_complicated_identifier + more_stuff
(lining up the repeated part on successive lines), you can minimize many 
of the problems that were offered as motivation for +=. Of course, this 
doesn’t mitigate the tedium of typing all that twice or the general 
verbosity.

Is += one symbol or two successive symbols? The answer has the immediate 
impact of saying whether a blank is allowed between the two characters, 
but there can also be deeper semantic issues.

If a program defines OPERATOR(+) (and possibly ASSIGNMENT(=)) for a 
derived type, can += be used on that type, or is += defined only for 
intrinsic numeric types? If so, can this intrinsic interpretation be 
overridden (with an ASSIGNMENT (+=) interface)?  (The question of one 
symbol or two may have a bearing on this question.)

When we were working on the array computation features in Fortran 90, I 
developed the habit of looking at computations in loops and asking 
myself whether they could be converted to array computations. During 
this discussion, I found myself asking how many potential uses of += 
with a long and/or complicated left-hand side are computing sums that 
could be done with some form of SUM. This probably isn’t a relevant 
question as long as there are enough that can’t reasonably be done with SUM.

_Two observations that seem more significant to me_

My first significant concern about += is the “slippery slope”. As soon 
as += was mentioned, -=, *=, and /= were expected. Since that accounts 
for four of the five numeric operators, it was not long before **= was 
mentioned. Other types data were not discussed here, but Perl, example, 
has the equivalents of //=, .AND.=, and .OR.=. In the extreme, this 
might lead to .DefinedBinaryOp.= so that there would be no necessity to 
remember which binary operators can precede the =. (I note in passing 
that if one likes the +.= solution to the /= issue, .OR..= looks a bit 
funky to me.)

My second significant concern is that even if all these += cousins are 
added to the language, this will still address only “the tip of the 
iceberg”. Consider the following examples: (In the interest reducing my 
typing, I will use ALAOCI in place of a_long_and_or_complicated_identifier.)
ALAOCI = MAX(ALAOCI,something_else) ! or MIN
ALAOCintegerI = MOD(ALAOCintegerI+1,n)
ALAOCmatrixI = MATMUL(ALAOCmatixI,another_matrix)
ALAOCintegerI = IOR(ALAOCintegerI,2**k) ! set bit k
ALAOCintegerI = IAND(ALAOCintegerI,NOT(2**k) ! clear bit k
ALAOCcharI = chars//ALAOCcharI
! prepend chars (cf. Using //= to append chars)
ALAOCcharI = TRIM(ALAOCcharI)//chars
! better append for non-ALLOCATABLE char variables
ALAOCcharI = ‘[‘//TRIM(ALAOCcharI)//’]’ ! add brackets
ALAOCcharI = ALAOCcharI(2:INDEX(ALAOCcharI,’]’)-1
! remove brackets
ALAOClogicalI = .NOT.ALAOClogicalI ! toggle variable
ALAOCnumericI = -ALAOCnumericI ! negate variable
ALAOCrealI = LOG(ALAOCrealI) ! convert to logarithmic data
ALAOCrealI = EXP(ALAOCrealI) ! convert back
ALAOCpointerI => ALAOCpointerI%next ! remove from linked list

_Solutions?_

Michael Klemm pointed out a proposed feature in Ada, using @ in the 
right-hand side of an assignment as a stand-in for the left-hand side of 
that assignment. Thus, instead of simplifying
ALAOCI = ALAOCI + whatever
to
ALAOCI += whatever
you could write
ALAOCI = @+whatever
If I correctly managed the switch to a monofont, it should be apparent 
that this is only one character longer than the += version and still 
much shorter than the original version. (If the /= issue leads to the 
use of +.=, the Ada-like version would be the same length.) Unlike +=, 
it applies equally well to “the entire iceberg”. It appears to avoid all 
the syntactic and semantic issues that came up with +=. Unless one is 
hellbent on copying C, I would consider += to be an inferior solution to 
the problem and encourage that it be abandoned in favor of pursuing an 
Ada-like solution (or something better if someone can come up with it).

Although I like the basic idea of this feature, I will offer a couple of 
quibbles: I am not overly fond of the character @ for this purpose, 
because it “looks funny” to me and because I generally prefer using 
characters in use in the language over using new characters. My first 
thought for a more Fortran-like stand-in was .LHS. (or some other .WORD. 
if you don’t like LHS). This opens the possibility of compatibility 
issues in programs that already use .LHS. as a defined operator. I 
believe all these issues can be resolved, but people may not like my 
resolution alternatives. Since underscore is not allowed as the first 
character in a name, _LHS_ is another alternative that might look 
slightly less Fortran-like but would avoid those issues. Both of these 
are somewhat longer than the single at sign, so I also offer .. (i.e., 
two consecutive periods) or _ (i.e. a single underscore). At the moment, 
I think I like the single underscore best, but I haven’t spent much time 
thinking about this issue.

Given that defined assignment interfaces make assignment statements an 
alternative way to CALL a subroutine, it might be nice for consistency 
if in a CALL statement , @ (or whatever is chosen) were made a stand-in 
for the first subroutine argument.

Van Snyder pointed out a proposal of his that attempted to be more 
general, allowing stand-ins to be defined for more than just the 
left-hand side. Most of the time, I tend to prefer general solutions 
over more specific solutions, but in this case, the syntax needed to 
handle the case of a stand-in for only the left-hand side is more than 
in the Ada-like proposal, and it appears to me that there are orders of 
magnitude more cases where one could use a stand-in for the left-hand 
side than for the use of other stand-ins. Thus, I do not see Van’s 
proposal as a good alternative to the Ada-like feature. However, if 
there are enough uses for these other stand-ins, it might be worth doing 
Van’s proposal (or its equivalent) in addition to the Ada-like proposal, 
provided one can resolve their incompatible uses of the at sign character.

While I like the functionality of Van’s proposal, I don’t particularly 
like its syntax. In my opinion, intermixing the stand-in definitions 
with the rest of the statement hurts readability, and I have my usual 
reservations about introducing the at sign character in this way, so I 
will suggest an alternative with equivalent functionality but a 
different syntax:

As Van points out, this is essentially ASSOCIATE limited to a single 
statement. Why doesn’t Van want to simply use ASSOCIATE? I assume that 
it is because in cases like this, the extra syntactic overhead of the 
ASSOCIATE construct adds painful verbosity. What can we do to reduce 
that overhead? Consider for a moment the IF statement and the IF 
construct. The IF statement
IF (/logical-scalar-expression/) /action-stmt/
is essentially a lower-overhead way of writing
IF (/logical-scalar-expression/) THEN
/action-stmt/
END IF
What I would suggest is the addition of a simple ASSOCIATE statement
ASSOCIATE (/association-list/) /action-stmt/
that would be the equivalent of
ASSOCIATE (/association-list/)
/action-stmt
/END ASSOCIATE
This alone cuts more than half of the syntactic overhead. My more 
radical suggestion would be to make the keyword ASSOCIATE optional in 
this form:
[ASSOCIATE] (/association-list/) /action-stmt
/Unless I’ve missed something, this remains unambiguous, but would allow 
you write something like
(V=>ALAOCI) CALL backwards_set(V+whatever,V)
It is slightly more verbose than Van’s equivalent
CALL backwards_set((V @ ALAOCI)+whatever,V)
but I find putting the stand-in definition(s)in front to be more 
readable, and I suspect using an extension of what we already have may 
be more acceptable to the committee than an entirely new syntax.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.j3-fortran.org/pipermail/j3/attachments/20210830/25fa2127/attachment-0001.htm>


More information about the J3 mailing list