June 18, 2012
Is it just me, or did I subvert the type system here?


import std.stdio;

struct Const
{
	this(void delegate() increment)
	{ this.increment = increment; }
	int a;
	void delegate() increment;
	void oops() const { this.increment(); }
}

void main()
{
	Const c;
	c = Const({ c.a++; });
	writeln(c.a);
	c.oops();
	writeln(c.a);
}
June 18, 2012
On 06/18/2012 07:36 AM, Mehrdad wrote:
> Is it just me, or did I subvert the type system here?
> 
> 
> import std.stdio;
> 
> struct Const
> {
>     this(void delegate() increment)
>     { this.increment = increment; }
>     int a;
>     void delegate() increment;
>     void oops() const { this.increment(); }
> }
> 
> void main()
> {
>     Const c;
>     c = Const({ c.a++; });
>     writeln(c.a);
>     c.oops();
>     writeln(c.a);
> }
> 

I don't think so. When calling oops you have two references to the object c:

- The this-pointer of the object itself which is not allowed to change
the object in the const-call.
- The reference from within main which is allowed to change it and can
be reached via the frame pointer of the delegate.

I see this as perfectly valid code. Of course, opinions may differ here.

Matthias
June 18, 2012
On Monday, June 18, 2012 07:36:26 Mehrdad wrote:
> Is it just me, or did I subvert the type system here?
> 
> 
> import std.stdio;
> 
> struct Const
> {
> 	this(void delegate() increment)
> 	{ this.increment = increment; }
> 	int a;
> 	void delegate() increment;
> 	void oops() const { this.increment(); }
> }
> 
> void main()
> {
> 	Const c;
> 	c = Const({ c.a++; });
> 	writeln(c.a);
> 	c.oops();
> 	writeln(c.a);
> }

No, actually I don't think that you did. The delegate isn't accessing the this pointer - which is where const would kick in. It's accessing c through a non- const reference to the data that was put in its body inside of main.

- Jonathan M Davis
June 18, 2012
On Monday, 18 June 2012 at 06:00:11 UTC, Matthias Walter wrote:
> On 06/18/2012 07:36 AM, Mehrdad wrote:
>> Is it just me, or did I subvert the type system here?
>> 
>> 
>> import std.stdio;
>> 
>> struct Const
>> {
>>     this(void delegate() increment)
>>     { this.increment = increment; }
>>     int a;
>>     void delegate() increment;
>>     void oops() const { this.increment(); }
>> }
>> 
>> void main()
>> {
>>     Const c;
>>     c = Const({ c.a++; });
>>     writeln(c.a);
>>     c.oops();
>>     writeln(c.a);
>> }
>> 
>
> I don't think so. When calling oops you have two references to the object c:
>
> - The this-pointer of the object itself which is not allowed to change
> the object in the const-call.
> - The reference from within main which is allowed to change it and can
> be reached via the frame pointer of the delegate.
>
> I see this as perfectly valid code. Of course, opinions may differ here.
>
> Matthias



My trouble isn't with the delegate, it's with the const method.

It's with the idea that "you can tell something about the code just by looking at it".

The way I understood it, you can assume that a `const` method cannot modify an object, but... that doesn't seem to be the case here.

What am I misunderstanding?
June 18, 2012
On Monday, 18 June 2012 at 06:00:11 UTC, Matthias Walter wrote:
> On 06/18/2012 07:36 AM, Mehrdad wrote:
>> Is it just me, or did I subvert the type system here?
>> 
>> 
>> import std.stdio;
>> 
>> struct Const
>> {
>>     this(void delegate() increment)
>>     { this.increment = increment; }
>>     int a;
>>     void delegate() increment;
>>     void oops() const { this.increment(); }
>> }
>> 
>> void main()
>> {
>>     Const c;
>>     c = Const({ c.a++; });
>>     writeln(c.a);
>>     c.oops();
>>     writeln(c.a);
>> }
>> 
>
> I don't think so. When calling oops you have two references to the object c:
>
> - The this-pointer of the object itself which is not allowed to change
> the object in the const-call.
> - The reference from within main which is allowed to change it and can
> be reached via the frame pointer of the delegate.
>
> I see this as perfectly valid code. Of course, opinions may differ here.
>
> Matthias



My trouble isn't with the delegate, it's with the const method.

It's with the idea that "you can tell something about the code just by looking at it".

The way I understood it, you can assume that a `const` method cannot modify an object, but... that doesn't seem to be the case here.

