[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