Closed Bug 7646 Opened 26 years ago Closed 20 years ago

XPIDL can't express C++ 'int m() const' const methods

Categories

(Core :: XPCOM, enhancement)

All
Other
enhancement
Not set
normal

Tracking

()

VERIFIED WONTFIX

People

(Reporter: brendan, Assigned: dbradley)

Details

It should, so C++ and similar languages can state this important (but hard to
get right, or retrofit!) fact about certain methods.

Since XPIDL can't put the [const] attribute after a node, the only choices are

[const] nsIFoo findFoo();

and

nsIFoo [const] findFoo();

The former should mean what it would in C++, where most people put the const
before the type to which it applies: you can say 'int const i = 42' if you like
in C++, but IMO that's rarely done; pointers as waldemar point out complicate
things, but XPIDL doesn't have any explicit pointer or similar declarator modes
(ignoring [ref] here).

So let's say the [const] goes immediately before the method name.

/be
1) I don't think that the compiler FE will let you put it immediately before the
method name. I think that it needs to go before the return type like it or not.

2) I *still* think that this is a big mistake. Yes, C++ supports marking methods
const. So what? Pinkerton said it was bullshit, but I think that the claim that
a call a to method will not change the state of the object is a claim about the
implementation of the object, not about the interface. I can have multiple
implementatations of the same interface where some are lazy and others eager.
Some will need to change their state to satsify the method call. So, my
implementation will have to cast away its own const this* to satisfy the C++
compiler and to satisfy a claim that does not belong in the interface
declaration of a cross language standard.

3) Do you intend to store this in the typelib too? Will any mapping make use of
it? Will we get into trouble if mappings *don't* abide by the claim?

4) As warren noted, C++ const members are as often as not a time wasting rathole
of lies. Why let this meme infect the more 'pure' xpcom interface rules if we're
going to busily ignore the claim for many implementors and callers of interfaces
anyway?

5) I don't see this in COM and I don't see it in Corba. Why are we adding it
here?

6) This is not like 'native' where we are allowing for a workaround to support
real code. This is an explicit changing of the rules about xpcom interfaces. It
is not just a question of can we add it to the compiler, but should we change
the xpcom rules to support this.

7) I have seen little reasoned argument for why it should be part of our
interface standard. I've heard complaints from people who've let it sneek into
their interfaces and who don't like the fixes. And I've heard 'sounds like a
good idea to me' arguments. So, are we going to support operator overloading
too?

8) As we go further beyond C++ calling C++ we're going to have to do things like
write proxy stubs that have to lie to the compiler about not changing their
state when in fact that do. Are we 100% certain that this won't get us into
trouble with compilers that make some optimizations based on assumptions that
const methods don't change an object's state?

When it comes down to it I just plain think that this does not belong as part of
the definition of valid xpcom interfaces. If you're going to do it then you're
going to do it.
Adding waldemar, whom I believe to be a disinterested party who knows C++ and
can represent the value of const methods accurately.

1.  You're right and mccabe and I are wrong, I just read parser.y in libIDL
sources and [properties] can't occur between the method type and method name.
To fix this would require extending libIDL, in which case we might as well allow
[const] after the parameter list, to match C++.  I'm cc'ing Andrew T. Veliath.

2.  Just because you and I know of counterexamples does not make const useless,
or even a statement only about implementations.  My understanding of const in
C++ is that it is a statement about interfaces in the sense that optimizers want
to know about it at method call sites, not when generating code for the method.
It's therefore a fact about all implementations that interface users (including
code generators) need to know.

3.  I see no benefit in extending the typelib format to record this fact at this
time.  Loss of optimization is not dangerous.  Extending the typelib format to
record this fact about the method is not hard, on the other hand.

4.  Warren's complaint about const matches alecf's experience casting away
const.  This doesn't convince me that const methods are worthless.  For years I
had the same problem with const parameter types, because of bad legacy code.
Nowadays that problem has faded to very low background noise.  Isn't the problem
with const methods analogous: programmers are riding the same learning curve?

