Hello, I was dealing with delegates when I found that the const correctness of the this pointer was 'lost' when accessing a member function of a class through a temporary delegate.
Here is an example:
class A{
void f () {}
}
const A a = new A;
a.f() //error, this is normal.
auto g = &a.f;
g(); //no error. Is this normal ?
I may be wrong, but it seems to me that as the const property of the this pointer is linked to the instance of the class (here 'a'), the delegate 'g' should contain a const pointer to A (because 'a' is const).
More generally, I seems that there is no management of the const correctness of the frame pointer of a delegate in D2
What about adding the const keyword for delegates, as we do for methods ? The const property of the delegate's frame pointer would be part of its type.
Example:
void f()
{
int x;
void g() const {
x ++; //would produce an error since the type of g is [void delegate() const]
}
}
Any thoughts about this ?

TM Wrote:
> Hello, I was dealing with delegates when I found that the const correctness of the this pointer was 'lost' when accessing a member function of a class through a temporary delegate.
> > Here is an example:
> > class A{
> void f () {}
> }
> > const A a = new A;
> a.f() //error, this is normal.
> auto g = &a.f;
> g(); //no error. Is this normal ?
> > I may be wrong, but it seems to me that as the const property of the this pointer is linked to the instance of the class (here 'a'), the delegate 'g' should contain a const pointer to A (because 'a' is const).
Looks like something that should be entered into bugzilla

On Sun, 27 Dec 2009 19:02:23 -0500, TM <ithink@therefore.iam> wrote:
> Hello,
> I was dealing with delegates when I found that the const correctness of the this pointer was 'lost' when accessing a member function of a class through a temporary delegate.
>> Here is an example:
>> class A{
> void f () {}
> }
>> const A a = new A;
> a.f() //error, this is normal.
> auto g = &a.f;
> g(); //no error. Is this normal ?
>> I may be wrong, but it seems to me that as the const property of the this pointer is linked to the instance of the class (here 'a'), the delegate 'g' should contain a const pointer to A (because 'a' is const).
>> More generally, I seems that there is no management of the const correctness of the frame pointer of a delegate in D2
>> What about adding the const keyword for delegates, as we do for methods ? The const property of the delegate's frame pointer would be part of its type.
>> Example:
>> void f()
> {
> int x;
> void g() const {
> x ++; //would produce an error since the type of g is [void delegate() const]
> }
> }
>> Any thoughts about this ?
This might be a difficult thing to fix, but it definitely *definitely* needs to be fixed. The problem is that a delegate stores a function pointer and a context pointer. However, it does not type the context pointer. For example, if you do this:
import std.stdio;
class A
{
void f() const {}
}
void main()
{
const A a = new A;
a.f();
auto g = &a.f;
writefln("%s", typeof(g).stringof);
}
You will get this:
void delegate()
The this pointer is hidden, and so is it's const decoration. I would expect to see:
void delegate() const
I'll file a bugzilla request for this.
-Steve

Steven Schveighoffer Wrote:
> > This might be a difficult thing to fix, but it definitely *definitely* needs to be fixed. The problem is that a delegate stores a function pointer and a context pointer. However, it does not type the context pointer. For example, if you do this:
> > import std.stdio;
> > class A
> {
> void f() const {}
> }
> > void main()
> {
> const A a = new A;
> a.f();
> auto g = &a.f;
> writefln("%s", typeof(g).stringof);
> }
> > You will get this:
> > void delegate()
> > The this pointer is hidden, and so is it's const decoration. I would expect to see:
> > void delegate() const
> > I'll file a bugzilla request for this.
> > -Steve
I disagree. Once the delegate is passed off to some other region of code, why should that other code care that there's an object that might not get modified from using the delegate? Especially when you consider that which object or stack frame is not tracked by the type system. Pure delegates make sense to me though.

