February 22, 2013
On Friday, 22 February 2013 at 17:25:58 UTC, kenji hara wrote:
> 2013/2/23 deadalnix <deadalnix@gmail.com>
>
>> On Friday, 22 February 2013 at 15:32:42 UTC, kenji hara wrote:
>>
>>> Yes, then the B's definition should raise "mutable A.foo() is not
>>> overridden but hidden in B" (but doesn't because of bug 8366).
>>>
>>>
>> I don't really understand why adding a special case for something that has
>> no real use case.
>>
>
> In old age, it had thrown HiddenFuncError in runtime, and some years ago,
> it had been changed to compile-time error.
> It is one of design in D to avoid unintended method hiding issue.
>

This whole overload on const (note overload, not override) has been introduced in the first place to solve problem that inout now solve in a superior way.
February 22, 2013
2013/2/23 deadalnix <deadalnix@gmail.com>

> On Friday, 22 February 2013 at 17:25:58 UTC, kenji hara wrote:
>
>> 2013/2/23 deadalnix <deadalnix@gmail.com>
>>
>>  On Friday, 22 February 2013 at 15:32:42 UTC, kenji hara wrote:
>>>
>>>  Yes, then the B's definition should raise "mutable A.foo() is not
>>>> overridden but hidden in B" (but doesn't because of bug 8366).
>>>>
>>>>
>>>>  I don't really understand why adding a special case for something that
>>> has
>>> no real use case.
>>>
>>>
>> In old age, it had thrown HiddenFuncError in runtime, and some years ago,
>> it had been changed to compile-time error.
>> It is one of design in D to avoid unintended method hiding issue.
>>
>>
> This whole overload on const (note overload, not override) has been introduced in the first place to solve problem that inout now solve in a superior way.
>

No, const/inout overload does not intend to solve 'method hiding' problem.

To clarify the situation, I try to explain.

class A {
  void foo() {}
  void foo() const {}
}
class B : A {
  override void foo() const {} // or inout
}