5.  XPCOM is neither COM nor CORBA.  If we add [const] methods to XPCOM, it'll
be for good reasons we hash out in mozilla.xpcom and here.  Are you making an
argument from authority here?

6.  I beg to differ: we are thinking about adding [const] to enable existing
interfaces to be converted by their owners.  We've done worse ([shared]) to
induce owners to convert.  You seem to be making a narrow technical distinction,
whereas I claim we do these things for "social" or "market" reasons: to win
XPIDL customers without whoring it so much that we corrupt and ruin XPIDL.  So
let's stick to arguing about whether [const] methods debase XPIDL, ok?

7.  I'm with you in opposing things like operator overloading (the slippery
slope argument).  The best arguments I've heard for adding const methods to
XPIDL are that C++ bindings benefit in compiled caller-code quality, and that
C++ users benefit from XPIDL-generated interfaces meeting their expectations.
Neither of those is trivial, nor is either earth-shaking.

Given the low cost of implementing XPIDL [const] methods, and the lack of bad
effects foreseen by me (correct me if I'm wrong, everyone), the benefits to C++
generated code, and user wish-fulfillment, seem worth it to me.

8.  It's hard to be 100% certain about anything, including how well XPConnect
will work.  Yet still we strive.  I think you are using an unfair yardstick in
calling for such certainty.

Anyway, in this particular case, I don't see how a proxy could mutate its 'this'
parameter for a const method call in a way that breaks call-site optimizations.
Waldemar?

/be
const in C++ is primarily saying something about the interface, namely that
calling the method does not change the behaviour of the object observable
through the interface.  It is legal in C++ for a const method to change the
internal state of the object.  It is true that const does affect implementation
in that it implies a default assumption that the implementation will not change
the internal state of the object.  However the "mutable" keyword (a relatively
recent feature of C++) exists precisely to allow this assumption to be
overridden.  So for example if you have a method that doesn't change the
observable behaviour of the object, but does change the internal state because
it caches or works lazily, then the method should be declared const and the
cache member should be declared mutable.
Just to prevent people from getting excited about mutable: many [unix] compilers
still don't handle mutable correctly. Please refrain from using it in the
Mozilla codebase for now...(because some OEM will have to do the work to
un-mutable the codebase anyway)
Support for const is essential for playing nice in the C++ world and supporting

widely used C++ design patterns.  The C++ standard libraries and parts of the

language itself (such as those dealing with unnamed temporaries) require the use

of const.  Without it the code gets littered with type casts, which is error-

prone and polarizes the code structure into warring camps.



As stated in the comments above, C++ allows const methods to mutate the state of

the object, with the understanding that these changes are not visible to the

outside.



Regarding point 9 above and Brendan's question about a proxy mutating its 'this'

parameter for a const method call in a way that breaks call-site optimizations:



The legality of this depends on three things:



1.  Is the proxy/method mutating fields that have been declared 'mutable'?  If

so, everything is OK.

2.  Has the 'this' object been created by C++?  If not, then everything is OK.

3.  Has the object been born as 'const'?  If not, then everything is OK.

You run into problems only when you *construct* the object as 'const' in C++

(such as declaring a const global variable) and then try to mutate its (non-

'mutable') fields.  This is understandable, since in this situation the compiler

is allowed to put the object into ROM.  Java doesn't let you mutate 'final'

values either.  If you don't create the object as 'const', then the only way to

get a const pointer to it is by (implicit or explicit) type conversion, and C++

explicitly states that such type conversions are reversible, so you can be 100%

sure that you won't run into problems with compilers doing advanced optimizations

(as long as these compilers conform to the C++ standard).



See page 107 of the C++ standard for further examples of this.



   Waldemar
Status: NEW → ASSIGNED
Changing status to ASSIGNED.
Note that |const| says something about how an object can be accessed from C++:

"Even if I only have |const| access to this object, I may still call _this_

particular method."  Marking a method |const| is a relaxation of restrictions.

It allows some methods to be called in _more_ situations.  In languages that

provide no schemes for having only |const| access to an object, such a relaxation

is neither necessary, nor harmful, nor used.  Even C++ doesn't necessarily

consider an object referred to through some |const| reference or pointer to be an

unchanging object.  C++ only requires that no modifications are made _through_

_that_ reference.



Supporting |const| methods from XPIDL does not make any promises C++ can't keep,

nor any promises that JS (or other clients) can't keep.  It has little or no

impact on any client that is not |const| savy.  It is more than just a nicety for

C++ clients, however.  |const| is an integral part of much of modern C++ idiom.

It would be a shame to disconnect ourselves from the font of current practice

when the cost to avoid that fate is negligable.
Looks like this one hasn't moved in a while; I'm gonna poke it with a stick.

I thought I remembered hearing that there was a verdict on this, and that const
support would not be added to XPIDL. I think that is the Right Thing, and I say
that as a big fan of the const idiom in C++. In general, it is not a good idea
to add semantics to XPIDL that do not have semantic equivalents in all the
implementation languages, because then implementations in certain languages
would not be able to support *quite* the same interface.

Plenty of C++ code doesn't operate at XPCOM interface boundaries, and the const
idiom is still quite useful there. But for those interface boundaries, the
playing field should be kept as level as possible between different languages.

I suspect I'm just reiterating points that have already gone into a decision on
this. If that decision has in fact occurred (as I suspect), I suggest this bug
be marked WONTFIX.
Re-reading this bug, I must say that jband made some good points, and I was not 
as sympathetic to them then as I am now.  However, I also see here (and recall 
from the newsgroups and hallways) that most people who cared to comment were in 
favor of adding [const] method support to XPIDL (if not to typelibs -- people 
were not careful to distinguish that support from just the .idl=>.h support that 
would result in C++ const method declarations).

To really poke this with a stick, I suppose we should air it in the newsgroups 
once again, but you could argue that anyone who cared enough should have already 
found this bug and commented in it.

/be
You know, I see no reason why xpidl couldn't add const on the Get* methods it
generates for attribute definitions. But that issue probably belongs in a
separate bug report (if it isn't already).

In response to the primary concern Waldemar voiced: there are a number of common
C++ patterns that do not translate to a component architecture, the most obvious
being "construction is resource allocation, destruction is resource cleanup."
CORBA and COM programming and design in C++ *isn't like* "normal" C++
programming. Don't expect XPCOM programming to be particularly different from
other component architectures in this regard.

As far as the "XPCOM is not COM or CORBA" truism goes, keep in mind that *both*
those Other component architectures have primarily targetted C++ as the
implementation language of choice. It should Tell Us Something that they don't
have const either.
[SPAM] Marking milestone 'future' as part of nsbeta3 triage.
Target Milestone: --- → Future
poke.  is anyone thinking about this, still, etc?  I would like to see const
methods supported by xpidl.
Don't hold your breath waiting for *me* to hack it. I still don't think const 
methods are appropriate in xpcom interfaces. 
Pavlov: I'm with John on this, but you might want to try rekindling this on the
newsgroups. It would be nice if either some plan of attack could be formulated,
or the bug closed as WONTFIX.

BTW, I've just filed bug 52406, which tracks making getters (generated from
attribute declarations) const.
Mass-reassigning mccabe's non-JS, non-Rhino bugs to jband (34 total). 

Would like to cc mccabe; but the mass-reassign page does not allow this. 
I'll leave it up to mccabe to decide if he wants to be cc'ed on these - 
Assignee: mike+mozilla → jband
Status: ASSIGNED → NEW
mass reassign of xpidl bugs to dbradley@netscape.com
Assignee: jband → dbradley
Severity: major → enhancement
Status: NEW → ASSIGNED
Priority: P3 → P5
Can we WONTFIX this yet?
The social/market value that const may have had 5 years ago has depreciated
considerably. WONTFIX ;)
Status: ASSIGNED → RESOLVED
Closed: 20 years ago
Resolution: --- → WONTFIX
aww, why? I don't really see good reasons here for that decision.
biesi: then you reopen, self-assign, and fix!  I'll review.

/be
ok.
Status: RESOLVED → REOPENED
Resolution: WONTFIX → ---
Assignee: BradleyJunk → cbiesinger
Status: REOPENED → NEW
Priority: P5 → --
Target Milestone: Future → mozilla1.8beta
biesi: You also need to make a compelling argument why this *should* be fixed.
The question to be answered is this: Why, in an environment where clients may be
using languages that are oblivious to the concept of "const", is the contract
implied by constness ever meaningful?
OK, I don't see me fixing this anytime soon... back to WONTFIX.
Status: NEW → RESOLVED
Closed: 20 years ago20 years ago
Resolution: --- → WONTFIX
Assignee: cbiesinger → dbradley
QA Contact: mike+mozilla → pschwartau
Target Milestone: mozilla1.8beta → ---
Christian, just because you don't have the time to do this doesn't mean it
shouldn't be done. People seem to have accepted the possibility of having
|const| in XPIDL, and others are positively interested in it, so I would say
that it should be marked NEW rathern than WONTFIX. BTW, if it is simple enough
to fix this, I might be tempted to do so. I even have some rudimentary
experience with lex and yacc.
Eyal: You assert that there's support for fixing this, yet the question I posed
in comment #22 hasn't been answered here.
(In reply to comment #24)
I had based my comment on Brenden Eich's comment. As for the question in comment
#22 : C++ is in itself (practically) oblivious to the concept of interfaces, so
I can't see how "languages may not have const" is really that much of an issue:
When such languages are used, it will be the responsibility of the coderto make
sure his/her methods doesn't make observable changes to the object. The 
contract is still meaningful even if you're not enforcing it with a baton... at
least that's my 2 cents on this matter.
> I can't see how "languages may not have const" is really that much of an
> issue: When such languages are used, it will be the responsibility of the
> coderto make sure his/her methods doesn't make observable changes to the
> object.

That is a horrid scenario. There's no way you're going to get const-correctness
right without support from the compiler. Ask anyone who's been using modern C++
for an appreciable time, or anyone who's applied const-correctness to an
existing C++ codebase.

In reality you're going to get a situation where components in languages without
const are totally oblivious to the "const" in the IDL; or worse, their
developers try not to be oblivious, but are sufficiently inconsistent in their
application of the rules that they might as well be.

From the perspective of such developers, "So what? We're not doing anything you
couldn't do in C++ with 'mutable' and 'const_cast'." And if that's a rationale
you're comfortable existing alongside, what are you achieving by adding "const"
to IDL at all? You aren't adding something that's enforcable.

And yet, you assert that the contract is meaningful. So *how* is the contract
meaningful? What does it mean? And most importantly, how can you make use of
what it means?
If you want an unenforced contract why not just suffix the method name with 
const? Then there's no false hopes and you're stating your desire for this the 
method to not modify state.
Braden, I could interpet what you're saying as an argument why other languages
should also have const methods... 

But humor aside, lack of const enforcements is not really that much worse than
the impossibility to enforce semantics in general, or from the fact that we can
have a GetNextPrevLineFromeBlockFrame() method (ok, this is actually a protected
C++ method, this doesn't appear in an IDL, but it might as well have), which
does not actually do anything of the numerous possible interperetations of what
it's supposed to do.

The fact is that _at_the_momemnt_ you have situations in the C++ code in which
methods are supposed to be const methods, and are coded to be const methods, but
aren't officially such, since they were declared via XPIDL. So the "horrid
scenario" is a reality right now. The fact that we don't officialy say in the
IDL that these methods are const doesn't make them any less const, and doesn't
the code using these methods conscienciously assume they are not const. By
adding the const keyword this problem will be solved in C++ and partially-solved
(small-part-ially-solved?) in languages without const enforcement.

> But humor aside, lack of const enforcements is not really that much worse than
> the impossibility to enforce semantics in general ....

Yes, it is much worse. Like any *specific* semantic, *consistent* enforcement is
useful. *Inconsistent* enforcement is useless, because a tool doing the spotty
enforcement cannot be trusted.

> The fact is that _at_the_momemnt_ you have situations in the C++ code in which
> methods are supposed to be const methods ....

That is, as far as I know, categorically false--because *pointers/references to
const XPCOM interfaces are not in use*. They're not in use because current XPIDL
has no notion of const. It's a chicken-and-egg problem, of course; but the
upshot is that *you cannot retrofit existing interfaces with const methods
without breaking a lot of code*.

So perhaps you just want to use it with new interfaces. Well, then you introduce
 an inconsistency: Use a const pointer/reference when using these new
interfaces, but you have to use a non-const pointer/reference when using all
these old ones; oh, and by the way, the non-const pointer/reference will work
just fine with the new ones, too.

Yuck.

> The fact that we don't officialy say in the IDL that these methods are const
> doesn't make them any less const ....

Actually, it does. Because the generated C++ doesn't have "const" applied to the
member function, so the function ain't const. You can use your knowledge of its
semantics to impose an idea of constness on it with your imagination, but that
doesn't make it const to the C++ compiler. And that means that the method
*cannot be called on a const object*.
Let me clarify my comment about breaking existing code by retrofitting existing
iterfaces with "const". The code will continue to compile--it just won't be
const-correct.
> Actually, it does. Because the generated C++ doesn't have "const" applied to 
> the member function, so the function ain't const. You can use your knowledge 
> of its semantics to impose an idea of constness on it with your imagination, 
> but that doesn't make it const to the C++ compiler. And that means that the 
> method *cannot be called on a const object*.

Is

unsigned long indexOf(in unsigned long startIndex,in nsISupports element)

not assumed by practically every bit of code which uses it to be a const method?
Can it not be called on a const (and I don't mean compiler-awareness-const) object?
If you don't mean to talk about the "const" that the compiler knows about, what
are you talking about?

Supposing your "indexOf" is a member function of IFoo, then:

  const IFoo * foo;
  obj->QueryInterface(iid, &foo);
  foo->indexOf(0, element);

... would not compile. indexOf is non-const, so it can't be called on a const
IFoo. So *no* bit of code currently assumes indexOf is a const member function,
or it wouldn't compile.
i confess i have not read all of the comments in this bug, but...

C++'s notion of a const method simply doesn't mix with COM.  one is forced to
provide separate interfaces for the mutatable and immutable methods (see for
example nsIArray and nsIMutableArray).  while this is not great, it is the
reality of COM.  i don't see the point of trying to change that.

afterall, how do you release a const interface pointer if the Release method is
non-const?  or do you assume that the non-const interface pointer does not have
to be released?  that wouldn't work either given that you got the non-const
interface pointer from QueryInterface ;-)
(In reply to comment #34)

Ok, Darin is making a good point. But it doesn't render the const methods
useless. The simplest solution could be that C++ code which takes a |const
nsIFoo *| will not be able to QI it and then release the reference, but rather
only use the given interfaces' known methods. Another option may be to have a
const QI and a non-const QI which return const and non-const pointers; with the
const pointer one would only be able to use const methods, and only Release()ing
it would have to 'cheat' and const-cast. But I am not an expert on COM so I'm
not sure whether that's feasible or whether that's wise.

Well, it seems the motivation for const methods is a bit undermined by this
issue... I still think they are useful - despite the 'shortcomings' of the
implementation languages.
What is the consensus here?  Do people want const methods in XPIDL?  This debate
has been ongoing for some time now.  Perhaps support should simply be added and
we should go from there?
This bug is WONTFIX for a good reason IMO.  Let it rest in peace ;-)

v. wontfix
Status: RESOLVED → VERIFIED
Component: xpidl → XPCOM
QA Contact: pschwartau → xpcom
You need to log in before you can comment on or make changes to this bug.