June 18, 2012
Le 18/06/2012 17:16, Mehrdad a écrit :
> On Monday, 18 June 2012 at 15:13:33 UTC, deadalnix wrote:
>>> Identical calls giving identical results? What?
>>>
>>>
>>> import std.stdio;
>>> struct S
>>> {
>>> this(int a)
>>> {
>>> this.a = a;
>>> this.increment = { return this.a++; };
>>> }
>>> int a;
>>> int delegate() pure increment;
>>> auto oops() const { return this.increment(); }
>>> }
>>> void main()
>>> {
>>> auto c = immutable(S)(0);
>>> writeln(c.oops()); // 0
>>> writeln(c.oops()); // 1
>>> writeln(c.oops()); // 2
>>> writeln(c.oops()); // 3
>>> writeln(c.oops()); // 4
>>> writeln(c.oops()); // 5
>>> }
>>
>> They are not call with the same parameters. The hidden parameter have
>> changed (I know this is tricky).
>
>
> Explain it however you want.
>
> The bottom line I'm getting at is, you can't re-order the calls, EVEN IF
> by "looking at them" you can tell they're pure @safe nothrow const...

Yes, but this isn't a problem with pure here, this is a problem with const.

The sample code should not compile.
June 18, 2012
On Monday, 18 June 2012 at 15:19:26 UTC, deadalnix wrote:
>
> Yes, but this isn't a problem with pure here, this is a problem with const.

Hence the title...

> The sample code should not compile.

What should the error be? Is it correct in the language spec?
June 18, 2012
On 06/18/2012 05:15 PM, Mehrdad wrote:
> On Monday, 18 June 2012 at 15:11:00 UTC, Timon Gehr wrote:
>> On 06/18/2012 04:55 PM, Mehrdad wrote:
>>>
>>> Identical calls giving identical results? What?
>>>
>>>
>>> import std.stdio;
>>> struct S
>>> {
>>>          this(int a)
>>>          {
>>>                  this.a = a;
>>>                  this.increment = { return this.a++; };
>>>          }
>>>          int a;
>>>          int delegate() pure increment;
>>>          auto oops() const { return this.increment(); }
>>> }
>>> void main()
>>> {
>>>          auto c = immutable(S)(0);
>>>          writeln(c.oops()); // 0
>>>          writeln(c.oops()); // 1
>>>          writeln(c.oops()); // 2
>>>          writeln(c.oops()); // 3
>>>          writeln(c.oops()); // 4
>>>          writeln(c.oops()); // 5
>>> }
>>
>> Now you have managed to break the type system.
>> The underlying issue is unrelated to delegates though.
>
>
>
> Yeah, I didn't mean to say it's a delegate issue either. That's why the
> title was saying "how to break _const_".  Delegates were just a means to
> an end. :)
>
>
> So (**IMHO**) if that's really the case, we should really spend some
> time fixing the /design/ of const before the implementation...

This is mostly about the design of object initialisation.

> good idea or no?