In above, B.foo does override _only_one_ vtbl entry, that is for A.foo()
const.
Then in B's vtbl, another entry for mutable A.foo() is *never* filled. We
call the state "B.foo() const hides mutable A.foo()". (If you really
inherit mutable A.foo() in B, you should use alias declaration, "alias
super.foo foo;")

Here you should be aware that, the B.foo() const fills just only one vtbl
entry.
Even if B.foo() const has covariant signature with both A.foo() and A.foo()
const, it never fill two vtbl entries for them.
It's not allowed.

Kenji Hara


February 22, 2013
On Fri, 22 Feb 2013 13:18:34 -0500, deadalnix <deadalnix@gmail.com> wrote:

> On Friday, 22 February 2013 at 17:25:58 UTC, kenji hara wrote:
>> 2013/2/23 deadalnix <deadalnix@gmail.com>
>>
>>> On Friday, 22 February 2013 at 15:32:42 UTC, kenji hara wrote:
>>>
>>>> Yes, then the B's definition should raise "mutable A.foo() is not
>>>> overridden but hidden in B" (but doesn't because of bug 8366).
>>>>
>>>>
>>> I don't really understand why adding a special case for something that has
>>> no real use case.
>>>
>>
>> In old age, it had thrown HiddenFuncError in runtime, and some years ago,
>> it had been changed to compile-time error.
>> It is one of design in D to avoid unintended method hiding issue.
>>
>
> This whole overload on const (note overload, not override) has been introduced in the first place to solve problem that inout now solve in a superior way.

inout does not solve the problem.  A non-const function is allowed to modify the state of the object, a const or inout version is not.

If inout is used on a parameter (including this) but not on the return value, it is equivalent to const.  The problem it solves requires return values (notably missing from all the examples in this discussion), and it requires that they be the same type.

It is probably rare to have both a const and non-const overload, that is true, but it is not up to D to decide what design is best.  We should take the most flexible approach, and allow designers to come up with whatever ideas they like.  I don't think there is any significant extra work required to support const method overloads in the compiler, in fact it would be a more significant change to make that an exception.

-Steve
February 22, 2013
On Friday, February 22, 2013 14:31:55 Steven Schveighoffer wrote:
> It is probably rare to have both a const and non-const overload, that is true, but it is not up to D to decide what design is best. We should take the most flexible approach, and allow designers to come up with whatever ideas they like. I don't think there is any significant extra work required to support const method overloads in the compiler, in fact it would be a more significant change to make that an exception.

A prime example of where overloading on const can be useful is caching. You can write a function which caches its result for efficiency purposes, but the const version can't cache, whereas the non-const one can. So, you can do something like

auto calculate()
{
 if(_dirty)
 _cache = _doCalculation();
 return _cache;
}

auto calculate() const
{
 if(_dirty)
 return _doCalculation();
 return _cache;
}

If you couldn't overload on const, then that wouldn't be possible. You'd be forced either to forgoe const and make it cache or to make it const and forgoe the caching.

- Jonathan M Davis
February 23, 2013
On Friday, 22 February 2013 at 18:55:58 UTC, kenji hara wrote:
> No, const/inout overload does not intend to solve 'method hiding' problem.
>
> To clarify the situation, I try to explain.
>
> class A {
>   void foo() {}
>   void foo() const {}
> }
>

You missed the important part. I'm talking about overload, not override. IE, not method hiding.

What you have in class A here is useful for use cases that are now solved by inout (getting ranges/iterator from collection for instance).

February 23, 2013
On Friday, 22 February 2013 at 20:32:59 UTC, Jonathan M Davis wrote:
> On Friday, February 22, 2013 14:31:55 Steven Schveighoffer wrote:
>> It is probably rare to have both a const and non-const overload, that is
>> true, but it is not up to D to decide what design is best. We should take
>> the most flexible approach, and allow designers to come up with whatever
>> ideas they like. I don't think there is any significant extra work
>> required to support const method overloads in the compiler, in fact it
>> would be a more significant change to make that an exception.
>
> A prime example of where overloading on const can be useful is caching. You
> can write a function which caches its result for efficiency purposes, but the
> const version can't cache, whereas the non-const one can. So, you can do
> something like
>
> auto calculate()
> {
>  if(_dirty)
>  _cache = _doCalculation();
>  return _cache;
> }
>
> auto calculate() const
> {
>  if(_dirty)
>  return _doCalculation();
>  return _cache;
> }
>
> If you couldn't overload on const, then that wouldn't be possible. You'd be
> forced either to forgoe const and make it cache or to make it const and forgoe
> the caching.
>

Nothing prevent you from putting the cache outside the object.
February 23, 2013
On Saturday, February 23, 2013 07:07:51 deadalnix wrote:
> On Friday, 22 February 2013 at 20:32:59 UTC, Jonathan M Davis
> 
> wrote:
> > On Friday, February 22, 2013 14:31:55 Steven Schveighoffer
> > 
> > wrote:
> >> It is probably rare to have both a const and non-const
> >> overload, that is
> >> true, but it is not up to D to decide what design is best. We
> >> should take
> >> the most flexible approach, and allow designers to come up
> >> with whatever
> >> ideas they like. I don't think there is any significant extra
> >> work
> >> required to support const method overloads in the compiler, in
> >> fact it
> >> would be a more significant change to make that an exception.
> > 
> > A prime example of where overloading on const can be useful is
> > caching. You
> > can write a function which caches its result for efficiency
> > purposes, but the
> > const version can't cache, whereas the non-const one can. So,
> > you can do
> > something like
> > 
> > auto calculate()
> > {
> > 
> >  if(_dirty)
> >  _cache = _doCalculation();
> >  return _cache;
> > 
> > }
> > 
> > auto calculate() const
> > {
> > 
> >  if(_dirty)
> >  return _doCalculation();
> >  return _cache;
> > 
> > }
> > 
> > If you couldn't overload on const, then that wouldn't be
> > possible. You'd be
> > forced either to forgoe const and make it cache or to make it
> > const and forgoe
> > the caching.
> 
> Nothing prevent you from putting the cache outside the object.

Which then makes it so that the function can't be pure. While overloading on constness may be infrequently needed, we're definitely losing something useful if we can't do it anymore.

- Jonathan M Davis
February 23, 2013
On Saturday, 23 February 2013 at 06:15:38 UTC, Jonathan M Davis wrote:
> Which then makes it so that the function can't be pure. While overloading on
> constness may be infrequently needed, we're definitely losing something useful
> if we can't do it anymore.
>

Note that is const is considered to be mutable or immutable and do not mute immutable, then a mutable and immutable version of the function can be conflated into a const one (and a different entry in mutable/immutable objects).

This isn't much of a problem because mutable and immutable cannot convert to each other anyway.
February 23, 2013
2013/2/23 deadalnix <deadalnix@gmail.com>

> On Friday, 22 February 2013 at 18:55:58 UTC, kenji hara wrote:
>
>> No, const/inout overload does not intend to solve 'method hiding' problem.
>>
>> To clarify the situation, I try to explain.
>>
>> class A {
>>   void foo() {}
>>   void foo() const {}
>> }
>>
>>
> You missed the important part. I'm talking about overload, not override. IE, not method hiding.
>
> What you have in class A here is useful for use cases that are now solved by inout (getting ranges/iterator from collection for instance).
>

What you intend is:

class A {
  void foo() inout { bar() }
  void bar() {}
  void bar() const {}
}
void main() {
  auto ma = new A();
  ma.foo();  // call foo() inout, and bar() is called in it.
  auto ca = new const A();
  ca.foo();  // call foo() inout, and bar() const is called in it.
}

? If so, it is just *impossible*. Inout method does not work as like that. Inside inout function, all inout qualified objects are treated as like const. In there, you never call mutable method from inout object. It is the inout design.

Kenji Hara


February 23, 2013
On Sat, 23 Feb 2013 01:06:43 -0500, deadalnix <deadalnix@gmail.com> wrote:

> On Friday, 22 February 2013 at 18:55:58 UTC, kenji hara wrote:
>> No, const/inout overload does not intend to solve 'method hiding' problem.
>>
>> To clarify the situation, I try to explain.
>>
>> class A {
>>   void foo() {}
>>   void foo() const {}
>> }
>>
>
> You missed the important part. I'm talking about overload, not override. IE, not method hiding.
>
> What you have in class A here is useful for use cases that are now solved by inout (getting ranges/iterator from collection for instance).

This actually is impossible to do with inout, unless your ranges are pointers or arrays (believe me, I tried with dcollections).  But that is not inout's fault, it's because we have no way to specify tail-const arbitrary types.

The above example does not work with inout, inout only makes sense on a method that returns something.  If you aren't returning anything, use const.

Here is something that inout cannot do:

class A {
   void foo() {writeln("mutable instance used!");}
   void foo() const {}
}

Remember, inout is only valid if ALL implementations (const, immutable, mutable) are identical.

And of course, if you want to count ALL overload possibilities, you can easily come up with more mainstream examples:

class A {
   private int _x;
   @property int x() const {return _x;}
   @property void x(int newx) {_x = x;}
}

So your special compiler rule, that makes extra work for the compiler maintainers, has to allow this case.  It's not a simple exception to add, and it adds pretty much no value.

If you don't want to provide overloads based solely on const, then don't.  But it doesn't HURT for it to be allowed to compile.

I can also write this valid function:

void foo() {}

What is the point?  Yes, we can make the compiler refuse to compile this, but it will always inline to a noop, so it doesn't hurt to allow it to comiple.  And there is nothing in the grammar that disallows this.

D should not be dictating design, just syntax.  Design patterns are not something that I think a language should require.  At it's core, a const method is just another function with a const parameter.  To make special rules based on that seems overly invasive.

-Steve