www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - const and non-const member function

reply Frank Fischer <frank.fischer s2001.tu-chemnitz.de> writes:
Hi,

I'm just playing around with const in DMD 2.003 and I have a question.
In C++ it is possible to have a const and a non-const member function with
the same name and parameter types. It depends on the type of the reference
to the object which function is called:

class A {
public:
  int myfunc() { return 0; }
  int myfunc() const { return 1; }
};

A a;
a.myfunc(); // returns 0
const A& b = a;
b.myfunc(); // returns 1

Is something like this possible in D? 

Another example would be with different return-types:
class B {
  A a;
public:

  A& myfunc() { return a; }
  const A& myfunc() { return a; }
};

(of course, in D you don't need explicit references but the idea is the
same).

Furthermore, is it possible to overload opApply(...) so it can be called on
non-const objects and const objects, and the non-const variant has
read-write access:

foreach(ref x; obj) x = 1; // possible for non-const 'obj'
foreach(ref x; cast(const(Obj))obj) x = 1; // ERROR for const 'obj'
foreach(x; obj) writefln("%d", x); // Ok for both, const and non-const 'obj'

What would be the D-way of doing this? I need this access to provide the
correct member functions in some of my D-libraries I write, since I want to
have const-versions of my objects.

Thanks,
Frank
Jul 25 2007
parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 In C++ it is possible to have a const and a non-const member function with
 the same name and parameter types. 
 ...
 Is something like this possible in D?

I don't think it's possible (yet). Trying class Foo { void bar() {} const void bar() {} } gives me an error. I'm not sure if it is by design or just not working yet.
 Furthermore, is it possible to overload opApply(...) so it can be called
 on non-const objects and const objects, and the non-const variant has
 read-write access:

Having that would pretty much depend on being able to have a opApply and a const opApply. I tried by using two functions with different names, but the compiler segfaulted on a ref const(Struct*). Cheers, Christian
Jul 25 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Christian Kamm wrote:
 In C++ it is possible to have a const and a non-const member function with
 the same name and parameter types. 
 ...
 Is something like this possible in D?

I don't think it's possible (yet). Trying class Foo { void bar() {} const void bar() {} } gives me an error. I'm not sure if it is by design or just not working yet.
 Furthermore, is it possible to overload opApply(...) so it can be called
 on non-const objects and const objects, and the non-const variant has
 read-write access:

Having that would pretty much depend on being able to have a opApply and a const opApply. I tried by using two functions with different names, but the compiler segfaulted on a ref const(Struct*). Cheers, Christian

I may be wrong, but I think the idea is that a method either is or isn't const-safe, and the difference between const and mutable references to the object is supposed to be in the availability of methods, not in their behavior. While I'm sure there's some percentage of the time subtle behavioral changes could be desirable, I don't believe const-method overloading is meant to happen. That said, a few demonstrative cases sometimes do wonders. :) (I'm also not 100% pleased with the 'const R M(){}' syntax for declaring const methods... To me it reads as a function M() returning 'const R'. Yes I know the syntax for that is 'const(R) M(){}' and no I don't have a better idea right off hand. I don't care for the C++ 'R M() const {}' either. Wasn't there something like 'R M:const(){}' volleyed back when the const discussions first happened?) -- Chris Nicholson-Sauls
Jul 25 2007
next sibling parent James Dennett <jdennett acm.org> writes:
Chris Nicholson-Sauls wrote:
 Christian Kamm wrote:
 In C++ it is possible to have a const and a non-const member function
 with
 the same name and parameter types. ...
 Is something like this possible in D?

I don't think it's possible (yet). Trying class Foo { void bar() {} const void bar() {} } gives me an error. I'm not sure if it is by design or just not working yet.
 Furthermore, is it possible to overload opApply(...) so it can be called
 on non-const objects and const objects, and the non-const variant has
 read-write access:

Having that would pretty much depend on being able to have a opApply and a const opApply. I tried by using two functions with different names, but the compiler segfaulted on a ref const(Struct*). Cheers, Christian

I may be wrong, but I think the idea is that a method either is or isn't const-safe, and the difference between const and mutable references to the object is supposed to be in the availability of methods, not in their behavior. While I'm sure there's some percentage of the time subtle behavioral changes could be desirable, I don't believe const-method overloading is meant to happen. That said, a few demonstrative cases sometimes do wonders. :)

