www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP30, delegates more destruction for your pleasure

reply "deadalnix" <deadalnix gmail.com> writes:
http://wiki.dlang.org/DIP30

As usual, go for simplicity, reduce the number of entity the
language define.

Feel free to destroy.
Mar 13 2013
next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Wednesday, 13 March 2013 at 18:00:54 UTC, deadalnix wrote:
 http://wiki.dlang.org/DIP30

 As usual, go for simplicity, reduce the number of entity the
 language define.

 Feel free to destroy.

From "Fully typed delegates": "Delegate's context is assumed to be of type void*. However, it can be specified as a type after the parameter list ". This does not look like the best idea: 1) context pointer may point to function frame with several different objects, 2) there are no evidences in th DIP about which problems are solved by ability to append explicit type of context pointer. From " UFCS as delegates": example with function foo(ref uint a) raises concern about ABI implementation. Currently context pointer is passed through RDI and arguments are passed differently. There would be a problem with functions like foo() which do not know from where to take an argument - are they called directly or like a closure? Frankly, I see this simpler: delegate = function pointer + data pointer, so they should follow language rules (especially regarding qualifiers). Currently this works: struct S { immutable int i; void bar() {} int foo() immutable { //bar(); (&bar)(); return i; } } I think that delegate call should be treated as a function call with extra parameter. If .funcptr is deduced to have qualifier X, than delegate call should be permitted only if explicit regular function call with X qualifier is permitted in that scope. Similar should happen with .ptr.
Mar 13 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 04:12 AM, deadalnix wrote:
 ...

It is a tempting idea, but do not work. Consider : void delegate() immutable a; const void delegate() b = a; This would be forbidden as covariance of function parameters and transitivity act in opposite directions.

Uh, why? In my current opinion, it should be as follows: void main(){ void delegate()inout w; void delegate()immutable i; void delegate()const c; void delegate() m; void delegate()const inout wc; // The following cases should be disallowed: i=c; // there may be mutable references to context c=m; // m may modify context i=m; // m may modify context w=i; // cannot use immutable as const or mutable w=m; // cannot use mutable as immutable w=c; // cannot use const as immutable wc=m;// cannot use mutable as immutable wc=c;// wc will access context as const or immutable i=w; // inout could mean const or mutable c=w; // inout could mean mutable i=wc; // inout const could mean const // These should be allowed: c=i; // certainly const if only immutable data accessed c=wc;// certainly const if only const inout data accessed m=c; // just loses guarantees to caller m=i; // ditto m=w; // ditto m=wc;// ditto w=wc;// m=c, c=c and i=i are valid wc=i;// c=i and i=i are valid wc=w;// c=m is not valid, but does the same thing as c=c here } If you disagree with one of them, please demonstrate how to break the type system using the conversion, or argue why a conversion would be valid.
Mar 14 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 04:41 PM, deadalnix wrote:
 ...

 DIP updated.

Using a vastly different set of allowed/disallowed cases. Every delegate type must implicitly convert to unqualified. Otherwise attribute inference may break code that would be valid without. (this has to work differently with explicitly-typed contexts, because those are not opaque.)
 The loss of information in cases like m=i causes problem when the copy
 or the destruction of the context isn't trivial.

 Cases like c=m must be enabled as they will happen anyway by
 transitivity (or we must prevent delegate call when the type qualifier
 is changed via transitivity which seem worse to me).

I favour neither, but your approach removes all guarantees on const. (For the time being, my front end implements the parenthesized part.)
 inout const isn't a valid type qualifier so I dropped it.

I consider that a DMD bug.
Mar 14 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 05:14 PM, deadalnix wrote:
 On Thursday, 14 March 2013 at 16:01:28 UTC, Timon Gehr wrote:
 On 03/14/2013 04:41 PM, deadalnix wrote:
 ...

 DIP updated.

Using a vastly different set of allowed/disallowed cases. Every delegate type must implicitly convert to unqualified. Otherwise attribute inference may break code that would be valid without. (this has to work differently with explicitly-typed contexts, because those are not opaque.)

Can you elaborate on that please ? I fail to see the problem.

int foo(int delegate() dg){ return dg(); } void main(){ foo(delegate()=>2); // error, int delegate()pure immutable // does not convert to int delegate() }
 I favour neither, but your approach removes all guarantees on const.

Such guarantee can already be broken with aliasing so nothing new.

Guarantees about const pure functions are lost. This is new. (Assuming a sound implementation.)
 inout const isn't a valid type qualifier so I dropped it.

I consider that a DMD bug.

What would be the semantic ?

It's just the combination of const and inout. It behaves in the straightforward fashion. inout is a wildcard standing for mutable, const or immutable. inout is mutable => const(inout) = const inout is const => const(inout) = const(const) = const inout is immutable => const(inout) = const(immutable) = immutable Hence const(inout) can be seen as a wildcard standing for const or immutable (but that's just derived information). Identifying const(inout) with const, as DMD does it, gratuitously loses type information.
Mar 14 2013
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/14/2013 06:59 AM, Maxim Fomin wrote:
 On Thursday, 14 March 2013 at 05:29:25 UTC, deadalnix wrote:
 On Thursday, 14 March 2013 at 05:12:51 UTC, Maxim Fomin wrote:
 ABI, at least partly, is and should be part of the spec. Otherwise it
 has some of the C++ problems. And the point was not about ABI in a
 sense of adding piece of information to chapter in dlang.org, but
 about implementing compiler. I am not enthusiastic about most DIPs
 presented recently because 1) without Walter and Andrei approval 2)
 without somebody willing to implement it, DIP turns to be a paper
 intellect exercise and corresponding ideas defence in the forum.

Timon Gehr and I are working on compiler. This isn't intellectual masturbation.

And without significant usage it is a coding exercise or NIH syndrome.

There's a significant amount of easy-to-implement language features missing.
 What is good in the compiler (brand new frontend?) relative to
 gdc/ldc/dmd? Why somebody would switch to it?

I do not care whether someone switches to it, but the plan is: * Diagnostics - Nicely formatted: Yes. - Useful diagnostics for template instantiation failures: TODO * CTFE - Working: Yes (eg: full support for closures.) - Fast: Partly done. (the implementation is not as horribly slow as DMD's.) * Sane and well-defined treatment of complex analysis dependencies. - Makes sure that is-expressions are consistent and unambiguous throughout compilation. - To the point diagnostics. - dlang.org spec and DMD frontend fundamentally broken in this regard. - Mostly works already. * Complete independence of compiler backend - (In fact, there is no backend yet, CTFE is sufficient for testing.) * Easy-to-use minimal wrapper library - Enabling frameworks for program analysis. - Simple plugging of custom back ends. - Not done yet. * Using the front end in a code editor - Incremental compilation. (Change only code gen of the function that was last accessed. - Display of semantic information. - Not done yet. (But the design of the front end will support such endeavours nicely.) * Short to-the-point code. Written in D.
 ...

Mar 14 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
14-Mar-2013 20:45, Timon Gehr пишет:
 On 03/14/2013 06:59 AM, Maxim Fomin wrote:
 On Thursday, 14 March 2013 at 05:29:25 UTC, deadalnix wrote:
 On Thursday, 14 March 2013 at 05:12:51 UTC, Maxim Fomin wrote:
 ABI, at least partly, is and should be part of the spec. Otherwise it
 has some of the C++ problems. And the point was not about ABI in a
 sense of adding piece of information to chapter in dlang.org, but
 about implementing compiler. I am not enthusiastic about most DIPs
 presented recently because 1) without Walter and Andrei approval 2)
 without somebody willing to implement it, DIP turns to be a paper
 intellect exercise and corresponding ideas defence in the forum.

