digitalmars.D.learn - Implicit cast to immutable
- bearophile (14/14) Oct 05 2011 Do you know why this program doesn't compile (with DMD 2.056head)?
- Andrej Mitrovic (7/7) Oct 05 2011 Maybe:
- bearophile (6/16) Oct 05 2011 Right.
- travert phare.normalesup.org (Christophe) (11/34) Oct 06 2011 The error message tells you why. new int[1] is not castable to immutable...
- bearophile (5/11) Oct 06 2011 The compiler is already able to infer delegate purity, I think.
- Steven Schveighoffer (9/22) Oct 06 2011 I think it's a bug.
- Daniel Murphy (16/31) Oct 15 2011 The implicit conversion to immutable is only possible inside strongly pu...
- Steven Schveighoffer (19/34) Oct 17 2011 That sounds like an incorrect restriction. The implicit cast to immutab...
- Daniel Murphy (28/40) Oct 17 2011 I think you've misunderstood what I'm saying. The patch I made implemen...
- bearophile (5/11) Oct 18 2011 This is the enhancement request I have written days ago:
- Daniel Murphy (21/33) Oct 18 2011 Yes, and the problem in that report is that the function is const-pure, ...
- travert phare.normalesup.org (Christophe) (16/57) Oct 21 2011 What is the rule ?
- Steven Schveighoffer (25/81) Oct 24 2011 crit :
- travert phare.normalesup.org (Christophe) (11/86) Oct 27 2011 OK, it must be proven from the signature of the function alone, and not
- Steven Schveighoffer (31/82) Oct 19 2011 Neither of those is relevant, since they do not contain parameters (I'm ...
- Daniel Murphy (14/102) Oct 19 2011 Yeah, they were supposed to be pure. I was just demonstrating that
- Steven Schveighoffer (39/165) Oct 19 2011 I had not thought about classes (or interfaces), I was only thinking of ...
Do you know why this program doesn't compile (with DMD 2.056head)? immutable(int[]) foo(in int[] x) pure { return new int[1]; } void main() {} It gives: test.d(2): Error: cannot implicitly convert expression (new int[](1u)) of type int[] to immutable(int[]) This program instead compiles (now x is int[2] instead of int[]): immutable(int[]) foo(in int[2] x) pure { return new int[1]; } void main() {} Bye and thank you, bearophile
Oct 05 2011
Maybe: immutable(int[]) foo(in int[] x) pure { return new immutable(int[1]); } void main() {} Or does this have something to do with implicit casts to immutable for pure functions? I'm only vaguely familiar with pure..
Oct 05 2011
Andrej Mitrovic:Maybe: immutable(int[]) foo(in int[] x) pure { return new immutable(int[1]); } void main() {}I'd like to know why the code in my original post doesn't compile. I suspect it's a DMD bug, but I am not sure.Or does this have something to do with implicit casts to immutable for pure functions?Right.I'm only vaguely familiar with pure..I suggest you to use purity more and more in D, because it helps and with the recent bug fixes it is also becoming usable in D (but there are some significant problems left, example: map/filter are not pure yet). Bye and thank you, bearophile
Oct 05 2011
bearophile , dans le message (digitalmars.D.learn:29961), a écrit :Andrej Mitrovic:The error message tells you why. new int[1] is not castable to immutable int[] (in a pure function). The solution is to change new int[1] to make it immutable directly. That is very consistent, so I don't think this should be considered as a bug. There may be an improvement to ask to make the compiler able to check when the cast to immutable is safe, but I don't think there is a bug.Maybe: immutable(int[]) foo(in int[] x) pure { return new immutable(int[1]); } void main() {}I'd like to know why the code in my original post doesn't compile. I suspect it's a DMD bug, but I am not sure.You would need to have pure delegates to have a real effect, wouldn't you ? -- ChristopheOr does this have something to do with implicit casts to immutable for pure functions?Right.I'm only vaguely familiar with pure..I suggest you to use purity more and more in D, because it helps and with the recent bug fixes it is also becoming usable in D (but there are some significant problems left, example: map/filter are not pure yet).
Oct 06 2011
Christophe:That is very consistent, so I don't think this should be considered as a bug. There may be an improvement to ask to make the compiler able to check when the cast to immutable is safe, but I don't think there is a bug.The compiler already performs such checks, in this case it answers "no" and I don't understand why, I think it's not the right answer.You would need to have pure delegates to have a real effect, wouldn't you ?The compiler is already able to infer delegate purity, I think. Bye, bearophile
Oct 06 2011
On Wed, 05 Oct 2011 19:19:37 -0400, bearophile <bearophileHUGS lycos.com> wrote:Do you know why this program doesn't compile (with DMD 2.056head)? immutable(int[]) foo(in int[] x) pure { return new int[1]; } void main() {} It gives: test.d(2): Error: cannot implicitly convert expression (new int[](1u)) of type int[] to immutable(int[]) This program instead compiles (now x is int[2] instead of int[]): immutable(int[]) foo(in int[2] x) pure { return new int[1]; } void main() {}I think it's a bug. new should be considered pure, and since it's return value cannot be a reference to any parameter, it should implicitly cast to immutable. The fact that changing the parameter to foo makes it compile is a big clue. Note, this should compile even if foo isn't pure, since new is pure (no matter what type of function it is in). -Steve
Oct 06 2011
The implicit conversion to immutable is only possible inside strongly pure functions. When the parameter is 'in int[]' foo cannot be strongly pure, only const pure. As 'in int[2]' is a value type, the second foo can be strongly pure. 'new' expressions will hopefully be able to be converted to immutable eventually, along with array concatenation and array.dup. It is also likely that the following will be valid code (const pure foo called with immutable arguments) int[] foo(in int[] x) pure { return new int[1]; } void main() { immutable x = foo([1, 2, 3].idup); } "bearophile" <bearophileHUGS lycos.com> wrote in message news:j6iom9$2g1m$1 digitalmars.com...Do you know why this program doesn't compile (with DMD 2.056head)? immutable(int[]) foo(in int[] x) pure { return new int[1]; } void main() {} It gives: test.d(2): Error: cannot implicitly convert expression (new int[](1u)) of type int[] to immutable(int[]) This program instead compiles (now x is int[2] instead of int[]): immutable(int[]) foo(in int[2] x) pure { return new int[1]; } void main() {} Bye and thank you, bearophile
Oct 15 2011
On Sat, 15 Oct 2011 23:05:43 -0400, Daniel Murphy <yebblies nospamgmail.com> wrote:The implicit conversion to immutable is only possible inside strongly pure functions. When the parameter is 'in int[]' foo cannot be strongly pure, only const pure. As 'in int[2]' is a value type, the second foo can be strongly pure. 'new' expressions will hopefully be able to be converted to immutable eventually, along with array concatenation and array.dup. It is also likely that the following will be valid code (const pure foo called with immutable arguments) int[] foo(in int[] x) pure { return new int[1]; } void main() { immutable x = foo([1, 2, 3].idup); }That sounds like an incorrect restriction. The implicit cast to immutable should depend on whether the function being *called* qualifies, not if the function you are calling *from* qualifies. Qualifying means the return type should be mutable, and cannot be derived from the parameters without requiring casts. The easiest way to do this is to ensure the parameters are all const, immutable, or implicitly cast to immutable. You could do funky things like assume for instance an int[] cannot possibly be implicit-casted to a char[], so therefore int[] foo(char[] data) pure can be implicitly casted to immutable, but that might be flirting with dangerous situations. The one exception should be allocating memory, which should always qualify, even though it's not a pure function. This should compile: void main() { immutable x = foo([1, 2, 3]); } -Steve
Oct 17 2011
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.v3h06olweav7ka localhost.localdomain...That sounds like an incorrect restriction. The implicit cast to immutable should depend on whether the function being *called* qualifies, not if the function you are calling *from* qualifies.I think you've misunderstood what I'm saying. The patch I made implemented two ways to implicly convert to immutable: the result of a pure function returning immutable and a return statement inside a pure function. 1) int[] fun() { return new int[]; } immutable x = fun(); // conversion happens here 2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun(); Bearophile's example is of the second, where it definately matters what the purity of the function is.Qualifying means the return type should be mutable, and cannot be derived from the parameters without requiring casts. The easiest way to do this is to ensure the parameters are all const, immutable, or implicitly cast to immutable. You could do funky things like assume for instance an int[] cannot possibly be implicit-casted to a char[], so therefore int[] foo(char[] data) pure can be implicitly casted to immutable, but that might be flirting with dangerous situations. The one exception should be allocating memory, which should always qualify, even though it's not a pure function.This is valid, but becomes very complicated with complex return types. I doubt this will ever make it into the language. I've got the beginnings of a patch to enable a sort of 'pure expression', such as new, array.dup and array concatenation expressions. The result of a call to a const-pure function using immutable arguments can be converted to immutable, while calling it with mutable or const arguments cannot, without searching the return type for anything the arguments can implicitly convert to (or create). Eg. I can't see a great way to detect situations like this: struct S { const void* p; } S[] fun(int[] arr) { return [ S(arr.ptr) ]; } immutable x = fun([1, 2, 3]);
Oct 17 2011
Daniel Murphy:2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun(); Bearophile's example is of the second, where it definately matters what the purity of the function is.This is the enhancement request I have written days ago: http://d.puremagic.com/issues/show_bug.cgi?id=6783 Bye, bearophile
Oct 18 2011
"bearophile" <bearophileHUGS lycos.com> wrote in message news:j7jepi$prp$1 digitalmars.com...Daniel Murphy:Yes, and the problem in that report is that the function is const-pure, not strong-pure. Without checking if the return type can contain a non-immutable reference from the arguments, it is not safe to implicitly convert the result to immutable. eg. immutable(int[]) foo(in int[] x) { return x; } auto g = [1, 2, 3]; auto a = foo(g.idup); //safe auto b = foo(g); // unsafe Checking at the call site is possible, but not from inside the function. int[] foo(in int[] x) { return new int[](3); } auto g = [1, 2, 3]; immutable a = foo(g.idup); // safe immutable b = foo(g); // unsafe, and easily rejected In your example, it is safe as the argument is not returned. Allowing this in the general case requires checking (recursively) that the return type does not contain any types that any of the arguments can implicitly convert to that are non-immutable.2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun(); Bearophile's example is of the second, where it definately matters what the purity of the function is.This is the enhancement request I have written days ago: http://d.puremagic.com/issues/show_bug.cgi?id=6783 Bye, bearophile
Oct 18 2011
"Daniel Murphy" , dans le message (digitalmars.D.learn:30139), a écrit :"bearophile" <bearophileHUGS lycos.com> wrote in message news:j7jepi$prp$1 digitalmars.com...What is the rule ? The result of a pure function can be cast to immutable if the arguments are immutable. That requires specific checking by the compiler. The real type of the argument prior to the conversion to the argument type has to be checked. in, scope, or inout arguments are supposed to solve the problem with function site checking: without call-site checking, which are IMO a rather bad idea. The result of pure int[] foo(in int[] x); is castable to immutable, since elements of x are not supposed to escape the function. The result of pure int[] foo(const int[] x); is not, because the value return by foo may be elements of x.Daniel Murphy:Yes, and the problem in that report is that the function is const-pure, not strong-pure. Without checking if the return type can contain a non-immutable reference from the arguments, it is not safe to implicitly convert the result to immutable. eg. immutable(int[]) foo(in int[] x) { return x; } auto g = [1, 2, 3]; auto a = foo(g.idup); //safe auto b = foo(g); // unsafe Checking at the call site is possible, but not from inside the function. int[] foo(in int[] x) { return new int[](3); } auto g = [1, 2, 3]; immutable a = foo(g.idup); // safe immutable b = foo(g); // unsafe, and easily rejected In your example, it is safe as the argument is not returned. Allowing this in the general case requires checking (recursively) that the return type does not contain any types that any of the arguments can implicitly convert to that are non-immutable.2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun(); Bearophile's example is of the second, where it definately matters what the purity of the function is.This is the enhancement request I have written days ago: http://d.puremagic.com/issues/show_bug.cgi?id=6783 Bye, bearophile
Oct 21 2011
On Fri, 21 Oct 2011 11:20:01 -0400, Christophe = <travert phare.normalesup.org> wrote:"Daniel Murphy" , dans le message (digitalmars.D.learn:30139), a =C3=A9=crit :="bearophile" <bearophileHUGS lycos.com> wrote in message news:j7jepi$prp$1 digitalmars.com...Daniel Murphy:2) immutable(int[]) fun() { return new int[]; } // conversion happens ==here immutable x =3D fun(); Bearophile's example is of the second, where it definately matters =e, =Yes, and the problem in that report is that the function is const-pur=what the purity of the function is.This is the enhancement request I have written days ago: http://d.puremagic.com/issues/show_bug.cgi?id=3D6783 Bye, bearophilenot strong-pure. Without checking if the return type can contain a non-immutable =oreference from the arguments, it is not safe to implicitly convert the result t=on.immutable. eg. immutable(int[]) foo(in int[] x) { return x; } auto g =3D [1, 2, 3]; auto a =3D foo(g.idup); //safe auto b =3D foo(g); // unsafe Checking at the call site is possible, but not from inside the functi=g =int[] foo(in int[] x) { return new int[](3); } auto g =3D [1, 2, 3]; immutable a =3D foo(g.idup); // safe immutable b =3D foo(g); // unsafe, and easily rejected In your example, it is safe as the argument is not returned. Allowin=ypethis in the general case requires checking (recursively) that the return t=does not contain any types that any of the arguments can implicitly =The theoretical rule should be, if it can be proven (except for the case= = where a cast is used) the result is not a subset of the input, then the = = result can be implicitly cast to immutable. The actual rule may be more conservative, since it may be difficult to = prove it.convert to that are non-immutable.What is the rule ?The result of pure int[] foo(in int[] x); is castable to immutable, since elements of x are not supposed to esca=pethe function. The result of pure int[] foo(const int[] x); is not, because the value return by foo may be elements of x.Only via cast. How does foo legally change const int[] data to int[] da= ta = without a cast? Note that the two functions you wrote are equivalent, since in translate= s = to "const scope" and scope does nothing to array parameters. -Steve
Oct 24 2011
"Steven Schveighoffer" , dans le message (digitalmars.D.learn:30255), a écrit :On Fri, 21 Oct 2011 11:20:01 -0400, Christophe <travert phare.normalesup.org> wrote:OK, it must be proven from the signature of the function alone, and not from the function body."Daniel Murphy" , dans le message (digitalmars.D.learn:30139), a écrit :The theoretical rule should be, if it can be proven (except for the case where a cast is used) the result is not a subset of the input, then the result can be implicitly cast to immutable. The actual rule may be more conservative, since it may be difficult to prove it."bearophile" <bearophileHUGS lycos.com> wrote in message news:j7jepi$prp$1 digitalmars.com...What is the rule ?Daniel Murphy:Yes, and the problem in that report is that the function is const-pure, not strong-pure. Without checking if the return type can contain a non-immutable reference from the arguments, it is not safe to implicitly convert the result to immutable. eg. immutable(int[]) foo(in int[] x) { return x; } auto g = [1, 2, 3]; auto a = foo(g.idup); //safe auto b = foo(g); // unsafe Checking at the call site is possible, but not from inside the function. int[] foo(in int[] x) { return new int[](3); } auto g = [1, 2, 3]; immutable a = foo(g.idup); // safe immutable b = foo(g); // unsafe, and easily rejected In your example, it is safe as the argument is not returned. Allowing this in the general case requires checking (recursively) that the return type does not contain any types that any of the arguments can implicitly convert to that are non-immutable.2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun(); Bearophile's example is of the second, where it definately matters what the purity of the function is.This is the enhancement request I have written days ago: http://d.puremagic.com/issues/show_bug.cgi?id=6783 Bye, bearophileI meant: pure const(int)[] foo(const/in int[] x); But I thought scope was transitive like const, so it had effect on arrays. I find it pretty useless like that. A transitive scope could be very useful for purity checking and memory management optimisations. It would be useful for implicit casting to immutable too, even in no pure function. I may write about that later in another thread.The result of pure int[] foo(in int[] x); is castable to immutable, since elements of x are not supposed to escape the function. The result of pure int[] foo(const int[] x); is not, because the value return by foo may be elements of x.Only via cast. How does foo legally change const int[] data to int[] data without a cast? Note that the two functions you wrote are equivalent, since in translates to "const scope" and scope does nothing to array parameters.
Oct 27 2011
On Tue, 18 Oct 2011 02:40:12 -0400, Daniel Murphy <yebblies nospamgmail.com> wrote:"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.v3h06olweav7ka localhost.localdomain...Neither of those is relevant, since they do not contain parameters (I'm assuming you meant them both to be pure).That sounds like an incorrect restriction. The implicit cast to immutable should depend on whether the function being *called* qualifies, not if the function you are calling *from* qualifies.I think you've misunderstood what I'm saying. The patch I made implemented two ways to implicly convert to immutable: the result of a pure function returning immutable and a return statement inside a pure function. 1) int[] fun() { return new int[]; } immutable x = fun(); // conversion happens here 2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun();No, it's not complicated, at least in my view. The rules are: 1. if the pure function parameters are only immutable or implicitly-convertible-to-immutable, the result is safe to cast to immutable, regardless of what happens inside the function, or the type of the result. 2. if the pure function parameters contain any mutable data that is mutable and *not* implicitly convertible to mutable, and the result is only safe to cast to immutable if it can already implicitly cast to immutable. 3. if the pure function parameters are implicitly castible to immutable, immutable, or are const, then: a) if the return type is implicitly castable to immutable, obviously it can be cast. b) if the return type is not implicitly castable to immutable, but contains only mutable references, then it's implicitly castable to immutable. c) otherwise, it cannot be implicitly cast. You do not need the function body to determine this, and the decision should be made by the compiler at the call site. Your case 2 where the conversion happens at the return statement is already covered.Qualifying means the return type should be mutable, and cannot be derived from the parameters without requiring casts. The easiest way to do this is to ensure the parameters are all const, immutable, or implicitly cast to immutable. You could do funky things like assume for instance an int[] cannot possibly be implicit-casted to a char[], so therefore int[] foo(char[] data) pure can be implicitly casted to immutable, but that might be flirting with dangerous situations. The one exception should be allocating memory, which should always qualify, even though it's not a pure function.This is valid, but becomes very complicated with complex return types. I doubt this will ever make it into the language.I've got the beginnings of a patch to enable a sort of 'pure expression', such as new, array.dup and array concatenation expressions. The result of a call to a const-pure function using immutable arguments can be converted to immutable, while calling it with mutable or const arguments cannot, without searching the return type for anything the arguments can implicitly convert to (or create). Eg. I can't see a great way to detect situations like this: struct S { const void* p; }This struct could only be cast to immutable under my rule 1 above. It does not implicitly cast to immutable.S[] fun(int[] arr) { return [ S(arr.ptr) ]; } immutable x = fun([1, 2, 3]);Invalid. arr is not implicitly castable to immutable and is mutable, so the result must already be implicitly castable (which it is not). This falls under rule 2 above, and fails the test. -Steve
Oct 19 2011
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.v3lug2q2eav7ka localhost.localdomain...On Tue, 18 Oct 2011 02:40:12 -0400, Daniel Murphy <yebblies nospamgmail.com> wrote:Yeah, they were supposed to be pure. I was just demonstrating that conversion happens at the return statement, or the call site, but only currently for strongly pure functions."Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.v3h06olweav7ka localhost.localdomain...Neither of those is relevant, since they do not contain parameters (I'm assuming you meant them both to be pure).That sounds like an incorrect restriction. The implicit cast to immutable should depend on whether the function being *called* qualifies, not if the function you are calling *from* qualifies.I think you've misunderstood what I'm saying. The patch I made implemented two ways to implicly convert to immutable: the result of a pure function returning immutable and a return statement inside a pure function. 1) int[] fun() { return new int[]; } immutable x = fun(); // conversion happens here 2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun();Ok, I think I meant to make fun pure and fun's parameter 'in', so it would fall under rule 3 but be rejected by 3b as it contains a const member. It's not always simple to determine if an aggregate contains non-mutable members. An example would be a class when you only have a base class reference. Another problem (which we're already seeing with the existing conversions) is that when you screw it up the conversion fails, but doesn't give you any hint as to why it failed. Making the rules more complicated is just going to make this worse.No, it's not complicated, at least in my view. The rules are: 1. if the pure function parameters are only immutable or implicitly-convertible-to-immutable, the result is safe to cast to immutable, regardless of what happens inside the function, or the type of the result. 2. if the pure function parameters contain any mutable data that is mutable and *not* implicitly convertible to mutable, and the result is only safe to cast to immutable if it can already implicitly cast to immutable. 3. if the pure function parameters are implicitly castible to immutable, immutable, or are const, then: a) if the return type is implicitly castable to immutable, obviously it can be cast. b) if the return type is not implicitly castable to immutable, but contains only mutable references, then it's implicitly castable to immutable. c) otherwise, it cannot be implicitly cast. You do not need the function body to determine this, and the decision should be made by the compiler at the call site. Your case 2 where the conversion happens at the return statement is already covered.Qualifying means the return type should be mutable, and cannot be derived from the parameters without requiring casts. The easiest way to do this is to ensure the parameters are all const, immutable, or implicitly cast to immutable. You could do funky things like assume for instance an int[] cannot possibly be implicit-casted to a char[], so therefore int[] foo(char[] data) pure can be implicitly casted to immutable, but that might be flirting with dangerous situations. The one exception should be allocating memory, which should always qualify, even though it's not a pure function.This is valid, but becomes very complicated with complex return types. I doubt this will ever make it into the language.I've got the beginnings of a patch to enable a sort of 'pure expression', such as new, array.dup and array concatenation expressions. The result of a call to a const-pure function using immutable arguments can be converted to immutable, while calling it with mutable or const arguments cannot, without searching the return type for anything the arguments can implicitly convert to (or create). Eg. I can't see a great way to detect situations like this: struct S { const void* p; }This struct could only be cast to immutable under my rule 1 above. It does not implicitly cast to immutable.S[] fun(int[] arr) { return [ S(arr.ptr) ]; } immutable x = fun([1, 2, 3]);Invalid. arr is not implicitly castable to immutable and is mutable, so the result must already be implicitly castable (which it is not). This falls under rule 2 above, and fails the test. -Steve
Oct 19 2011
On Wed, 19 Oct 2011 21:39:47 -0400, Daniel Murphy <yebblies nospamgmail.com> wrote:"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.v3lug2q2eav7ka localhost.localdomain...I had not thought about classes (or interfaces), I was only thinking of concrete types. I think in the case of classes, all parameters with classes must be marked as immutable to have an implicit cast of the result to immutable (i.e. fall under rule 1). In reality, the rules I specify are enough, but they simply aren't explicit about how classes make it impossible to determine if any const members are aboard. The same goes for void *, which could point to a type which has const members. All cases where classes or void * pointers are involved must fall under rule 1, since you cannot determine whether such types are transitively mutable.On Tue, 18 Oct 2011 02:40:12 -0400, Daniel Murphy <yebblies nospamgmail.com> wrote:Yeah, they were supposed to be pure. I was just demonstrating that conversion happens at the return statement, or the call site, but only currently for strongly pure functions."Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.v3h06olweav7ka localhost.localdomain...Neither of those is relevant, since they do not contain parameters (I'm assuming you meant them both to be pure).That sounds like an incorrect restriction. The implicit cast to immutable should depend on whether the function being *called* qualifies, not if the function you are calling *from* qualifies.I think you've misunderstood what I'm saying. The patch I made implemented two ways to implicly convert to immutable: the result of a pure function returning immutable and a return statement inside a pure function. 1) int[] fun() { return new int[]; } immutable x = fun(); // conversion happens here 2) immutable(int[]) fun() { return new int[]; } // conversion happens here immutable x = fun();Ok, I think I meant to make fun pure and fun's parameter 'in', so it would fall under rule 3 but be rejected by 3b as it contains a const member. It's not always simple to determine if an aggregate contains non-mutable members. An example would be a class when you only have a base class reference.No, it's not complicated, at least in my view. The rules are: 1. if the pure function parameters are only immutable or implicitly-convertible-to-immutable, the result is safe to cast to immutable, regardless of what happens inside the function, or the type of the result. 2. if the pure function parameters contain any mutable data that is mutable and *not* implicitly convertible to mutable, and the result is only safe to cast to immutable if it can already implicitly cast to immutable. 3. if the pure function parameters are implicitly castible to immutable, immutable, or are const, then: a) if the return type is implicitly castable to immutable, obviously it can be cast. b) if the return type is not implicitly castable to immutable, but contains only mutable references, then it's implicitly castable to immutable. c) otherwise, it cannot be implicitly cast. You do not need the function body to determine this, and the decision should be made by the compiler at the call site. Your case 2 where the conversion happens at the return statement is already covered.Qualifying means the return type should be mutable, and cannot be derived from the parameters without requiring casts. The easiest way to do this is to ensure the parameters are all const, immutable, or implicitly cast to immutable. You could do funky things like assume for instance an int[] cannot possibly be implicit-casted to a char[], so therefore int[] foo(char[] data) pure can be implicitly casted to immutable, but that might be flirting with dangerous situations. The one exception should be allocating memory, which should always qualify, even though it's not a pure function.This is valid, but becomes very complicated with complex return types. I doubt this will ever make it into the language.I've got the beginnings of a patch to enable a sort of 'pure expression', such as new, array.dup and array concatenation expressions. The result of a call to a const-pure function using immutable arguments can be converted to immutable, while calling it with mutable or const arguments cannot, without searching the return type for anything the arguments can implicitly convert to (or create). Eg. I can't see a great way to detect situations like this: struct S { const void* p; }This struct could only be cast to immutable under my rule 1 above. It does not implicitly cast to immutable.S[] fun(int[] arr) { return [ S(arr.ptr) ]; } immutable x = fun([1, 2, 3]);Invalid. arr is not implicitly castable to immutable and is mutable, so the result must already be implicitly castable (which it is not). This falls under rule 2 above, and fails the test. -SteveAnother problem (which we're already seeing with the existing conversions) is that when you screw it up the conversion fails, but doesn't give you any hint as to why it failed. Making the rules more complicated is just going to make this worse.By letting the caller choose the return type, you are eliminating code duplication. Consider the function: int[] repeat(in int[] x, uint ntimes) pure { int[] result; result.reserve(x.length * ntimes); foreach(uint i; 0..ntimes) result ~= x; return result; } Under my rules, you need only this one function to handle all 9 cases of converting between constancies of int int[] => int[] int[] => const(int)[] int[] => immutable(int)[] const(int)[] => int[] ... I think this is worth having. In contrast, what we have now is quite limited, and inconsistent. A long-standing request I've had is this: http://d.puremagic.com/issues/show_bug.cgi?id=1654 I think this new feature of implicit immutable casting via pure is the key. The more we make immutable data safer and easier to create and convert, the better off D (and pure functions) will be. -Steve
Oct 19 2011