The normal reason (coming from C++) for having overloads by constness is when the return value should differ in constness. The C++ community would frown on code with differences between const and non-const member functions other than those that directly relate to constness. A trivial almost example is any object returning a reference to a component of itself; if the object is const, then the reference to its component should not allow modification, but if the object is non-const, then modification of its component may well be reasonable. (There's a separate debate that I don't want to get into about whether it's poor design to expose references to components. If that's a sticking point to you, imagine that the relationship is "uses" rather than "is composed of".) -- James
Jul 25 2007
prev sibling parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 I may be wrong, but I think the idea is that a method either is or isn't
 const-safe, and the difference between const and mutable references to
 the object is supposed to be in the availability of methods, not in
 their behavior.  While I'm sure there's some percentage of the time
 subtle behavioral changes could be desirable, I don't believe
 const-method overloading is meant to happen.
 
 That said, a few demonstrative cases sometimes do wonders.  :)

Well, the original poster basically wanted it to be possible to have class Container(T) { int opApply(int delegate(ref T) dg); const int opApply(int delegate(ref const(T)) dg); } such that foreach would work on const(Container!(T)) and Container!(T) alike, using the correct types. To me, that seems pretty reasonable. James Dennett pointed out another, simpler example Foo getThis() { return this; } const const(Foo) getThis() { return this; } invariant invariant(Foo) getThis() { return this; } Personally, I'd like to see the 'templating on const' solution that was thrown around during one of the const debates C C(Foo) getThis(constness C)() { return this; } and C int opApply(constness C)(int delegate(ref C(T)) dg) as the different versions are usually quite similar, except for slightly different types.
 (I'm also not 100% pleased with the 'const R M(){}' syntax for declaring
 const methods...  

Yes, it's quite bad: const Foo func(const Foo) { const Foo = ...; } All consts look the same, but the first means the method, the second is an alternative for const(Foo) and the third is the compile-time const storage class. I'd probably disallow const Foo in parameter declarations, yet don't know how to do make the method-const look different. Cheers, Christian
Jul 26 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Christian Kamm wrote:
 (I'm also not 100% pleased with the 'const R M(){}' syntax for declaring
 const methods...  

Yes, it's quite bad: const Foo func(const Foo) { const Foo = ...; } All consts look the same, but the first means the method, the second is an alternative for const(Foo) and the third is the compile-time const storage class. I'd probably disallow const Foo in parameter declarations, yet don't know how to do make the method-const look different.

How about this for method-const: --- Foo const(func)(const Foo) { // ... } --- Though I guess that may look too much like the const(Type) notation...
Jul 26 2007
next sibling parent Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 I'd probably disallow const Foo in parameter declarations, yet don't know
 how to do make the method-const look different.

How about this for method-const: --- Foo const(func)(const Foo) { // ... } --- Though I guess that may look too much like the const(Type) notation...

I thought the same thing: putting the const/invariant after the return type might be okay --- Foo const func(const(Foo)) --- but the current way of doing it has the merit of allowing --- const { void func1(); void func2(); } --- which'd be odd to explain with the const being anywhere but in the very front.
Jul 26 2007
prev sibling parent Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Frits van Bommel wrote:
 Christian Kamm wrote:
 (I'm also not 100% pleased with the 'const R M(){}' syntax for declaring
 const methods...  

Yes, it's quite bad: const Foo func(const Foo) { const Foo = ...; } All consts look the same, but the first means the method, the second is an alternative for const(Foo) and the third is the compile-time const storage class. I'd probably disallow const Foo in parameter declarations, yet don't know how to do make the method-const look different.

How about this for method-const: --- Foo const(func)(const Foo) { // ... } --- Though I guess that may look too much like the const(Type) notation...

I have a radical notion. We could place it after the parameter list! Foo func(const Foo) const { // ... } -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Jul 26 2007
prev sibling parent Regan Heath <regan netmail.co.nz> writes:
Christian Kamm wrote:
 Well, the original poster basically wanted it to be possible to have
 
 class Container(T)
 {
   int opApply(int delegate(ref T) dg);
   const int opApply(int delegate(ref const(T)) dg);
 }
 
 such that foreach would work on const(Container!(T)) and Container!(T)
 alike, using the correct types. To me, that seems pretty reasonable.

Initially I thought it would overload on the 'ref' part of the delegate in opApply, eg. class Container { int[] array; //called when 'ref' not used, suitable for 'const' objects int opApply(int delegate(int) dg) { int result = 0; for (int i = 0; i < array.length; i++) { result = dg(array[i]); if (result) break; } return result; } //called when 'ref' used, not suitable for 'const' objects int opApply(int delegate(ref int) dg) { int result = 0; for (int i = 0; i < array.length; i++) { result = dg(array[i]); if (result) break; } return result; } } Current D implementation expects the delegate to have 'ref' in it, anything else is an error and foreach on a const object gives: Error: a.opApply can only be called on a mutable object Instead it could, on a const object look for: int opApply(int delegate(Type) dg) and on non-const: int opApply(int delegate(ref Type) dg) Regan
Jul 26 2007