Timon Gehr and I are working on compiler. This isn't intellectual masturbation.

And without significant usage it is a coding exercise or NIH syndrome.

There's a significant amount of easy-to-implement language features missing.
 What is good in the compiler (brand new frontend?) relative to
 gdc/ldc/dmd? Why somebody would switch to it?

I do not care whether someone switches to it, but the plan is: * Diagnostics - Nicely formatted: Yes. - Useful diagnostics for template instantiation failures: TODO * CTFE - Working: Yes (eg: full support for closures.) - Fast: Partly done. (the implementation is not as horribly slow as DMD's.) * Sane and well-defined treatment of complex analysis dependencies. - Makes sure that is-expressions are consistent and unambiguous throughout compilation. - To the point diagnostics. - dlang.org spec and DMD frontend fundamentally broken in this regard. - Mostly works already. * Complete independence of compiler backend - (In fact, there is no backend yet, CTFE is sufficient for testing.) * Easy-to-use minimal wrapper library - Enabling frameworks for program analysis. - Simple plugging of custom back ends. - Not done yet. * Using the front end in a code editor - Incremental compilation. (Change only code gen of the function that was last accessed. - Display of semantic information. - Not done yet. (But the design of the front end will support such endeavours nicely.) * Short to-the-point code. Written in D.

Dunno about others but I'm sold. In fact, I was since I've first heard about it. -- Dmitry Olshansky
Mar 14 2013
prev sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
14-Mar-2013 09:59, Maxim Fomin пишет:
 On Thursday, 14 March 2013 at 05:29:25 UTC, deadalnix wrote:
 On Thursday, 14 March 2013 at 05:12:51 UTC, Maxim Fomin wrote:
 ABI, at least partly, is and should be part of the spec. Otherwise it
 has some of the C++ problems. And the point was not about ABI in a
 sense of adding piece of information to chapter in dlang.org, but
 about implementing compiler. I am not enthusiastic about most DIPs
 presented recently because 1) without Walter and Andrei approval 2)
 without somebody willing to implement it, DIP turns to be a paper
 intellect exercise and corresponding ideas defence in the forum.

