!standard 5.2.1 (0) 09-11-03 AI05-0187-1/01 !class amendment 09-11-03 !status work item 09-11-03 !status received 09-11-02 !priority Low !difficulty Medium !subject Shorthand for assignments with expressions naming target !summary A syntactic shorthand is introduced for assignment statements with expressions that include references to the target object. !problem It would be useful to have a shorthand for an assignment that updates its target object with an expression involving the target. That is, for common assignments of a form such as: := ; or even more generally of the form: := ; the objective is to be able to write this without repeating the name of the target object. The motivation here would be to aid readability, because often such assignments involve an object with a longish identifier (as Ada tends to encourage) or a complex compound name, and repeating the full name in the assignment expression is unwieldy and tends to make the statement too heavy and hence less readable. !proposal C and C++ allow shorthand forms for assignment such as "SomeObject += 1", and the proposal is to add a similar capability in Ada. This could be done using the same kind of syntactic notation as C (e.g., A +:= B), that would allow cases involving binary operators, or using a more general approach that would work for other forms of expression, by adding a new form of primary that would stand for the left-hand side. The latter alternative would permit arbitrary use of the target object's name on the assignment's right-hand side (e.g., Target_Object := Func (T_O)). (Note: There are some ARG members who prefer the first approach, and others who prefer the second, so further discussion is needed before writing up any details.) !wording ** TBD ** !discussion ** TBD ** !examples ** TBD ** !ACATS test ACATS C-Tests are needed to check this feature. !appendix From: Gary Dimukes Sent: Monday, November 2, 2009 12:57 PM While we're on the subject of minor proposals to consider for the next revision, and since this is the last opportunity to put them on the table, there's one that I'd like to float that pops up in my mind from time to time. It would be nice to have a shorthand for making an assignment that updates its target object using an expression that involves the target. That is, for common assignments of a form such as: := ; to be able to write this without repeating the name of the target object. The motivation here would be to aid readability, because often such assignments involve an object with a longish identifier (as Ada tends to encourage) or a complex compound name, and repeating the full name in the assignment expression is unwieldy and tends to make the statement too heavy and hence less readable. C and C++ allow shorthand forms for assignment such as "SomeObject += 1", and I'm proposing to allow something similar, but more general, for Ada. Rather than extending the syntax for the assignment token, I would add a new form of primary that would stand for the left-hand side. This would permit arbitrary use of the target object's name on the right-hand side (e.g., Target_Object := Func (T_O). If such a feature were to be added, the tricky part is to come up with a reasonable syntax for denoting the object. Adding a new reserved word presumablby won't fly (and there aren't any suitable existing reserved words), and using an identifier for this would be a bad idea in any case. Some short but reasonably distinctive and obtrusive token is what's needed. One fairly obvious choice would be Ada's existing <> token. That won't work though, because it clashes with Ada 05's addition of box defaults in aggregates (unless we were to syntactically restrict the new token's use, though I wouldn't recommend that). In the absence of any obvious existing token, and for purposes of discussion (if there's any interest in such), I'll suggest a new compound delimiter <<>> as a strawman, formed by sticking the existing left and right label brackets together. (Another choice could be '$', but that might be considered too U.S.-centric;-) The only other issue I see is to define the semantics of evaluating the symbol denoting the target object. It could be defined as a textual macro, so each occurrence of the name would be reevaluated, but I believe the more appropriate semantics would be to bind the name once, when the left-hand side name is evaluated, making it equivalent to a renaming. So each occurrence in the assignment expression denotes the value of the single object determined by the target name. (This means requiring evaluation of the target object before the expression, but that seems fine.) Is there any interest in considering this proposal? If so, I can take care of drafting the AI. **************************************************************** From: Tucker Taft Sent: Monday, November 2, 2009 1:16 PM I'd be more interested in just allowing the "=" syntax: X = Y; would be equivalent to X := X Y; except of course "equivalent" is never really just "equivalent" ;-). Inventing some other syntax to mean the LHS is just making Ada harder to read for non-Ada folks, while adding "=" would make it easier for non-Ada folks to learn to read (and write) Ada. **************************************************************** From: Randy Brukardt Sent: Monday, November 2, 2009 1:29 PM > Is there any interest in considering this proposal? If so, I can take > care of drafting the AI. I'm mildly interested in this idea. I'm not at all interested in Tucker's suggestion of copying C++, because I find that it is quite common to need this in function calls: Target := Func(Target, ...); Given Ada's equivalence of operators to functions, you sould have to be able to handle user-defined operators in a :=+ operator anyway. Moreover, the resolution would be messy (you'd have to handle operators where the Right operand is a different type). And that would give an unnatural incentive to name functions as operators if they commonly occurred in this form -- that seems exactly wrong. (We'd also need to add three character or more delimiters, something Ada does not already have. I don't know if adding new delimiters is actually a problem, but it surely would add to the costs of a new feature.) If Ada can do something *better* that existing languages, we at least ought to consider that. Blindly copying other ideas does little to enhance the case for using Ada. **************************************************************** From: Steve Baird Sent: Monday, November 2, 2009 5:59 PM > I'd be more interested in just allowing the "=" syntax: ... If we want to go with this approach, as opposed to the more general approach that Gary and Randy were discussing, I think a better way to define the semantics of = ; via an equivalence is in terms of an implicit rename declaration, as in declare : 'Type renames ; begin := operator ; end; **************************************************************** From: Robert Dewar Sent: Monday, November 2, 2009 11:11 PM > I'd be more interested in just allowing the "=" syntax: ... I agree that a simple form is better, though I think the A68 syntax is a better choice for Ada X +:= 1; I like the assignment symbol appearing, and in fact this is a better analog of the C practice than X += 1; **************************************************************** From: Robert Dewar Sent: Monday, November 2, 2009 11:12 PM > I'm not at all interested in Tucker's suggestion of copying C++, > because I find that it is quite common to need this in function calls: > > Target := Func(Target, ...); Yes, but I still find the proposal unwieldy and ugly, and I think I prefer to see things spelled out in a case like this. > If Ada can do something *better* that existing languages, we at least > ought to consider that. Blindly copying other ideas does little to > enhance the case for using Ada. I don't think this fancy proposal *is* better, I think it is too obscure. **************************************************************** From: Tucker Taft Sent: Monday, November 2, 2009 11:37 PM I guess I just find "+:=" uglier than "+=". Also, Algol 68 had to distinguish "+:=" from "+=:" and I don't think we have that issue in Ada (though I don't know what "+=:" meant!). **************************************************************** From: Robert Dewar Sent: Tuesday, November 3, 2009 6:43 AM Nor me, totally unfamiliar, are you sure this was in Algol68 **************************************************************** From: Tucker Taft Sent: Tuesday, November 3, 2009 7:37 AM Here is a hand-drawn Algol 68 syntax chart from an old ACM Communications. It shows both ":=" and "=:" (I think!): http://www.sofport.com:5055/ARG/algol-68-p39-peck.pdf **************************************************************** From: Robert Dewar Sent: Tuesday, November 3, 2009 10:53 AM Well the date suggests it may be preliminary, and I sure don't remember the other form, what would it mean? I may just have forgotten of course **************************************************************** From: Robert Dewar Sent: Tuesday, November 3, 2009 11:10 AM Anyway, never mind what A68 had, I prefer +:= because it makes it clear it is still an assignment, just as in C += is still clearly an assignment. **************************************************************** From: Gary Dismukes Sent: Tuesday, November 3, 2009 12:20 PM Looking at an Algol 68 textbook I have, it appears that the notation is only available for use as an alternative to +:= for character strings. It's called the "plusto" operator, and "h +=: r" is equivalent to "r +:= h", where r is of mode "ref string" and h is of mode string or char. **************************************************************** From: Brad Moore Sent: Tuesday, November 3, 2009 12:30 PM This is somewhat related to assignment shorthand, along the lines of improved notation possibilities... (I apologize if this is too far off topic, if there is any interest we can create a separate thread) It would be nice if we could optionally use infix notation more generally for boolean binary functions, instead of just operators. e.g. Instead of if Contains (Grocery_List, Radishes) if Less_Than (X, Y) if Is_Factor (3, 21) ... -- Is what a factor of what? Being able to write if Grocery_List Contains Radishes if X Is_Less_Than Y if 3 Factors_Into 21 Seems more natural. We do have a reasonable approximation with object prefix notation, but that only works for tagged types. eg. if Grocery_List.Contains(Radishes) But if one doesn't have a tagged type, you are stuck with prefix notation, unless you can overload an operator. Would there be any interest in this capability? **************************************************************** From: Robert Dewar Sent: Tuesday, November 3, 2009 12:57 PM > Being able to write > > if Grocery_List Contains Radishes > if X Is_Less_Than Y > if 3 Factors_Into 21 This really should be a completely separate topic, it has nothing to do with an assignment short hand. Personally I don't like it, and it has huge implementation consequences (it breaks the invariant that two identifiers cannot appear in sequence). ... > Would there be any interest in this capability? It's an interesting language capability (have a look at ABC for a fully developed version), but to me it does not fit well with Ada syntax. **************************************************************** From: Brad Moore Sent: Tuesday, November 3, 2009 2:09 PM OK, but maybe this does tie in with assignment short hand afterall. Suppose we said that an infix call had to be enclosed by <>. As in, if 3 21 This would address your concern about two identifiers appearing in sequence, and would help make it clearer that an infix notation is being used. Now suppose we extend this idea to also apply to binary procedure calls, in particular where the first formal is an in out parameter. Now suppose we added some predefined procedures for elementary types, eg. procedure "+" (Sum : in out Integer; Addend : Integer); Then we might be able to write using infix notation; X <+> 3; -- Equivalent to "+"(X, 3) or X := X + 3; or in C, X += 3; This gives us a shorthand notation and gets around having to worry about the assignment operator, because it is not an assignment. It is a procedure call. I realize these ideas are a bit "out there", but maybe they will lead to something... **************************************************************** From: Bob Duff Sent: Tuesday, November 3, 2009 3:41 PM ... > Would there be any interest in this capability? I might consider something like that in a from-scratch language design, but I don't think it's appropriate at this point in the life of Ada to be adding such bells and whistles. > As in, > > if 3 21 I don't think that works. It would cause trouble for parsers, since "3 I'll suggest a new > compound delimiter <<>> as a strawman, formed by sticking the existing > left and right label brackets together. > Is there any interest in considering this proposal? If so, I can take > care of drafting the AI. Like Randy, I have mild interest. It seems trivial to implement, and somewhat useful. I think the "right" way to do it is to have a reserved word (perhaps "idem"). But we certainly don't want to tolerate upward compatibilities for this little feature, so I agree with your choice of <<>>. I don't like the += or +:= ideas, because they only work for operators. The problem we're trying to solve is having to repeat the left-hand side of an assignment on the right-hand side, which cause trouble because you have to carefully compare the two, and because you have to worry about side effects. Both of these: Table_Of_Gizmos(Current_Gizmo_Index).Blah_Blah := <<>> + 1; Table_Of_Gizmos(Current_Gizmo_Index).Line := Next_Link (<<>>); seem equally useful. <<>> should not reevaluate -- the side effects of the lhs should happen once. I see Tucker's point that the += syntax is familiar to programmers of the C family of languages. Good point, but I still don't like it. Anyway, for Ada to be readable, you have to learn the language. E.g. select ... or terminate; Sure, "terminate" is a nice English word, but you can't really understand it without learning what it means in Ada. **************************************************************** From: Gary Dismukes Sent: Tuesday, November 3, 2009 3:31 PM Here's a skeleton AI for the assignment shorthand proposal, in case it's possible to add this to the agenda for the upcoming ARG meeting. Since there are two suggested approaches for such a feature, further discussion is needed, so I've mentioned both and not pursued writing up a detailed proposal. [Editor's note: this is version /01 of the AI.] **************************************************************** From: Edmond Schonberg Sent: Tuesday, November 3, 2009 3:42 PM > r using a more general > approach that would work for other forms of expression, by adding a > new form of primary that would stand for the left-hand side. The > latter alternative would permit arbitrary use of the target object's > name on the assignment's right-hand side (e.g., Target_Object := Func > (T_O)). Maybe the digraph <- could be used for this purpose: A.B := F (<-, <-); A (X) := <- + 1; intuitively it hints at its purpose by pointing to the left-hand side in the assignment. **************************************************************** From: Stephen Michell Sent: Tuesday, November 3, 2009 6:23 PM But I would say the same about +=, not worth the change to Ada. **************************************************************** From: Robert Dewar Sent: Tuesday, November 3, 2009 7:34 PM Well I must say that X (A, B, G + 1) := X (A, B, G + 1) + 1; is pretty ugly, and the Ada way of getting around this is awfully heavy (declare block, now if we could just say in functional style something like J := J + 1 where J = X (A, B, G + 1) that would be better (please don't think of this as a language suggestion :-)) So to me X (A, B, G + 1) +:= 1; is worthwhile, and trivial to learn, use and implement. I am dubious about the more general forms with <<>> or whatever ... **************************************************************** From: Bob Duff Sent: Tuesday, November 3, 2009 7:48 PM I'm primarily concerned with implementation difficulty at this point. Implementers are having trouble keeping up. Up to Ada 2005, even, and now we're talking about Ada 2012 or 2015 or whatever it's called. The "+=" thing is trivial to implement, as is the <<>> thing, whereas "if Grocery_List Contains Radishes" is probably not. But having said that, I could easily be convinced that none of this is worth the trouble! **************************************************************** From: Bob Duff Sent: Tuesday, November 3, 2009 7:54 PM > Maybe the digraph <- could be used for this purpose: I like it! In a from-scratch language design, I'd prefer a keyword. How about the pronoun "it", as in "X[f(i)].Y := it + 1;"? But as I said, I'm opposed to new reserved words for this purpose. I can tolerate new reserved words, but only for something important. **************************************************************** From: Robert Dewar Sent: Tuesday, November 3, 2009 8:06 PM I still find this klunky compared to X[f(i)].Y +:= 1; To me this notation takes care of the most common cases. Note by the way that the example BLABLA := Next (BLABLA); is more easily handled (as in the GNAT sources), by just introducing an abstraction: Next (BLABLA); which reads just fine, and indeed reads better than BLABLA := Next (<-); or BLABLA := Next (it); Whereas in the +:= case we are comparing A +:= N; with Increment (A, N); (if we use procedural abstraction) or A := <- + N; (if we introduce a general A := it + N; language gizmo) and the +:= notation is better After all the whole business of infix operators is redundant, we can write: "+" (1, 2); but we know that we want the +, because in this particular case, the functional notation is klunky. Much the same considerations apply to +:= and that's why it is reasonable to have a special case for infix operators in this situation. You don't want to generalize if the generalization has a negative effect on the 99% common use case, and helps only the remaining 1%. **************************************************************** From: Randy Brukardt Sent: Tuesday, November 3, 2009 8:32 PM But that argues for *only* supporting +:= and forgetting the rest of the operators. None of the other cases are at all likely. And in any case, we aren't going to support all of the operators in this form: **:= is ugly but the operators that are reserved words don't work at all. I surely hope we aren't going to allow stuff like: mod:= and:= and so on. Those aren't possible to lex in any reasonable way, and parsing doesn't have enough information (it doesn't see whitespace) to check the difference between "and:=" and "and :=". So, no matter what we do, we're going to have a very warty design if you just try to support this in assignment. I'm sympathetic to the concern about usability, but I really don't want to see an amazingly inconsistent design in Ada. **************************************************************** From: Edmond Schonberg Sent: Tuesday, November 3, 2009 8:33 PM I was thinking about it, (I mean "it") but like you I don't think this small convenience deserves a new keyword. Maybe we should limit ourselves to op:= syntax for the predefined binary operators, and not try to generalize this to the power of lambda expressions! **************************************************************** From: Tucker Taft Sent: Tuesday, November 3, 2009 8:54 PM It would be simplest to parse ":=" as two separate tokens, and allow white space between the operator and the ":=" if that is what the user chooses to write. It doesn't seem so bad to write: A(I) mod := 7; to mean A(I) := A(I) mod 7; In some ways, it almost seems more elegant to write: B(Z) + := 3; than to jam the two symbols together into "+:=". ****************************************************************