Certainly.
June 18, 2012
On 06/18/2012 05:13 PM, deadalnix wrote:
> Le 18/06/2012 16:55, Mehrdad a écrit :
>> On Monday, 18 June 2012 at 14:48:37 UTC, deadalnix wrote:
>>> Le 18/06/2012 16:44, Mehrdad a écrit :
>>>> Interesting, making the delegate `pure' doesn't change anything either.
>>>>
>>>> So 'pure' doesn't let you "infer something just by looking at the code
>>>> either", right?
>>>
>>> It does ! It tell you that the function have no side effect, and that
>>> the function called with identical arguments will return identical
>>> results.
>>>
>>> pure will not ensure constness or immutability. const and immutable
>>> are made for that.
>>>
>>> The fact that D decouple purity and immutability is a very nice design
>>> decision and is explained nicely here :
>>> http://klickverbot.at/blog/2012/05/purity-in-d/
>>
>>
>>
>> Identical calls giving identical results? What?
>>
>>
>> import std.stdio;
>> struct S
>> {
>> this(int a)
>> {
>> this.a = a;
>>     this.increment = { return this.a++; };
>> }
>> int a;
>> int delegate() pure increment;
>> auto oops() const { return this.increment(); }
>> }
>> void main()
>> {
>>     auto c = immutable(S)(0);
>>     writeln(c.oops()); // 0
>>     writeln(c.oops()); // 1
>>     writeln(c.oops()); // 2
>>     writeln(c.oops()); // 3
>>     writeln(c.oops()); // 4
>>     writeln(c.oops()); // 5
>> }
>
> They are not call with the same parameters. The hidden parameter have
> changed (I know this is tricky).

The whole problem is that the hidden parameter has changed. It is immutable!
June 18, 2012
On Monday, 18 June 2012 at 15:21:36 UTC, Timon Gehr wrote:
>> So (**IMHO**) if that's really the case, we should really spend some
>> time fixing the /design/ of const before the implementation...
>
> This is mostly about the design of object initialisation.
>
>> good idea or no?
>
> Certainly.


My initial instinct would be to require a "const constructor" in order for an object to be const-able, but I'm not sure if that would work correctly or not..
June 18, 2012
Le 18/06/2012 17:20, Mehrdad a écrit :
> On Monday, 18 June 2012 at 15:19:26 UTC, deadalnix wrote:
>>
>> Yes, but this isn't a problem with pure here, this is a problem with
>> const.
>
> Hence the title...
>
>> The sample code should not compile.
>
> What should the error be? Is it correct in the language spec?

The specification lack on that point, because we are here facing a specification bug. Depending on how we choose to fix that, the error can be different.

Fix the initializer to dissalow the way you initialize c is probably the way to go on that specific case. Andrei says that work have been done in that direction, but I'm not aware of where it is now. It also require a way to qualify the frame pointer; which isn't possible ATM.
June 18, 2012
Le 18/06/2012 17:23, Timon Gehr a écrit :
> On 06/18/2012 05:13 PM, deadalnix wrote:
>> Le 18/06/2012 16:55, Mehrdad a écrit :
>>> On Monday, 18 June 2012 at 14:48:37 UTC, deadalnix wrote:
>>>> Le 18/06/2012 16:44, Mehrdad a écrit :
>>>>> Interesting, making the delegate `pure' doesn't change anything
>>>>> either.
>>>>>
>>>>> So 'pure' doesn't let you "infer something just by looking at the code
>>>>> either", right?
>>>>
>>>> It does ! It tell you that the function have no side effect, and that
>>>> the function called with identical arguments will return identical
>>>> results.
>>>>
>>>> pure will not ensure constness or immutability. const and immutable
>>>> are made for that.
>>>>
>>>> The fact that D decouple purity and immutability is a very nice design
>>>> decision and is explained nicely here :
>>>> http://klickverbot.at/blog/2012/05/purity-in-d/
>>>
>>>
>>>
>>> Identical calls giving identical results? What?
>>>
>>>
>>> import std.stdio;
>>> struct S
>>> {
>>> this(int a)
>>> {
>>> this.a = a;
>>> this.increment = { return this.a++; };
>>> }
>>> int a;
>>> int delegate() pure increment;
>>> auto oops() const { return this.increment(); }
>>> }
>>> void main()
>>> {
>>> auto c = immutable(S)(0);
>>> writeln(c.oops()); // 0
>>> writeln(c.oops()); // 1
>>> writeln(c.oops()); // 2
>>> writeln(c.oops()); // 3
>>> writeln(c.oops()); // 4
>>> writeln(c.oops()); // 5
>>> }
>>
>> They are not call with the same parameters. The hidden parameter have
>> changed (I know this is tricky).
>
> The whole problem is that the hidden parameter has changed. It is
> immutable!

As said, this is effectively a const/immutable issue. Not a purity issue.

I'm not claiming that this code is fine, just explaining that the code is fine in regard to purity.
June 18, 2012
On Monday, 18 June 2012 at 15:24:31 UTC, Mehrdad wrote:
> On Monday, 18 June 2012 at 15:21:36 UTC, Timon Gehr wrote:
>>> So (**IMHO**) if that's really the case, we should really spend some
>>> time fixing the /design/ of const before the implementation...
>>
>> This is mostly about the design of object initialisation.
>>
>>> good idea or no?
>>
>> Certainly.
>
>
> My initial instinct would be to require a "const constructor" in order for an object to be const-able, but I'm not sure if that would work correctly or not..

Come to think of it, that would play REALLY nicely with 'scope' -- a reference to a non-const object can be escaped from a 'const constructor' if and only if the reference is scope!

Bingo! Does that work??
June 18, 2012
On 06/18/2012 05:14 PM, Christophe Travert wrote:
> Matthias Walter , dans le message (digitalmars.D:170036), a écrit :
>> 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.
>
> But here, the frame pointer of the delegate is part of the const
> structure. By transitivity, the frame pointer should be const, ...

'By transitivity' is not a sufficient reason. What you really mean is
'For the guarantee that a const pure method does not change its mutable
parameters'.
June 18, 2012
Le 18/06/2012 17:28, Mehrdad a écrit :
> On Monday, 18 June 2012 at 15:24:31 UTC, Mehrdad wrote:
>> On Monday, 18 June 2012 at 15:21:36 UTC, Timon Gehr wrote:
>>>> So (**IMHO**) if that's really the case, we should really spend some
>>>> time fixing the /design/ of const before the implementation...
>>>
>>> This is mostly about the design of object initialisation.
>>>
>>>> good idea or no?
>>>
>>> Certainly.
>>
>>
>> My initial instinct would be to require a "const constructor" in order
>> for an object to be const-able, but I'm not sure if that would work
>> correctly or not..
>
> Come to think of it, that would play REALLY nicely with 'scope' -- a
> reference to a non-const object can be escaped from a 'const
> constructor' if and only if the reference is scope!
>
> Bingo! Does that work??

Indeed, this should be scope for ctor (avoid partially initialized object in 3rd party code) /dtor (avoid resurrection, which is a real pain for any GC, and a very good way to ends up with alive object in invalid state).