Timon Gehr and I are working on compiler. This isn't intellectual masturbation.

And without significant usage it is a coding exercise or NIH syndrome. What is good in the compiler (brand new frontend?) relative to gdc/ldc/dmd? Why somebody would switch to it?

Being fed up with 'the one and only' and 'the implementation is the reference' principle? The more compilers we have - the better defined language standard we get. And the latter is a very good thing in its own right. -- Dmitry Olshansky
Mar 14 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/13/2013 07:00 PM, deadalnix wrote:
 http://wiki.dlang.org/DIP30

 As usual, go for simplicity, reduce the number of entity the
 language define.

 Feel free to destroy.

It's quite pretty. But: 1. Removes optional parens for UFCS 2. Syntactic confusion of ref applying to return value and ref applying to context. Rules are insufficiently specified. 3. Misses the load mutable-context delegate from const-qualified type case. 4. typeof(dg.ptr), typeof(dg.funcptr) ? (quite obvious what you want, but missing) Also: You will have to change the ABI in order to unify UFCS with methods, because the implicit 'this' pointer is passed as the last argument for methods IIRC.
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 13 March 2013 at 18:54:29 UTC, Maxim Fomin wrote:
 From "Fully typed delegates": "Delegate's context is assumed to 
 be of type void*. However, it can be specified as a type after 
 the parameter list ".

Pointer already cast to void* so that isn't really new. ref are pointer behind the hood. This is necessary as the context type is especially important for value types, not really for reference/pointers.
 This does not look like the best idea: 1) context pointer may 
 point to function frame with several different objects, 2) 
 there are no evidences in th DIP about which problems are 
 solved by ability to append explicit type of context pointer.

1) It is explained : context is a pointer to a tuple. 2) It does allow value type as context, which in return allow to unify many construct into delegates. It also solve the qualifier transitivity problem.
 From " UFCS as delegates": example with function foo(ref uint 
 a) raises concern about ABI implementation. Currently context 
 pointer is passed through RDI and arguments are passed 
 differently. There would be a problem with functions like foo() 
 which do not know from where to take an argument - are they 
 called directly or like a closure?

I don't think ABI should be part of D spec. Or should it ? Anyway, I don't see any reason to have all kind of different ABI for function call, and this is a good opportunity to unify everything using the context as a regular, first argument.
 Frankly, I see this simpler: delegate = function pointer + data 
 pointer, so they should follow language rules (especially 
 regarding qualifiers).

It is a tempting idea, but do not work. Consider : void delegate() immutable a; const void delegate() b = a; This would be forbidden as covariance of function parameters and transitivity act in opposite directions.
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 13 March 2013 at 20:43:13 UTC, Timon Gehr wrote:
 On 03/13/2013 07:00 PM, deadalnix wrote:
 http://wiki.dlang.org/DIP30

 As usual, go for simplicity, reduce the number of entity the
 language define.

 Feel free to destroy.

It's quite pretty. But: 1. Removes optional parens for UFCS

It is still possible to have optional () in many cases. For instance in chained calls. It have the big advantage to unify the optional () for all callable (and we only have 2 of them now).
 2. Syntactic confusion of ref applying to return value and ref 
 applying to context. Rules are insufficiently specified.

Yeah, the idea is basically to differentiate prefix and postfix qualifiers. Note that this is already ambiguous in many cases in the current grammar.
 3. Misses the load mutable-context delegate from 
 const-qualified type case.

Yeah, I clearly have to edit the DIP to explain that.
 4. typeof(dg.ptr), typeof(dg.funcptr) ? (quite obvious what you 
 want, but missing)

 Also: You will have to change the ABI in order to unify UFCS 
 with methods, because the implicit 'this' pointer is passed as 
 the last argument for methods IIRC.

I don't see the point of having a different ABI in the first place, and am not sure if ABI should be specified here.
Mar 13 2013
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
--047d7b86db60a0925e04d7da5a08
Content-Type: text/plain; charset=UTF-8

2013/3/14 deadalnix <deadalnix gmail.com>
 It is a tempting idea, but do not work. Consider :

 void delegate() immutable a;
 const void delegate() b = a;

 This would be forbidden as covariance of function parameters and
 transitivity act in opposite directions.

You are misunderstanding about delegate type syntax and transitivity. 1. This qualifier for delegate type should be added after parameter types. const void delegate() b; // bad, typeof(b) == const(void deelgate()) void delegate() const b; // good, b can hold const method 2. A delegate which has immutable context cannot implicitly convertible to const context delegate. In general, if a delegate can implicitly convertible to another, there should be _contravariance_ of parameter types. void delegate() immutable a; void delegate() const b; b = a; // bad a = b; // good Kenji Hara --047d7b86db60a0925e04d7da5a08 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">2013= /3/14 deadalnix <span dir=3D"ltr">&lt;<a href=3D"mailto:deadalnix gmail.com= " target=3D"_blank">deadalnix gmail.com</a>&gt;</span><blockquote class=3D"= gmail_quote" style=3D"margin-top:0px;margin-right:0px;margin-bottom:0px;mar= gin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);bor= der-left-style:solid;padding-left:1ex"> It is a tempting idea, but do not work. Consider :<br> <br> void delegate() immutable a;<br> const void delegate() b =3D a;<br> <br> This would be forbidden as covariance of function parameters and transitivi= ty act in opposite directions.<br> </blockquote></div><br></div><div class=3D"gmail_extra">You are misundersta= nding about delegate type syntax and transitivity.</div><div class=3D"gmail= _extra"><br></div><div class=3D"gmail_extra">1. This qualifier for delegate= type should be added after parameter types.</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">const void = delegate() b;=C2=A0 =C2=A0// bad, typeof(b) =3D=3D const(void deelgate())<b= r></div><div class=3D"gmail_extra">void delegate()=C2=A0const=C2=A0b;=C2=A0= =C2=A0// good, b can hold const method</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">2. A delega= te which has immutable context cannot implicitly convertible to const conte= xt delegate.</div><div class=3D"gmail_extra"><br></div><div class=3D"gmail_= extra"> In general, if a delegate can implicitly convertible to another, there shou= ld be _contravariance_ of parameter types.<br></div><div class=3D"gmail_ext= ra"><br></div><div class=3D"gmail_extra">void delegate() immutable a;<br></= div> <div class=3D"gmail_extra">void delegate()=C2=A0const=C2=A0b;</div><div cla= ss=3D"gmail_extra">b =3D a; =C2=A0// bad<br></div><div class=3D"gmail_extra= ">a =3D b; =C2=A0// good</div><div class=3D"gmail_extra"><div><br></div><di= v>Kenji Hara</div></div></div> --047d7b86db60a0925e04d7da5a08--
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 03:45:39 UTC, kenji hara wrote:
 2013/3/14 deadalnix <deadalnix gmail.com>
 It is a tempting idea, but do not work. Consider :

 void delegate() immutable a;
 const void delegate() b = a;

 This would be forbidden as covariance of function parameters 
 and
 transitivity act in opposite directions.

