Article View: comp.std.c++
Article #91Re: Alternatives to operator.()
From: Jim Adcock
Date: Mon, 27 Jul 1992 20:48
Date: Mon, 27 Jul 1992 20:48
200 lines
9427 bytes
9427 bytes
In article <BruME9.HGJ@world.std.com> wmm@world.std.com (William M Miller) writes: |I wonder if it ever occurred to you that the explanation for my |continuing to maintain my objections is that we disagree about the |validity of your arguments, rather than that I have forgotten them or |didn't understand them in the first place? I considered such a possibility but I had to reject this hypothesis in the face of your continued misstatements about my proposal. If you understood my proposal, you would not make misstatements about it, but rather would argue against it using true statements. |expr addressing context scope |---- ------------------ ----- |i stack frame of f() f() | |::i program static file | storage | |x.i x class X | |(*xp).i object to which xp class X | points (indirection) | |xp->i object to which xp class X | points (indirection) | |xr.i object to which xr class X | refers (may not be | an indirection, | depending on | implementation) | |In each case, you look up the name "i" in the implied scope, take the |corresponding offset out of the symbol table, and add it to the base |address implied by the addressing context. Your statement is incorrect in both the (*xp) and xp-> cases above, therefore how can it be an argument against operator.() ? I keep making this point, and you keep ignoring it: The language ALREADY permits operators *, &, and -> to be overloaded, yet you keep making arguments pretending that these overloadable operators don't ALREADY exist. You insist that operator.() must be a simple binding. Yet this statement is already false within the language. If your statement were true, then the following two expressions would have to be identical: (*pfoo).doSomething(); pfoo -> doSomething(); yet the language ALREADY permits such a statement NOT to be true. Dot therefore, already DOES NOT represent "just" a simple binding, because overloadable operators &, *, and -> ALREADY "break" this statement. ON THE CONTRARY, then, we need overloadable operator.() to ALLOW such relationships to continue to be made, in the face of ALREADY overloadable operators &, * and -> |Whether you use the |resulting address in an lvalue or rvalue context is immaterial to the |process. The role of "." is simply to indicate that the expression |preceding the "." is to be used to determine the addressing context |and scope for the interpretation of the name following. This is |exactly analogous to what "::" and the absence of qualification do. Again, the fact that -> and * can be overloaded INDEPENDENTLY ALREADY contradicts your statement, since they already allow the historical relationship: (*pfoo). <==> pfoo-> to be violated. On the contrary then, "." must represent the DIFFERENCE in the operation of (*pfoo) and pfoo-> so that the overall relationship can be maintained. | x.i; | |This isn't detailed enough. Using your terminology, it should read, |"reference to the object named 'i' within the object 'x'", which is Wrong. If this were my terminology, then in the following: px -> i; would mean "i within the object referred to by px" which is clearly a false statement given that the language ALREADY allows operator-> to be overloaded. |Just out of curiosity, did you ever program in Bliss? If I recall |correctly, it has this idea that every name is really just a pointer. No, on the contrary, I program in C++, which has this idea that every name is really just a reference. |If the target class has a member operator and you want to use it via |the smart reference, you MUST provide a forwarding function under your |proposal. Neither your operator.() nor the conversion function |alleviates this necessity. I have pointed out that there is a tiny fixed set of unary member operators where ARM requires the LHS to be a member. ARM pages 333-337 lists these as I have previously noted. The pertinent member functions are as follows, as I have previously noted: 1) Assignment: operator=() 2) Function Call: operator()() 3) Substcripting: operator[]() 4) Class Member Access: operator->() That's It. Since there is such a small fixed set of possible functions, this does not represent a "real" argument against operator.(), but rather represents an argument in choice of implementation syntax. This small FIXED set of operators could be implemented using templates, or macros, for example. This is a very DIFFERENT situation from forwarding member functions in general, where the names of the member functions cannot be predicted in advance, and where the set of functions to be forwarded IS NOT tiny. Further, as I have previously noted, these set of four functions are exactly the ones that an implementor of a reference class MIGHT NOT want to have forwarded! Thus, NOT having these things forwarded automatically might argubly be considered a "feature." IF the smart reference class implementor CHOOSES to have one or more of these tiny fixed set of member operators forwarded, that CHOICE is TRIVIAL to implement. BUT, what if the class implementor CHOOSES NOT to forward one of these operators? What if a "smart reference" implementor CHOOSES that operator=() should mean -- BY DEFAULT -- assign one smart reference to another [such as references are implemented in just about all other OOPLS] ref1 = ref2; // assign ref2 to ref1 NOT assign refed-ob2 to refed-ob1 Your position would prohibit such a CHOICE. |If you "CHOOSE" not to provide such |forwarding functions, the desired operations simply won't be available |via the smart reference. I agree that you have reduced the burden of |writing forwarding functions in your proposal, but you have not |eliminated it. Wherever there is a CHOICE, there is a burden. Some committee members would keep *all* such choices from the programmer -- but only for operator.() out of all the operators. Again, if operators *, & and -> were not ALREADY in the language, I could see this. BUT operators *, & and -> ARE ALREADY in the language. These committee members special case arguments against ONLY overloading operator.() out of this set of operators is silly. The argument has already been decided. Overloaded * & -> ARE in the langauge ALREADY, therefor so should overloadable operator.() |No circumlocution is needed in the smart reference's member functions, |agreed, but that was not the context I was describing. If there is a |"metaoperation" to be performed on the smart reference itself, the |circumlocation *is* necessary. Such metaoperations might include |status queries, cache invalidation, network rerouting, etc. Again, this represents an implementor CHOICE. No one forces the programmer to make these choices, and no one forces the programmer to use operator.() CHOICES available to the implementor REMAIN te CHOICE to forward each function independently, doing with each as they choose, inventing some new syntax to represent NOT forwarded, etc: ref.notForwarded(); ref->notForwarded() local(ref).notForwarded(); notForwarded(ref); etc, etc. These all represent implementor CHOICES. If the language is to offer any convenience to the programmer, someone somewhere has to decide that that convenience IS. If that convenience fails to meet the needs of some programmer in some situation, then the programmer needs to be able to sidestep the "convenience." You argue that because a language default doesn't meet the needs of everybody always, we shouldn't offer it to anybody ever. This is a vacuous argument. |I have explored your proposal. The three disadvantages are still |there. Refusing to acknowledge them doesn't make them go away. There |is room for discussion about the degree to which they are significant, |but denial doesn't move that discussion forward very much. I am happy to acknowledge strengths and weaknesses in my proposal. However, I will continue to try to refute erroneous statements that you or any other people make against it. Again, rather then keep making vacuous arguments that "my" proposal is "half-empty" why don't *you* write down *your* counterproposal for how something, anything else would work that is better. Because right now, your counter-proposal is not "half-empty" -- rather it is totally empty, because you have refused to counter-suggest any CONCRETE counterproposal, such that you, I or the other guy can COMPARE two CONCRETE proposals, in order to discover which might be better. Again, put up or shut up. Either come up with something better, or get out of the way. I suggest that if you or some other committee member puts in the work to TRY to come up with a better counterproposal, you will quickly find out that my proposal isn't nearly as bad as you would suggest. But you refuse to address that possibility, by refusing to do any such CONCRETE work.
Technical Details
Message-ID:
<1992Jul27.204820.8400@microsoft.com>Path:
arc1-ca.pugleaf.net!sparky!uunet!microsoft!hexnut!jimadReferences:
<Brqq7D.97w@world.std.com> <1992Jul23.024159.18039@microsoft.com> <BruME9.HGJ@world.std.com>Show Full Headers
Complete Article Headers
Newsgroups: comp.std.c++ Path: arc1-ca.pugleaf.net!sparky!uunet!microsoft!hexnut!jimad From: jimad@microsoft.com (Jim Adcock) Subject: Re: Alternatives to operator.() Message-ID: <1992Jul27.204820.8400@microsoft.com> Date: 27 Jul 92 20:48:20 GMT Organization: Microsoft Corporation References: <Brqq7D.97w@world.std.com> <1992Jul23.024159.18039@microsoft.com> <BruME9.HGJ@world.std.com> Lines: 202