What am I misunderstanding?
June 18, 2012
On 06/18/2012 08:04 AM, Mehrdad wrote:
> On Monday, 18 June 2012 at 06:00:11 UTC, Matthias Walter wrote:
>> On 06/18/2012 07:36 AM, Mehrdad wrote:
>>> Is it just me, or did I subvert the type system here?
>>>
>>>
>>> import std.stdio;
>>>
>>> struct Const
>>> {
>>>     this(void delegate() increment)
>>>     { this.increment = increment; }
>>>     int a;
>>>     void delegate() increment;
>>>     void oops() const { this.increment(); }
>>> }
>>>
>>> void main()
>>> {
>>>     Const c;
>>>     c = Const({ c.a++; });
>>>     writeln(c.a);
>>>     c.oops();
>>>     writeln(c.a);
>>> }
>>>
>>
>> I don't think so. When calling oops you have two references to the object c:
>>
>> - The this-pointer of the object itself which is not allowed to change
>> the object in the const-call.
>> - The reference from within main which is allowed to change it and can
>> be reached via the frame pointer of the delegate.
>>
>> I see this as perfectly valid code. Of course, opinions may differ here.
>>
>> Matthias
> 
> 
> 
> My trouble isn't with the delegate, it's with the const method.
> 
> It's with the idea that "you can tell something about the code just by looking at it".
> 
> The way I understood it, you can assume that a `const` method cannot modify an object, but... that doesn't seem to be the case here.
> 
> What am I misunderstanding?

Its not, that a const method cannot modify an object, it just ensures
that the const method cannot modify the object *by using the this-pointer*.

Other things cannot be ensured with const: For example, a const method could wake up a 2nd thread and proceed with a longer computation. Then this 2nd thread may have a reference to the object and may change it while your computation is going on.
June 18, 2012
On Monday, 18 June 2012 at 06:14:22 UTC, Matthias Walter wrote:
> Its not, that a const method cannot modify an object, it just ensures that the const method cannot modify the object *by using the this-pointer*.



I see...


So that means you /can't/ tell something just by looking at a part of the code, right?

(Just mentioning this since this idea seemed to be emphasized a lot by D.)
June 18, 2012
On 06/18/2012 08:19 AM, Mehrdad wrote:
> On Monday, 18 June 2012 at 06:14:22 UTC, Matthias Walter wrote:
>> Its not, that a const method cannot modify an object, it just ensures that the const method cannot modify the object *by using the this-pointer*.
> 
> 
> 
> I see...
> 
> 
> So that means you /can't/ tell something just by looking at a part of the code, right?
> 
> (Just mentioning this since this idea seemed to be emphasized a lot
> by D.)

Yes, you are right with that.

June 18, 2012
Okay, how about this? http://ideone.com/VMlzS

Does this break const?


import std.stdio;
class S
{
        this(int a)
        {
                this.a = a;
                this.increment = { this.a++; };
        }
        int a;
        void delegate() increment;
        void oops() const { this.increment(); }
}
void main()
{
        auto c = new const(S)(0);
        writeln(c.a);
        c.oops();
        writeln(c.a);
}
June 18, 2012
On Monday, June 18, 2012 08:19:55 Mehrdad wrote:
> On Monday, 18 June 2012 at 06:14:22 UTC, Matthias Walter wrote:
> > Its not, that a const method cannot modify an object, it just ensures that the const method cannot modify the object *by using the this-pointer*.
> 
> I see...
> 
> 
> So that means you /can't/ tell something just by looking at a part of the code, right?
> 
> (Just mentioning this since this idea seemed to be emphasized a
> lot by D.)

You can if the function is pure as well, because then that delegate would not be legal. For instance, this code

import std.stdio;

struct Const
{
        this(void delegate() pure increment)
        { this.increment = increment; }
        int a;
        void delegate() pure increment;
        void oops() const pure { this.increment(); }
}

void main()
{
        Const c;
        c = Const({ c.a++; });
        writeln(c.a);
        c.oops();
        writeln(c.a);
}


fails to compile, giving this error:

q.d(15): Error: constructor q.Const.this (void delegate() pure increment) is not callable using argument types (void delegate() nothrow @safe)

All const guarantees is that the object isn't altered through the const reference/pointer (which in the case of a const function is this). That's powerful, but it needs pure as well to really be able to just glance at it and know that it's not altering your object.

If you want an extreme exampl. you could create an object whose entire state was held in a global variable, then the fact that the this pointer was const wouldn't mean much. But if the member functions were pure, then you couldn't access that global variable, and so that externalization of the state wouldn't work, and you'd be guaranteed that the const function didn't alter your object (as long as none of the arguments to that const function held a reference or pointer to that object anyway (though that's a fairly abnormal thing to do) - only strong purity absolutely guarantees that your object isn't being altered).

- Jonathan M Davis
« First   ‹ Prev
1 2 3 4 5 6 7 8 9 10 11
Top | Discussion index | About this forum | D home