You are misunderstanding about delegate type syntax and transitivity. 1. This qualifier for delegate type should be added after parameter types. const void delegate() b; // bad, typeof(b) == const(void deelgate()) void delegate() const b; // good, b can hold const method

After or before don't change anything here as type qualifier are transitives. It means that a const delegate must have a const context. Or, in code : static assert(is(const delegate() == const delegate() const)); // Pass
 2. A delegate which has immutable context cannot implicitly 
 convertible to
 const context delegate.

 In general, if a delegate can implicitly convertible to 
 another, there
 should be _contravariance_ of parameter types.

 void delegate() immutable a;
 void delegate() const b;
 b = a;  // bad
 a = b;  // good

As showed above, this is equivalent to my sample code in the previous post, and it does break transitivity. void delegate() const b; // Context of b is const (ie mutable or immutable). void delegate() immutable a; // Context of a is immutable a = b; // a now contains a reference to possibly mutable data considered as immutable by the type system. This is *VERY* wrong.
Mar 13 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 14 March 2013 at 03:12:21 UTC, deadalnix wrote:
 From " UFCS as delegates": example with function foo(ref uint 
 a) raises concern about ABI implementation. Currently context 
 pointer is passed through RDI and arguments are passed 
 differently. There would be a problem with functions like 
 foo() which do not know from where to take an argument - are 
 they called directly or like a closure?

I don't think ABI should be part of D spec. Or should it ? Anyway, I don't see any reason to have all kind of different ABI for function call, and this is a good opportunity to unify everything using the context as a regular, first argument.

ABI, at least partly, is and should be part of the spec. Otherwise it has some of the C++ problems. And the point was not about ABI in a sense of adding piece of information to chapter in dlang.org, but about implementing compiler. I am not enthusiastic about most DIPs presented recently because 1) without Walter and Andrei approval 2) without somebody willing to implement it, DIP turns to be a paper intellect exercise and corresponding ideas defence in the forum.
 Frankly, I see this simpler: delegate = function pointer + 
 data pointer, so they should follow language rules (especially 
 regarding qualifiers).

It is a tempting idea, but do not work. Consider : void delegate() immutable a; const void delegate() b = a; This would be forbidden as covariance of function parameters and transitivity act in opposite directions.

The problem is that there is 1 qualifier in current syntax and two underlying objects.
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 05:12:51 UTC, Maxim Fomin wrote:
 On Thursday, 14 March 2013 at 03:12:21 UTC, deadalnix wrote:
 From " UFCS as delegates": example with function foo(ref uint 
 a) raises concern about ABI implementation. Currently context 
 pointer is passed through RDI and arguments are passed 
 differently. There would be a problem with functions like 
 foo() which do not know from where to take an argument - are 
 they called directly or like a closure?

I don't think ABI should be part of D spec. Or should it ? Anyway, I don't see any reason to have all kind of different ABI for function call, and this is a good opportunity to unify everything using the context as a regular, first argument.

ABI, at least partly, is and should be part of the spec. Otherwise it has some of the C++ problems. And the point was not about ABI in a sense of adding piece of information to chapter in dlang.org, but about implementing compiler. I am not enthusiastic about most DIPs presented recently because 1) without Walter and Andrei approval 2) without somebody willing to implement it, DIP turns to be a paper intellect exercise and corresponding ideas defence in the forum.

Timon Gehr and I are working on compiler. This isn't intellectual masturbation. As of ABI, it is right now insufficiently defined to have a situation different than C++'s.
 The problem is that there is 1 qualifier in current syntax and 
 two underlying objects.

Exactly. And theses are using different (and opposite) rules for implicit casts.
Mar 13 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 14 March 2013 at 05:29:25 UTC, deadalnix wrote:
 On Thursday, 14 March 2013 at 05:12:51 UTC, Maxim Fomin wrote:
 ABI, at least partly, is and should be part of the spec. 
 Otherwise it has some of the C++ problems. And the point was 
 not about ABI in a sense of adding piece of information to 
 chapter in dlang.org, but about implementing compiler. I am 
 not enthusiastic about most DIPs presented recently because 1) 
 without Walter and Andrei approval 2) without somebody willing 
 to implement it, DIP turns to be a paper intellect exercise 
 and corresponding ideas defence in the forum.