On Mon, 28 Dec 2009 10:50:02 -0500, Jason House <jason.james.house@gmail.com> wrote:
> Steven Schveighoffer Wrote:
>>>>> This might be a difficult thing to fix, but it definitely *definitely*
>> needs to be fixed. The problem is that a delegate stores a function
>> pointer and a context pointer. However, it does not type the context
>> pointer. For example, if you do this:
>>>> import std.stdio;
>>>> class A
>> {
>> void f() const {}
>> }
>>>> void main()
>> {
>> const A a = new A;
>> a.f();
>> auto g = &a.f;
>> writefln("%s", typeof(g).stringof);
>> }
>>>> You will get this:
>>>> void delegate()
>>>> The this pointer is hidden, and so is it's const decoration. I would
>> expect to see:
>>>> void delegate() const
>>>> I'll file a bugzilla request for this.
>>>> -Steve
>>> I disagree. Once the delegate is passed off to some other region of code, why should that other code care that there's an object that might not get modified from using the delegate? Especially when you consider that which object or stack frame is not tracked by the type system. Pure delegates make sense to me though.
It could be part of the interface for a function that takes a delegate (i.e. I require that this delegate does not modify it's 'this' parameter).
But I agree, there could be issues -- if you don't care what the delegate does (const or not), then how do you specify that?
I suppose we need delegate contravariance at that point -- a delegate to a const function should implicitly casts to a delegate of a non-const function. See http://d.puremagic.com/issues/show_bug.cgi?id=3075
This might be a good reason to revive that enhancement.
BTW, you also need to correctly mark shared functions, which *do* matter as far as delegates go, since you need to synchronize access to the 'this' pointer before calling the delegate.
-Steve

Jason House Wrote:
> Steven Schveighoffer Wrote:
> > > > > This might be a difficult thing to fix, but it definitely *definitely* needs to be fixed. The problem is that a delegate stores a function pointer and a context pointer. However, it does not type the context pointer. For example, if you do this:
> > > > import std.stdio;
> > > > class A
> > {
> > void f() const {}
> > }
> > > > void main()
> > {
> > const A a = new A;
> > a.f();
> > auto g = &a.f;
> > writefln("%s", typeof(g).stringof);
> > }
> > > > You will get this:
> > > > void delegate()
> > > > The this pointer is hidden, and so is it's const decoration. I would expect to see:
> > > > void delegate() const
> > > > I'll file a bugzilla request for this.
> > > > -Steve
> > > I disagree. Once the delegate is passed off to some other region of code, why should that other code care that there's an object that might not get modified from using the delegate? Especially when you consider that which object or stack frame is not tracked by the type system. Pure delegates make sense to me though.
I disagree with you. To me, the loss of the frame pointer's const attribute looks like a cast. I do not expect to be allowed to call the above 'a.f' wihout casting a into a const A. And yet it is possible by using a delegate, which I think performs a hidden cast operation.
I think Steven Schveighoffer is right. Moreover the const correctness of the this pointer is well managed as far as objects are concerned, so why not have the same behaviour with delegate ?

On Mon, 28 Dec 2009 03:02:23 +0300, TM <ithink@therefore.iam> wrote:
> Hello,
> I was dealing with delegates when I found that the const correctness of the this pointer was 'lost' when accessing a member function of a class through a temporary delegate.
>> Here is an example:
>> class A{
> void f () {}
> }
>> const A a = new A;
> a.f() //error, this is normal.
> auto g = &a.f;
> g(); //no error. Is this normal ?
>> I may be wrong, but it seems to me that as the const property of the this pointer is linked to the instance of the class (here 'a'), the delegate 'g' should contain a const pointer to A (because 'a' is const).
>> More generally, I seems that there is no management of the const correctness of the frame pointer of a delegate in D2
>> What about adding the const keyword for delegates, as we do for methods ? The const property of the delegate's frame pointer would be part of its type.
>> Example:
>> void f()
> {
> int x;
> void g() const {
> x ++; //would produce an error since the type of g is [void delegate() const]
> }
> }
>> Any thoughts about this ?
It shouldn't compile: it makes no sense to can't non-const method through const reference, and the same applies to shared. OTOH, the following should just work:
class A {
void constMethod() const {}
void sharedMethod() shared {}
}
const A a1 = new A();
void delegate() const dg1 = &a1.constMethod;
shared A a2 = new shared A();
void delegate() shared dg2 = &a2.sharedMethod();
(in examples above, const and shared attributes are applied to both function pointer and frame pointer)
I already wrote about a necessity of introduction of "shared delegates" in a separate thread. Until then, Thread creation is broken in D.

TM Wrote:
> Jason House Wrote:
> > > Steven Schveighoffer Wrote:
> > > > > > > > This might be a difficult thing to fix, but it definitely *definitely* needs to be fixed. The problem is that a delegate stores a function pointer and a context pointer. However, it does not type the context pointer. For example, if you do this:
> > > > > > import std.stdio;
> > > > > > class A
> > > {
> > > void f() const {}
> > > }
> > > > > > void main()
> > > {
> > > const A a = new A;
> > > a.f();
> > > auto g = &a.f;
> > > writefln("%s", typeof(g).stringof);
> > > }
> > > > > > You will get this:
> > > > > > void delegate()
> > > > > > The this pointer is hidden, and so is it's const decoration. I would expect to see:
> > > > > > void delegate() const
> > > > > > I'll file a bugzilla request for this.
> > > > > > -Steve
> > > > > > I disagree. Once the delegate is passed off to some other region of code, why should that other code care that there's an object that might not get modified from using the delegate? Especially when you consider that which object or stack frame is not tracked by the type system. Pure delegates make sense to me though.
> > > I disagree with you. To me, the loss of the frame pointer's const attribute looks like a cast.
The quoted code (by Steve) above is not the same as yours. Both the variable and the called member are const. Invoking the delegate does not violate the const system. I did respond to your original example saying to file a bugzilla entry.
> I do not expect to be allowed to call the above 'a.f' wihout casting a into a const A. And yet it is possible by using a delegate, which I think performs a hidden cast operation.
>
Calling a const member function is allowed without casting from either thread-local mutable data or immutable data. Calling a non-const member function on a const object is what's illegal. That's what your original sample did. Constructing such a delegate (without casts) should be illegal and is a bug in dmd.
Once a const-correct delegate is created, it should be usable like any other delegate.

Am 28.12.2009 18:44, schrieb Denis Koroskin:
> On Mon, 28 Dec 2009 03:02:23 +0300, TM <ithink@therefore.iam> wrote:
>>> Hello,
>> I was dealing with delegates when I found that the const correctness
>> of the this pointer was 'lost' when accessing a member function of a
>> class through a temporary delegate.
>>>> Here is an example:
>>>> class A{
>> void f () {}
>> }
>>>> const A a = new A;
>> a.f() //error, this is normal.
>> auto g = &a.f;
>> g(); //no error. Is this normal ?
>>>> I may be wrong, but it seems to me that as the const property of the
>> this pointer is linked to the instance of the class (here 'a'), the
>> delegate 'g' should contain a const pointer to A (because 'a' is const).
>>>> More generally, I seems that there is no management of the const
>> correctness of the frame pointer of a delegate in D2
>>>> What about adding the const keyword for delegates, as we do for
>> methods ? The const property of the delegate's frame pointer would be
>> part of its type.
>>>> Example:
>>>> void f()
>> {
>> int x;
>> void g() const {
>> x ++; //would produce an error since the type of g is [void delegate()
>> const]
>> }
>> }
>>>> Any thoughts about this ?
>> It shouldn't compile: it makes no sense to can't non-const method
> through const reference, and the same applies to shared. OTOH, the
> following should just work:
>> class A {
> void constMethod() const {}
> void sharedMethod() shared {}
> }
>> const A a1 = new A();
> void delegate() const dg1 = &a1.constMethod;
>> shared A a2 = new shared A();
> void delegate() shared dg2 = &a2.sharedMethod();
>> (in examples above, const and shared attributes are applied to both
> function pointer and frame pointer)
>> I already wrote about a necessity of introduction of "shared delegates"
> in a separate thread. Until then, Thread creation is broken in D.
Actually in both cases the error is not happening when the delegate is called but at the point where the delegate is created. _Creating_ a delegate to a non-const function should simply be impossible when a const object is bound (result in a compile time error). Similarily, for a shared object, the necessary synchronization code should be added to the delegate instead of having the shared attribute attached to the delegate.
Typing the delegate will just create superfluous type combinations and complicate delegate usage - additionally it would be strange in the sense that it makes assumptions about the type of the "context pointer" without knowing what it is (object, stack frame, struct, ...).
Sönke

Jason House Wrote:
> TM Wrote:
> > > Jason House Wrote:
> > > > > Steven Schveighoffer Wrote:
> > > > > > > > > > > This might be a difficult thing to fix, but it definitely *definitely* needs to be fixed. The problem is that a delegate stores a function pointer and a context pointer. However, it does not type the context pointer. For example, if you do this:
> > > > > > > > import std.stdio;
> > > > > > > > class A
> > > > {
> > > > void f() const {}
> > > > }
> > > > > > > > void main()
> > > > {
> > > > const A a = new A;
> > > > a.f();
> > > > auto g = &a.f;
> > > > writefln("%s", typeof(g).stringof);
> > > > }
> > > > > > > > You will get this:
> > > > > > > > void delegate()
> > > > > > > > The this pointer is hidden, and so is it's const decoration. I would expect to see:
> > > > > > > > void delegate() const
> > > > > > > > I'll file a bugzilla request for this.
> > > > > > > > -Steve
> > > > > > > > > I disagree. Once the delegate is passed off to some other region of code, why should that other code care that there's an object that might not get modified from using the delegate? Especially when you consider that which object or stack frame is not tracked by the type system. Pure delegates make sense to me though.
> > > > > > I disagree with you. To me, the loss of the frame pointer's const attribute looks like a cast.
> > The quoted code (by Steve) above is not the same as yours. Both the variable and the called member are const. Invoking the delegate does not violate the const system. I did respond to your original example saying to file a bugzilla entry.
> > > > > I do not expect to be allowed to call the above 'a.f' wihout casting a into a const A. And yet it is possible by using a delegate, which I think performs a hidden cast operation.
> > > > Calling a const member function is allowed without casting from either thread-local mutable data or immutable data. Calling a non-const member function on a const object is what's illegal. That's what your original sample did. Constructing such a delegate (without casts) should be illegal and is a bug in dmd.
> > Once a const-correct delegate is created, it should be usable like any other delegate.
I totally agree that the problem is the conversion of a [ void delegate() const] to a [void delegate()]. I totally agree that we should be allowed to call the const-correct delegate once it has been created.
ie, this should be correct:
void delegate() g = cast ( void delegate() ) (f); //here a cast would be necessary
g(); //This would be OK, of course
Concerning the bugzilla, the problem is that adding the 'const' and 'share' properties of the frame pointer as a part of the delegate's type is more like a new feature than a compiler bug, isn't it ?
On the other hand, it looks like we all agree to say this is a must have feature. Do wee ?