-
Notifications
You must be signed in to change notification settings - Fork 17
Augmented assignment (+=) #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This is a very common request, so we should have an issue for it and document why such ideas were not implemented yet. The last time I have seen this discussed is with this proposal: https://j3-fortran.org/doc/year/19/19-111r1.txt. It actually has reason why it was rejected. (The |
I think, just doing the two 'positive' operators would already help a lot. '-=' and '/=' are much less needed and can be circumvented like this: a = 1.0_real64
do i=1, 10
a -= vector(i)
end do Can be written as: a = 1.0_real64
a *= -1
do i=1, 10
a += vector(i)
end do
a *= -1 And analogous for division (maybe in line with the loop statements, to make the purpose clearer?): a = 1.0_real64
a = 1/a; do i=1, 10
a *= vector(i)
end do; a = 1/a While this seems messy, it prevents the 'space ship operator' from being valid: a -=- 1 ! this gives the same as 'a += 1' The main point however should be, that '-=' and '/=' are much less needed. I would really advise against another operator for '/='. That would be quite counter-intuitive. PS: since the referred paper was in parts rejected due to a missing use case, I will add one to the original post =) |
Good point: the proposal would be to only add |
The important aspect of BCPL's assignment operator(s) is that the left-hand side of the assignment is evaluated only once; e.g., if Fortran were to acquire such a feature, in |
I referenced your point in the original post. |
Additionally, this feature should specifically state whether the augmented assignment is atomic or reducing or disallowed in some circumstances (shared variable in |
I'd suggest also adding |
For once I agree with the committee for not adding something. 😃 I think these variants are best left to C-based languages. I don't think they are very "Fortranic". Aesthetically I've always thought they were weird, and I don't think we really gain much by having them (except new confusion about |
@libavius wrote:
The above "hypothetical code" can be written using current Fortran standard as: a = 1.0_real64 - sum(vector) |
In fact you can write it as a = 1 - sum(vector) But I think @libavius's point was to show how it can be used. A typical loop where I use i = 1
j = 1
do j = 1, size(nl)
n = nl(j)
zeta = zl(j)
l = ll(j)
do m = -l, l
nlist(i) = n
zetalist(i) = zeta
llist(i) = l
mlist(i) = m
i = i + 1
end do
end do Where it is kept as a running index. I am leaning towards @jacobwilliams's comment above (#113 (comment)) that |
@FortranFan I know, thanks anyway for the hint. A more elaborate use case: type Molecule_t
type(Atom_t), allocatable :: atoms(:)
contains
procedure, pass :: Get_electrons_number => Molecule_t_get_electrons_number
end type Molecule_t
contains
function Molecule_t_get_electrons_number(this) result(electrons_number)
class(Molecule_t), intent(in) :: this
integer :: electrons_number
integer :: i
electrons_number = 0
if (ALLOCATED(this%atoms) then
do i=1, SIZE(this%atoms)
electrons_number = electrons_number + this%atoms(i)%get_electrons_number()
end do
end if
end subroutine Molecule_t_get_electrons_number The loop would–in my opinion–be easier readable like this: do i=1, SIZE(this%atoms)
electrons_number += this%atoms(i)%get_electrons_number()
end do @FortranFan I could write this with the electrons_number = SUM([( this%atoms(i)%get_electrons_number(), i=1, SIZE(this%atoms) )]) EDIT: (or easier, but still with allocation, if electrons_number = SUM(this%atoms%get_electrons_number() ) This is in addition to the possible reduction of function calls that @klausler mentioned. @jacobwilliams jup, the confusion with |
@libavius for your latest use case, I would recommend to change type Molecule_t
real(dp), allocatable :: electrons_number(:)
...
contains
procedure, pass :: Get_electrons_number => Molecule_t_get_electrons_number
end type Molecule_t And then change the loop to just: electrons_number = sum(this%electrons_number) |
@certik The idea in this case would be, that a molecule has atoms but an atom can also exist without a molecule. To avoid code duplication I don't want the molecule to have a member 'electrons_number' or implement atom-related functions again but rather iterate over its atoms. |
The way I do this in my electronic structure codes is that I do not have an Atom type at all. So if your molecule has only one atom, then the length of all the arrays will be just 1. There is no code duplication and in fact things run much faster. |
@septcolor |
@cmacmackin indeed, the approach I suggested is flat and exposed. It's not encapsulated. It has the huge advantage that it works well with current Fortran, and typically optimizes really well and runs fast, and it's actually typically simpler in terms of lines of code (as demonstrated above). The disadvantage is that if you change the underlying representation, you need to rework your whole code. So with my approach, one has to design things well, but one can use the current Fortran language. For the encapsulated approach, Fortran does not have the best tools currently. |
As for the syntax, what about Espen Myklebusts proposal in #80, using the
It would not cause any conflicts with current operators, so it could be also used for division (I would find it really strange, if
(example by Espen Myklebust). |
@aradi is your idea different to the proposal I linked at #113 (comment), which was rejected? |
@certik Yes, Espen Myklebusts proposal has in my opinion a considerably lower complexity, as the one you have linked in. The |
@aradi thanks for the clarification. (For the record the |
I think this'd be superb elegant =) EDIT: After some time, I'm not so sure anymore. It is also a bit of syntactic overload... |
I like the idea of using a symbol in the right-hand side to denote the current value of the left-hand side, but |
I think the reasons outlined why augmented assignment probably won't work out are true. But I would be in favor of the "pronoun" proposal that @certik mentioned. There are a variety of languages starting to support this kind of feature (most commonly in languages that have a pattern matching feature). One might think of this as basically syntactic sugar for an associate block with only a single line in it. For example:
would be directly equivalent to:
So this could basically be treated as syntactic sugar, not really a new functionality. |
|
Perhaps, it is too late to discuss this but somehow I have not seen anyone mentioning another important aspect of the compound/augmented assignment: It allows to perform more efficient in-place operations, such as Another similar example is that if we have a type like this
and there is a frequent need to do operations like this -- |
There is a renewed discussion at the J3 mailinglist about this feature. I created a prototype implementation in a compiler: https://gitlab.com/lfortran/lfortran/-/merge_requests/1286 |
ASSOCIATE can't be used to form a mutable association with every variable. Variables with vector-valued subscripts, and coindexed references, become immutable copies of expressions if they appear as "right-hand" sides of selectors in ASSOCIATE & al. If you want to use ASSOCIATE to get a mutable abbreviation of the variable of an assignment-stmt, it won't always work. I prefer the idea of using a symbol in the expr of assignment-stmt to denote (a copy of) the variable, e.g. "var = @ + expr". It would work with any operation (including those spelled like |
Ada extends the notion of '@' so that you can do things like this:
c(i,j) = cmplx(real(@) + 1.0d0, aimag(@) * 3.0d0, real64)
The '@' can stand-in for the entity on LHS as many times as needed and as a sub-expression on the RHS.
So, this generalizes what you could achieve with operator assignments like +=.
|
PS: It's required that the expression that is bound via '@' is evaluated only once, so that it's clear how many times functions and the likes are evaluated then they occur multiple times as part of a '@'. |
I do quite like the idea of a symbol for a shorthand for the lhs. I feel almost certain that using |
Some further thought about the use of a special symbol (say
|
Another discussion of this proposal: https://fortran-lang.discourse.group/t/updating-assignment-operators/2129 |
First of all, I think that the idea (originally by Espen Myklebusts, I suppose) with a LHS designator instead of dozens new operators is great and offers a syntactically simple and flexible way of enhancing assignments. I could only suggest to use an existing Fortran association syntax to avoid introducing additional symbols. This way, the combined assignment-operation would look like: (lhs => container % array(:, :, i)) = lhs + fun(lhs)
(c => complex_array(i, j)) = cmplx(real(c) + 1.0_real64, aimag(c) * 3, kind=real64) etc. This is essentially a more "fortranic" development of the idea by @everythingfunctional . Such a construction can be considered as a one-line ASSOCIATE block, but, as @klausler has remarked, the restrictions inherent to the ASSOCIATE statement can be considerably relaxed in the new construction. Typical restrictions of the assignment statement should rather be applied. The advantage of such a syntax is that it does not introduce any new lexer elements and does not seem to create a clash with existing constructions. |
To me, the precise goal of the augmented assignment, as discussed here, is still unclear. Should it be simple syntactic sugar to abbreviate code (which would be for sure useful), or should it represent new operators, which one can also extend for user defined types (useful when designing efficient OOP-based abstract calculus concepts)? |
To me just |
A couple of points (from someone interested in having either |
@opeil @certik |
That is not the case with C's augmented assignment operators, not is it true with the proposals above.
This is also not the case. Instances where an augmented assignment statement might require use of a temporary would also be in need of a temporary if written without the augmentation.
Fortran allows new user-defined operators but not new assignment statement symbols. The most general proposal for augmented assignments -- namely, the introduction of a symbol to represent the previous value of the left-hand side of the assignment -- avoids the problems with |
I like a lot the idea of having a placeholder for the lhs, as this would abbreviate long expressions in many cases. But then, it would be still syntactic sugar only, as programmers won't be able to extend it for their own types in order to provide efficient in-place implementations for them. (As one would be able to do by overriding the |
Neither an augmented variant of assignment ( One of the reasons the alterative approach of using a symbol that designates the previous value of the left-hand side is more natural than augmenting variants of assignment(s) is that you can use your user-defined |
Maybe there should be an independent issue proposing the LHS symbol? While its usage has some overlaps with augmented assignment, it is really a different thing as it extends way beyond what augmented assignment can do, but is less intuitive to use and read (especially for people who switch from other languages). |
@klausler OK, I see your point. But, then, similar to what have been proposed above, an extension of the current
It won't be as compact as other forms proposed, but it would be for sure a very natural extension of the current language. Actually, augmented assignment operators (
If any of the two is not given, I'd rather go with the LHS-association. That seems to fit more to the current language and would allow for a much more flexible usage. |
|
In the renewed discussion mentioned in #113 (comment), there appears the idea that
might actually work, since assignment isn't allowed in expressions, so there should be little risk of mixing up
with
as assignment for both compilers and human code readers. While not ideal, I'd take such a solution gladly over lines such as
|
allow writing
a += b
instead of
and
a *= b
instead of
I think this feature is quite important, since the lack of it misleads programmers towards the use of (too) short variable names:
I would write like to write this:
electrons_number += charge
But maybe prefer this
over this abomination of a line =)
This should not end in a discussion whether to use long variable names or not, let's just agree, that they are better sometimes.
This is a second use case
This is a third (and fourth) use case
The text was updated successfully, but these errors were encountered: