From: Joshua Maurice on
On May 15, 1:32 pm, "Alf P. Steinbach" <al...(a)start.no> wrote:
> On 15.05.2010 00:22, * Joshua Maurice:
> > A::foo could just
> > as easily have the return type "int" or "std::string", and the
> > analysis would come out the same.
>
> No, in that case none of the example expressions would compile.
>
> The first example expression works because foo has a result type that is covariant with respect to each foo declaration's containing class.

Ok. Let's do this then. I first fixed up your example so it would
actually compile. Here it is:
struct A
{
A& a() { return *this; }
A& foo() { return *this; }
};
struct B : A
{
B& b() { return *this; }
B& foo() { return *this; }
};
void foo()
{
B().foo().b().a(); //compiles fine
B().a().foo().b(); //compile error
}
"ComeauTest.c", line 14: error: class "A" has no member "b"
B().a().foo().b();

Now, here's the same code with my suggested modification:
struct A
{
A& a() { return *this; }
int foo() { return 1; }
};
struct B : A
{
B& b() { return *this; }
B& foo() { return *this; }
};
void foo()
{
B().foo().b().a(); //compiles fine
B().a().foo().b(); //compile error
}
"ComeauTest.c", line 14: error: expression must have class type
B().a().foo().b();

So, I ask again: how does "covariant" come into this analysis at all?
See my earlier post in this thread where I clearly lay out how the
compiler deduces the (static) type of each expression, then deduces
the function to call by looking up the name as a member of that
(static) type, repeated several times. I believe it to be correct, and
the steps the compiler takes in no way involves any sort of
"covariant" analysis as I understand the term.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on
"Alf P. Steinbach" <alfps(a)start.no> writes:
> On 15.05.2010 00:22, * Joshua Maurice:
>> On May 14, 8:49 am, "Alf P. Steinbach"<al...(a)start.no> wrote:
>>> * Joshua Maurice:
>>>> Without virtual, there is no overriding, only
>>>> overloading, and thus talking about covariant return types does not
>>>> make sense.
>>>
>>> There is overriding, overloading and hiding, although one may use
>>> the word "overloading" to include the latter, and I suspect the
>>> standard does.
>>>
>>> But anyway, with hiding in the picture it does make sense to talk
>>> about covariant result types for non-virtuals.
>>>
>>> E.g.,
>>>
>>> struct A
>>> {
>>> A& a() { return *this; }
>>> A& foo() const { return *this; }
>>> };
>>>
>>> struct B: A
>>> {
>>> B& b() { return *this; }
>>> B& foo() const { return *this; } // Covariant result type
>>> }
>>>
>>> Now writing B().foo().b().a() should work nicely, but writing
>>> B().a().foo().b() should not compile.

Note: I shall be using this below, `corrected' according to Alf's saying
that the `const's here are spurious.

<snip />

> On 15.05.2010 00:22, * Joshua Maurice:
>> What exactly are you trying to get at? This is
>> how I understand it:
>>
>> First example:
>> 1) The (static) type of the expression "B()" is "B".
>> 2) Compile-time lookup of the name "foo" as a member of B finds
>> B::foo.
>> 3) The (static) type of the expression "B().foo()" thus has the type
>> of the return type of B::foo, aka "B&".
>> 4) Compile-time lookup of the name "b" as a member of B finds B::b.
>> 5) The (static) type of the expression "B().foo().b()" thus has the
>> type of the return type of B::b, aka "B&".
>> 6) Compile-time lookup of the name "a" as a member of B finds A::a.
>> Thus it is well formed.
>>
>> Second example:
>> 1) The (static) type of the expression "B()" is "B".
>> 2) Compile-time lookup of the name "a" as a member of B finds A::a.
>> 3) The (static) type of the expression "B().a()" thus has the type of
>> the return type of A::a, aka "A&".
>> 4) Compile-time lookup of the name "foo" as a member of A finds
>> A::foo.
>> 5) The (static) type of the expression "B().a().foo()" thus has the
>> type of the return type of A::foo, aka "A&".
>> 6) Compile-time lookup of the name "b" as a member of A fails. The
>> compiler finds that A has no such member.
>> Thus it requires a diagnostic.
>
> Ignoring my "const" typo, this is a correct analysis, yes.
>
>
>> How does "covariant" come into this analysis at all?
>
> Which you then answer, by way of a false assertion :-), in your next
> question, same paragraph:
>
>
>> A::foo could just
>> as easily have the return type "int" or "std::string", and the
>> analysis would come out the same.
>
> No, in that case none of the example expressions would compile.

Assuming that a complete (and corrected, for stray const) example of the
code we are talking about is:

struct A
{
A& a() { return *this; }
A& foo() { return *this; } // #1
};

struct B: A
{
B& b() { return *this; }
B& foo() { return *this; }
};

int main()
{
B().foo().b().a(); // succeeds // #2
B().a().foo().b(); // fails
}

my analysis is that, if we take Joshua's idea and replace line // #1
with:
int foo() { return 1; }

as suggested, then the use in #2 (unchanged) would indeed compile, just
as for the original form above.

13:29:24 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $cat covariance2.cpp
struct A
{
A& a() { return *this; }
int foo() { return 1; }
};

struct B: A
{
B& b() { return *this; }
B& foo() { return *this; }
};

int main()
{
B().foo().b().a();
}

13:29:30 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $gcc -c covariance2.cpp

13:29:38 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $

Furthermore, James' analysis in "First example:", above, remains valid
also.
Regards

Paul Bibbings

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alf P. Steinbach on
On 17.05.2010 01:48, * Paul Bibbings:
>
> Whatever `covariant' means "in general" is irrelevant [to using this term
> in general] owing to the fact that the ISO defines the term specifically
> according to what it requires for its purposes.

Of course the general meaning is not irrelevant.

You may consider that early C++ compilers generally didn't support covariant
reseult types, that one current compiler (MSVC) has trouble with them in
connection with virtual inheritance, and that C++ as a language doesn't support
covariant smart pointers as result type, and that for all three cases the
practical answer is to implement the covariance yourself.

Implementing the covariance (correctly) in such cases is based on covariant
result types of a non-virtual function; the external interface remains the same
as if the compiler and/or language had supported this.

But with your and Joshua's terminology you can't even talk about that.

Is that practical, do you think?

From my point of view it's like an adult maintaining that "gravity" is Earth's
attraction and that only, apparently because that's all the person is familiar
with, and dismissing the gravity of neutron stars since they're far out of
Earth's reach: "that's not gravity".

I do not assume that an adult taking such a view actually believes it himself or
herself.


Cheers,

- Alf

--
blog at <url: http://alfps.wordpress.com>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alf P. Steinbach on
On 17.05.2010 01:42, * Joshua Maurice:
> On May 15, 1:32 pm, "Alf P. Steinbach"<al...(a)start.no> wrote:
>> On 15.05.2010 00:22, * Joshua Maurice:
>>> A::foo could just
>>> as easily have the return type "int" or "std::string", and the
>>> analysis would come out the same.
>>
>> No, in that case none of the example expressions would compile.
>>
>> The first example expression works because foo has a result type that is covariant with respect to each foo declaration's
containing class.
>
> Ok. Let's do this then. I first fixed up your example so it would
> actually compile. Here it is:
> struct A
> {
> A& a() { return *this; }
> A& foo() { return *this; }
> };
> struct B : A
> {
> B& b() { return *this; }
> B& foo() { return *this; }
> };
> void foo()
> {
> B().foo().b().a(); //compiles fine
> B().a().foo().b(); //compile error
> }
> "ComeauTest.c", line 14: error: class "A" has no member "b"
> B().a().foo().b();
>
> Now, here's the same code with my suggested modification:
> struct A
> {
> A& a() { return *this; }
> int foo() { return 1; }
> };
> struct B : A
> {
> B& b() { return *this; }
> B& foo() { return *this; }
> };
> void foo()
> {
> B().foo().b().a(); //compiles fine
> B().a().foo().b(); //compile error
> }
> "ComeauTest.c", line 14: error: expression must have class type
> B().a().foo().b();
>
> So, I ask again: how does "covariant" come into this analysis at all?

Add a test case like

B().a().foo().a()

and you'll see some difference between A::foo() having 'int' and 'A&' result type.

Sorry for not providing a clarifying enough example.

More generally, covariant result types of non-virtual methods is the common
solution to implementing that covariance where the compiler and/or language
doesn't support it. See my reply else-thread to Paul Bibbings. In short, I don't
believe that you're serious.


Cheers & hth.,

- Alf

--
blog at <url: http://alfps.wordpress.com>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on
"Alf P. Steinbach" <alfps(a)start.no> writes:
> On 17.05.2010 01:48, * Paul Bibbings:
>>
>> Whatever `covariant' means "in general" is irrelevant [to using this term
>> in general] owing to the fact that the ISO defines the term specifically
>> according to what it requires for its purposes.

May I politely suggest that the above style of quoting, in which words
have been added by yourself which may not be immediately obvious as
such, is unhelpful, particularly where that addition completely
changes the meaning of those words.

Rather, it is my assertion that "Whatever `covariant' means 'in general'"
is irrelevant /in the context of the OP's original question/ which, as the
Subject line shows, was "Does covariant return types hold for
non-virtual?"

In the text from my previous post, which occurred prior to the above
(snipped), I presented `covariant' as being a defined term in ISO/IEC
14882:2003, [class.virtual]/5 and gave that definition. As a *defined*
term it's definition, as given there, provides the sole context in which
the meaning of the term must be understood in answering the OP's
question.
According to the definition given, and in the context of the meaning
there given and of the OP's actual question, the answer is "No," by
definition.
> Of course the general meaning is not irrelevant.
>
> You may consider that early C++ compilers generally didn't support
> covariant reseult types, that one current compiler (MSVC) has trouble
> with them in connection with virtual inheritance, and that C++ as a
> language doesn't support covariant smart pointers as result type, and
> that for all three cases the practical answer is to implement the
> covariance yourself.
>
> Implementing the covariance (correctly) in such cases is based on
> covariant result types of a non-virtual function; the external
> interface remains the same as if the compiler and/or language had
> supported this.
>
> But with your and Joshua's terminology you can't even talk about that.

Can I again set some distance from any sense of the terminology being
`mine'.
> Is that practical, do you think?
>
> From my point of view it's like an adult maintaining that "gravity" is
> Earth's attraction and that only, apparently because that's all the
> person is familiar with, and dismissing the gravity of neutron stars
> since they're far out of Earth's reach: "that's not gravity".
>
> I do not assume that an adult taking such a view actually believes it
> himself or herself.

As the term is /defined/, I would suggest that `belief' does not come
into the question. Rather, it is merely of a case of promoting a
commonality of understanding by agreeing to accept defined terms where
such are given, in context. Otherwise we risk opening the door to such
confusions as might arise were I, as an Englishman, to ask for `jelly'
with my ice-cream in a diner in the United States.
Regards

Pau
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]