Timon Gehr and I are working on compiler. This isn't intellectual masturbation.

And without significant usage it is a coding exercise or NIH syndrome. What is good in the compiler (brand new frontend?) relative to gdc/ldc/dmd? Why somebody would switch to it?
 As of ABI, it is right now insufficiently defined to have a 
 situation different than C++'s.

Yes, and this is a problem. But at least it does exists and covers some aspects.
 The problem is that there is 1 qualifier in current syntax and 
 two underlying objects.

Exactly. And theses are using different (and opposite) rules for implicit casts.

The perhaps should we move DIP in that direction too?
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 05:59:09 UTC, Maxim Fomin wrote:
 On Thursday, 14 March 2013 at 05:29:25 UTC, deadalnix wrote:
 On Thursday, 14 March 2013 at 05:12:51 UTC, Maxim Fomin wrote:
 ABI, at least partly, is and should be part of the spec. 
 Otherwise it has some of the C++ problems. And the point was 
 not about ABI in a sense of adding piece of information to 
 chapter in dlang.org, but about implementing compiler. I am 
 not enthusiastic about most DIPs presented recently because 
 1) without Walter and Andrei approval 2) without somebody 
 willing to implement it, DIP turns to be a paper intellect 
 exercise and corresponding ideas defence in the forum.

Timon Gehr and I are working on compiler. This isn't intellectual masturbation.

And without significant usage it is a coding exercise or NIH syndrome. What is good in the compiler (brand new frontend?) relative to gdc/ldc/dmd? Why somebody would switch to it?

ldc/gdc/dmd all uses the same frontend. The frontend is not suitable to build static analysis tools, or any tool in general (code formater, ide support, repl, anything). It has many quirk, especially when you start mixing advanced features together. In general, many people think that D suffer to be too much tied to one implementation.
 As of ABI, it is right now insufficiently defined to have a 
 situation different than C++'s.

Yes, and this is a problem. But at least it does exists and covers some aspects.

If I had to specify it, I'd say that context and this parameter goes as first argument 100% of the time.
 The problem is that there is 1 qualifier in current syntax 
 and two underlying objects.

Exactly. And theses are using different (and opposite) rules for implicit casts.

The perhaps should we move DIP in that direction too?

I'll edit it tonight.
Mar 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 11:42:29 UTC, Timon Gehr wrote:
 On 03/14/2013 04:12 AM, deadalnix wrote:
 ...

It is a tempting idea, but do not work. Consider : void delegate() immutable a; const void delegate() b = a; This would be forbidden as covariance of function parameters and transitivity act in opposite directions.

Uh, why?

This would be forbidden, according to the rule expressed in the post + transitivity guaranty. That is not the position I defend.
 In my current opinion, it should be as follows:

 void main(){
 	void delegate()inout w;
 	void delegate()immutable i;
 	void delegate()const c;
 	void delegate() m;
 	void delegate()const inout wc;
 	
 	// The following cases should be disallowed:
 	
 	i=c; // there may be mutable references to context
 	c=m; // m may modify context
 	i=m; // m may modify context
 	w=i; // cannot use immutable as const or mutable
 	w=m; // cannot use mutable as immutable
 	w=c; // cannot use const as immutable
 	wc=m;// cannot use mutable as immutable
 	wc=c;// wc will access context as const or immutable
 	i=w; // inout could mean const or mutable
 	c=w; // inout could mean mutable
 	i=wc; // inout const could mean const

 	// These should be allowed:
 	
 	c=i; // certainly const if only immutable data accessed
 	c=wc;// certainly const if only const inout data accessed
 	m=c; // just loses guarantees to caller
 	m=i; // ditto
 	m=w; // ditto
 	m=wc;// ditto
 	w=wc;// m=c, c=c and i=i are valid
 	wc=i;// c=i and i=i are valid
 	wc=w;// c=m is not valid, but does the same thing as c=c here
 }

 If you disagree with one of them, please demonstrate how to 
 break the type system using the conversion, or argue why a 
 conversion would be valid.

I do agree with you on that one. However, c=m may be ok, as nothing immutable can be muted. That is an open question. inout don't make a lot of sense without return type. It needs to be ironed out in that regard. Very good list !
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 11:42:29 UTC, Timon Gehr wrote:
 On 03/14/2013 04:12 AM, deadalnix wrote:
 ...

It is a tempting idea, but do not work. Consider : void delegate() immutable a; const void delegate() b = a; This would be forbidden as covariance of function parameters and transitivity act in opposite directions.

Uh, why? In my current opinion, it should be as follows: void main(){ void delegate()inout w; void delegate()immutable i; void delegate()const c; void delegate() m; void delegate()const inout wc; // The following cases should be disallowed: i=c; // there may be mutable references to context c=m; // m may modify context i=m; // m may modify context w=i; // cannot use immutable as const or mutable w=m; // cannot use mutable as immutable w=c; // cannot use const as immutable wc=m;// cannot use mutable as immutable wc=c;// wc will access context as const or immutable i=w; // inout could mean const or mutable c=w; // inout could mean mutable i=wc; // inout const could mean const // These should be allowed: c=i; // certainly const if only immutable data accessed c=wc;// certainly const if only const inout data accessed m=c; // just loses guarantees to caller m=i; // ditto m=w; // ditto m=wc;// ditto w=wc;// m=c, c=c and i=i are valid wc=i;// c=i and i=i are valid wc=w;// c=m is not valid, but does the same thing as c=c here } If you disagree with one of them, please demonstrate how to break the type system using the conversion, or argue why a conversion would be valid.

DIP updated. The loss of information in cases like m=i causes problem when the copy or the destruction of the context isn't trivial. Cases like c=m must be enabled as they will happen anyway by transitivity (or we must prevent delegate call when the type qualifier is changed via transitivity which seem worse to me). inout const isn't a valid type qualifier so I dropped it.
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 16:01:28 UTC, Timon Gehr wrote:
 On 03/14/2013 04:41 PM, deadalnix wrote:
 ...

 DIP updated.

Using a vastly different set of allowed/disallowed cases. Every delegate type must implicitly convert to unqualified. Otherwise attribute inference may break code that would be valid without. (this has to work differently with explicitly-typed contexts, because those are not opaque.)

Can you elaborate on that please ? I fail to see the problem.
 I favour neither, but your approach removes all guarantees on 
 const.

Such guarantee can already be broken with aliasing so nothing new.
 inout const isn't a valid type qualifier so I dropped it.

I consider that a DMD bug.

What would be the semantic ?
Mar 14 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 21:29:26 UTC, Timon Gehr wrote:
 int foo(int delegate() dg){ return dg(); }

 void main(){
     foo(delegate()=>2); // error, int delegate()pure immutable
                         // does not convert to int delegate()
 }

That make sense. The rules have to be loosened.
 Guarantees about const pure functions are lost. This is new. 
 (Assuming a sound implementation.)

Yes. This is still better than hole in the type system IMO.
 It's just the combination of const and inout.
 It behaves in the straightforward fashion.

 inout is a wildcard standing for mutable, const or immutable.

 inout is mutable   => const(inout) = const
 inout is const     => const(inout) = const(const) = const
 inout is immutable => const(inout) = const(immutable) = 
 immutable

 Hence const(inout) can be seen as a wildcard standing for const 
 or immutable (but that's just derived information). Identifying 
 const(inout) with const, as DMD does it, gratuitously loses 
 type information.

I see. Type qualifier come at high cost, so I'm not sure.
Mar 14 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Thursday, 14 March 2013 at 21:29:26 UTC, Timon Gehr wrote:
 int foo(int delegate() dg){ return dg(); }

 void main(){
     foo(delegate()=>2); // error, int delegate()pure immutable
                         // does not convert to int delegate()
 }

OK, is it possible to consider naked delegate as const(void*) then ? I think we should go for the usual instead of the covariant one as you propose. The regular will happen anyway and it is quite hard to keep everything together without introducing annoying rules. For instance : class Foo { delegate() bar; } Foo f = new Foo(); d.bar = { ... } const g = f; g.bar(); // ???
Mar 15 2013