www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Generic collection/element function signatures in D2 versus D1

reply "Nick Sabalausky" <a a.a> writes:
In D1 I did this sort of thing a fair amount:

void foo(T)(T[] collection, T elem)
{
    // Blah, whatever
}

Worked for any of the string types, worked for any array, or anything with 
the appropriate opIndexes, and for all I know there may be some improvement 
that could still be made. But of course, in D2 strings have that extra 
immutable part that mucks up the above for strings (and then there's 
ranges), so: Is there a typical generally-best way in D2 to declare a 
function signature for operating on collections and elements? I know it 
would involve using the standard range interfaces in the body and choosing 
the most restrictive range type that gets the job done, and I'm fine with 
all that, but is there a good example of a typical "best-practice" 
generic-function signature in D2?

-------------------------------
Not sent from an iPhone.
Sep 04 2010
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:i5su5e$23mk$1 digitalmars.com...
 In D1 I did this sort of thing a fair amount:

 void foo(T)(T[] collection, T elem)
 {
    // Blah, whatever
 }

 Worked for any of the string types, worked for any array, or anything with 
 the appropriate opIndexes, and for all I know there may be some 
 improvement that could still be made. But of course, in D2 strings have 
 that extra immutable part that mucks up the above for strings (and then 
 there's ranges), so: Is there a typical generally-best way in D2 to 
 declare a function signature for operating on collections and elements? I 
 know it would involve using the standard range interfaces in the body and 
 choosing the most restrictive range type that gets the job done, and I'm 
 fine with all that, but is there a good example of a typical 
 "best-practice" generic-function signature in D2?
Oh, also, and perhaps more importantly (I forgot, this was my main original reason for even posting the question): What would be the *right* D2 version of the above code that *didn't* bother with ranges, and just stuck with arrays and strings? Sometimes I need to do something in CTFE and using ranges leads to using "std.algorithm", and CTFE still tends to choke on a lot of "std.algorithm".
Sep 04 2010
parent reply Jacob Carlborg <doob me.com> writes:
On 2010-09-04 10:02, Nick Sabalausky wrote:
 "Nick Sabalausky"<a a.a>  wrote in message
 news:i5su5e$23mk$1 digitalmars.com...
 In D1 I did this sort of thing a fair amount:

 void foo(T)(T[] collection, T elem)
 {
     // Blah, whatever
 }

 Worked for any of the string types, worked for any array, or anything with
 the appropriate opIndexes, and for all I know there may be some
 improvement that could still be made. But of course, in D2 strings have
 that extra immutable part that mucks up the above for strings (and then
 there's ranges), so: Is there a typical generally-best way in D2 to
 declare a function signature for operating on collections and elements? I
 know it would involve using the standard range interfaces in the body and
 choosing the most restrictive range type that gets the job done, and I'm
 fine with all that, but is there a good example of a typical
 "best-practice" generic-function signature in D2?
Oh, also, and perhaps more importantly (I forgot, this was my main original reason for even posting the question): What would be the *right* D2 version of the above code that *didn't* bother with ranges, and just stuck with arrays and strings? Sometimes I need to do something in CTFE and using ranges leads to using "std.algorithm", and CTFE still tends to choke on a lot of "std.algorithm".
If you're not going to modify the content of the array I think this will work: void foo (T) (const(T)[] collection, T elem) {} This will allow both mutable, immutable and const arrays. But it will not let you modify the array like this: collection[3] = 'a'; -- /Jacob Carlborg
Sep 04 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Jacob Carlborg" <doob me.com> wrote in message 
news:i5t61q$2j76$1 digitalmars.com...
 If you're not going to modify the content of the array I think this will 
 work:

 void foo (T) (const(T)[] collection, T elem) {}

 This will allow both mutable, immutable and const arrays. But it will not 
 let you modify the array like this:

 collection[3] = 'a';
On DMD 2.048, This isn't working for me: ----------------------------------------- void foo(T)(const(T)[] coll, T elem) { } void main() { string x = "hello"; foo(x, x[1]); } ----------------------------------------- Result: ----------------------------------------- testStringAndChar.d(8): Error: template testStringAndChar.foo(T) does not match any function template declaration testStringAndChar.d(8): Error: template testStringAndChar.foo(T) cannot deduce template function from argument types !()(string,immutable(char)) ----------------------------------------- I figured that was just because 'const(immutable(T))[]' doesn't make much sence, so I tried this and got the exact same error messages: ----------------------------------------- import std.traits; void foo(T)(const(Unqual!T)[] coll, T elem) { } void main() { string x = "hello"; foo(x, x[1]); } ----------------------------------------- It seems to be a problem with IFTI, because this does work with both versions: foo!char(x, x[1]); Kind of a pain.
Sep 11 2010
parent Brad Roberts <braddr puremagic.com> writes:
On 9/11/2010 9:32 PM, Nick Sabalausky wrote:
 "Jacob Carlborg" <doob me.com> wrote in message 
 news:i5t61q$2j76$1 digitalmars.com...
 If you're not going to modify the content of the array I think this will 
 work:

 void foo (T) (const(T)[] collection, T elem) {}

 This will allow both mutable, immutable and const arrays. But it will not 
 let you modify the array like this:

 collection[3] = 'a';
On DMD 2.048, This isn't working for me: ----------------------------------------- void foo(T)(const(T)[] coll, T elem) { } void main() { string x = "hello"; foo(x, x[1]); } ----------------------------------------- Result: ----------------------------------------- testStringAndChar.d(8): Error: template testStringAndChar.foo(T) does not match any function template declaration testStringAndChar.d(8): Error: template testStringAndChar.foo(T) cannot deduce template function from argument types !()(string,immutable(char)) ----------------------------------------- I figured that was just because 'const(immutable(T))[]' doesn't make much sence, so I tried this and got the exact same error messages: ----------------------------------------- import std.traits; void foo(T)(const(Unqual!T)[] coll, T elem) { } void main() { string x = "hello"; foo(x, x[1]); } ----------------------------------------- It seems to be a problem with IFTI, because this does work with both versions: foo!char(x, x[1]); Kind of a pain.
http://d.puremagic.com/issues/show_bug.cgi?id=2594
Sep 11 2010
prev sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Saturday 04 September 2010 00:57:48 Nick Sabalausky wrote:
 In D1 I did this sort of thing a fair amount:
 
 void foo(T)(T[] collection, T elem)
 {
     // Blah, whatever
 }
 
 Worked for any of the string types, worked for any array, or anything with
 the appropriate opIndexes, and for all I know there may be some improvement
 that could still be made. But of course, in D2 strings have that extra
 immutable part that mucks up the above for strings (and then there's
 ranges), so: Is there a typical generally-best way in D2 to declare a
 function signature for operating on collections and elements? I know it
 would involve using the standard range interfaces in the body and choosing
 the most restrictive range type that gets the job done, and I'm fine with
 all that, but is there a good example of a typical "best-practice"
 generic-function signature in D2?
 
 -------------------------------
 Not sent from an iPhone.
Okay, here's a shot at it: import std.algorithm; import std.array; import std.container; import std.stdio; import std.traits; void foo(T, U)(T collection, U elem) if(is(U : Unqual!(typeof(collection[].front)))) { if(elem == collection.front) writefln("%s == %s", elem, collection.front); else writefln("%s != %s", elem, collection.front); } void bar(R, U)(R range, U elem) if(is(U : Unqual!(typeof(range.front)))) { if(elem == range.front) writefln("%s == %s", elem, range.front); else writefln("%s != %s", elem, range.front); } void main() { dstring a = "hello world"; foo(a, 'h'); foo(a, 'g'); bar(a, 'h'); bar(a, 'g'); writeln(); Array!int b; b.insert(1); b.insert(2); b.insert(3); foo(b, 1); foo(b, 2); bar(b, 1); bar(b, 2); writeln(); SList!int c; c.insert(3); c.insert(2); c.insert(1); foo(c, 1); foo(c, 2); bar(c, 1); bar(c, 2); writeln(); auto d = find(c[], 2); bar(d, 1); bar(d, 2); } foo() takes a container type where you can get a range to the whole thing with a slice, and bar() works on ranges. However, it looks like all of the containers in std.container currently implement front(), so both foo() and bar() work on them. Of course, if you doing stuff that isn't on a range, then bar() wouldn't work, and foo() won't work on ranges. So, which you want probably depends on what you're trying to do. A function like bar will work on more but will be restricted to range-base operations only. And depending on what you do in a function like bar(), you might need more template constraints to constrain the type of range. I haven't tried any of this with CTFE, but the function signatures should work just fine with it. Whether you can use CTFE should therefore be a question of what you try to do in the function. In any case, I think that Unqual is the secret sauce that you're looking for here. - Jonathan M Davis
Sep 04 2010
parent reply BLS <windevguy hotmail.de> writes:
On 05/09/2010 02:16, Jonathan M Davis wrote:
 void foo(T)(T[] collection, T elem)
  {
       // Blah, whatever
  }
I am curious, how this will look and feel once inout is working ? inout void foo(T)(inout(T)[] collection, inout T elem) { // Blah, whatever} }
Sep 05 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy hotmail.de> wrote:

 On 05/09/2010 02:16, Jonathan M Davis wrote:
 void foo(T)(T[] collection, T elem)
  {
       // Blah, whatever
  }
I am curious, how this will look and feel once inout is working ? inout void foo(T)(inout(T)[] collection, inout T elem) { // Blah, whatever} }
inout void doesn't make any sense. You can't have a const void or immutable void. Now, if foo is a member function, then inout applies to the "this" pointer, but even then, you need a return type other than void for inout to be used. -Steve
Sep 07 2010
parent reply Jacob Carlborg <doob me.com> writes:
On 2010-09-07 14:49, Steven Schveighoffer wrote:
 On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy hotmail.de> wrote:

 On 05/09/2010 02:16, Jonathan M Davis wrote:
 void foo(T)(T[] collection, T elem)
 {
 // Blah, whatever
 }
I am curious, how this will look and feel once inout is working ? inout void foo(T)(inout(T)[] collection, inout T elem) { // Blah, whatever} }
inout void doesn't make any sense. You can't have a const void or immutable void. Now, if foo is a member function, then inout applies to the "this" pointer, but even then, you need a return type other than void for inout to be used. -Steve
inout is only used when you want to return the same constness (mutable, const, immutable) as you passed in to the function. If you don't want that, or don't want to return anything then const(T)[] is what you want. It will accept mutable, const and immutable. -- /Jacob Carlborg
Sep 07 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 07 Sep 2010 08:56:15 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2010-09-07 14:49, Steven Schveighoffer wrote:
 On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy hotmail.de> wrote:

 On 05/09/2010 02:16, Jonathan M Davis wrote:
 void foo(T)(T[] collection, T elem)
 {
 // Blah, whatever
 }
I am curious, how this will look and feel once inout is working ? inout void foo(T)(inout(T)[] collection, inout T elem) { // Blah, whatever} }
inout void doesn't make any sense. You can't have a const void or immutable void. Now, if foo is a member function, then inout applies to the "this" pointer, but even then, you need a return type other than void for inout to be used. -Steve
inout is only used when you want to return the same constness (mutable, const, immutable) as you passed in to the function. If you don't want that, or don't want to return anything then const(T)[] is what you want. It will accept mutable, const and immutable.
Yes, exactly. This is why inout functions cannot return void. -Steve
Sep 07 2010
parent reply Pelle <pelle.mansson gmail.com> writes:
On 09/07/2010 03:15 PM, Steven Schveighoffer wrote:
 On Tue, 07 Sep 2010 08:56:15 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2010-09-07 14:49, Steven Schveighoffer wrote:
 On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy hotmail.de> wrote:

 On 05/09/2010 02:16, Jonathan M Davis wrote:
 void foo(T)(T[] collection, T elem)
 {
 // Blah, whatever
 }
I am curious, how this will look and feel once inout is working ? inout void foo(T)(inout(T)[] collection, inout T elem) { // Blah, whatever} }
inout void doesn't make any sense. You can't have a const void or immutable void. Now, if foo is a member function, then inout applies to the "this" pointer, but even then, you need a return type other than void for inout to be used. -Steve
inout is only used when you want to return the same constness (mutable, const, immutable) as you passed in to the function. If you don't want that, or don't want to return anything then const(T)[] is what you want. It will accept mutable, const and immutable.
Yes, exactly. This is why inout functions cannot return void. -Steve
Hmm. class C { void foo(void delegate(inout(C)) f) inout { f(this); } } Am I missing something?
Sep 07 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 07 Sep 2010 09:28:18 -0400, Pelle <pelle.mansson gmail.com> wrote:

 On 09/07/2010 03:15 PM, Steven Schveighoffer wrote:
 On Tue, 07 Sep 2010 08:56:15 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2010-09-07 14:49, Steven Schveighoffer wrote:
 On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy hotmail.de> wrote:

 On 05/09/2010 02:16, Jonathan M Davis wrote:
 void foo(T)(T[] collection, T elem)
 {
 // Blah, whatever
 }
I am curious, how this will look and feel once inout is working ? inout void foo(T)(inout(T)[] collection, inout T elem) { // Blah, whatever} }
inout void doesn't make any sense. You can't have a const void or immutable void. Now, if foo is a member function, then inout applies to the "this" pointer, but even then, you need a return type other than void for inout to be used. -Steve
inout is only used when you want to return the same constness (mutable, const, immutable) as you passed in to the function. If you don't want that, or don't want to return anything then const(T)[] is what you want. It will accept mutable, const and immutable.
Yes, exactly. This is why inout functions cannot return void. -Steve
Hmm. class C { void foo(void delegate(inout(C)) f) inout { f(this); } } Am I missing something?
Yes, a valid return. Your function should be: void foo(void delegate(const(C) f) const It helps to understand that inout/const/immutable has NOTHING to do with code generation, it only has to do with limiting what compiles. For this reason, an inout function is compiled once, and works on all three constancies (4 if you have a nested inout function). For the entire function any inout variable is treated as a non-changeable value, just like const. Then when you return, it's converted at the call site back to the constancy with which it was called. If the return value is void, then there's nothing to convert, and no reason to use inout over const. I'll repeat -- there is no benefit to inout if you are not returning anything. -Steve
Sep 07 2010
parent reply Pelle <pelle.mansson gmail.com> writes:
On 09/07/2010 04:33 PM, Steven Schveighoffer wrote:
 Yes, a valid return. Your function should be:

 void foo(void delegate(const(C) f) const

 It helps to understand that inout/const/immutable has NOTHING to do with
 code generation, it only has to do with limiting what compiles. For this
 reason, an inout function is compiled once, and works on all three
 constancies (4 if you have a nested inout function). For the entire
 function any inout variable is treated as a non-changeable value, just
 like const. Then when you return, it's converted at the call site back
 to the constancy with which it was called. If the return value is void,
 then there's nothing to convert, and no reason to use inout over const.

 I'll repeat -- there is no benefit to inout if you are not returning
 anything.

 -Steve
That's not an equivalent function signature. Or maybe it is, but look at this (sorry it's so long): class C { int x; this(int y) { x = y; } inout(int*) foo() inout { return &x; } void bar(void delegate(int*) f) { f(&x); } void bar(void delegate(const(int*)) f) const { f(&x); } void bar(void delegate(immutable(int*)) f) immutable { f(&x); } } void main() { immutable(int)* wah; void wahwah(immutable(int*) x) { wah = x; } auto c = new immutable(C)(10); wahwah(c.foo); // why is this privilegied with inout c.bar(&wahwah); // and this not? writeln(*wah); } Can't use void delegate(const(int*)) there.
Sep 07 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 07 Sep 2010 11:37:20 -0400, Pelle <pelle.mansson gmail.com> wrote:

 On 09/07/2010 04:33 PM, Steven Schveighoffer wrote:
 Yes, a valid return. Your function should be:

 void foo(void delegate(const(C) f) const

 It helps to understand that inout/const/immutable has NOTHING to do with
 code generation, it only has to do with limiting what compiles. For this
 reason, an inout function is compiled once, and works on all three
 constancies (4 if you have a nested inout function). For the entire
 function any inout variable is treated as a non-changeable value, just
 like const. Then when you return, it's converted at the call site back
 to the constancy with which it was called. If the return value is void,
 then there's nothing to convert, and no reason to use inout over const.

 I'll repeat -- there is no benefit to inout if you are not returning
 anything.

 -Steve
That's not an equivalent function signature. Or maybe it is, but look at this (sorry it's so long): class C { int x; this(int y) { x = y; } inout(int*) foo() inout { return &x; } void bar(void delegate(int*) f) { f(&x); } void bar(void delegate(const(int*)) f) const { f(&x); } void bar(void delegate(immutable(int*)) f) immutable { f(&x); } } void main() { immutable(int)* wah; void wahwah(immutable(int*) x) { wah = x; } auto c = new immutable(C)(10); wahwah(c.foo); // why is this privilegied with inout c.bar(&wahwah); // and this not? writeln(*wah); } Can't use void delegate(const(int*)) there.
Thanks for clarifying, I didn't quite understand the usage before. This is a limitation of inout's design. Technically inout requires a single inout output, and can have multiple inout inputs. Your example matches that description, so in theory it's possible. But to simplify things, a function's only inout output must be on the return value. So things like void fn(inout int* x, out inout(int) y) don't qualify either. IMO there is a whole host of implicit delegate casting that should be possible, but isn't, including delegate contravariance. However, let's get inout working as it's currently designed before we go relaxing the requirements. I'm not a compiler/language designer, so I'm unsure if what you want has any pitfalls. -Steve
Sep 07 2010
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 07 Sep 2010 14:06:58 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Tue, 07 Sep 2010 11:37:20 -0400, Pelle <pelle.mansson gmail.com>  
 wrote:

 On 09/07/2010 04:33 PM, Steven Schveighoffer wrote:
 Yes, a valid return. Your function should be:

 void foo(void delegate(const(C) f) const

 It helps to understand that inout/const/immutable has NOTHING to do  
 with
 code generation, it only has to do with limiting what compiles. For  
 this
 reason, an inout function is compiled once, and works on all three
 constancies (4 if you have a nested inout function). For the entire
 function any inout variable is treated as a non-changeable value, just
 like const. Then when you return, it's converted at the call site back
 to the constancy with which it was called. If the return value is void,
 then there's nothing to convert, and no reason to use inout over const.

 I'll repeat -- there is no benefit to inout if you are not returning
 anything.

 -Steve
That's not an equivalent function signature. Or maybe it is, but look at this (sorry it's so long): class C { int x; this(int y) { x = y; } inout(int*) foo() inout { return &x; } void bar(void delegate(int*) f) { f(&x); } void bar(void delegate(const(int*)) f) const { f(&x); } void bar(void delegate(immutable(int*)) f) immutable { f(&x); } } void main() { immutable(int)* wah; void wahwah(immutable(int*) x) { wah = x; } auto c = new immutable(C)(10); wahwah(c.foo); // why is this privilegied with inout c.bar(&wahwah); // and this not? writeln(*wah); } Can't use void delegate(const(int*)) there.
Thanks for clarifying, I didn't quite understand the usage before. This is a limitation of inout's design. Technically inout requires a single inout output, and can have multiple inout inputs. Your example matches that description, so in theory it's possible.
I realized last night that this won't work. Simple reason -- during an inout function, the function promises to treat the arguments as if they were const. If your class instance was mutable, this would not be true, e.g.: class C { int x; void bar(void delegate(inout(int)* f) inout { f(&x); } } void main() { auto c = new C; void dg(int *f) {*f = 10;} c.bar(&dg); // modifies c, even though the function is marked as inout } -Steve
Sep 08 2010
parent reply Pelle <pelle.mansson gmail.com> writes:
On 09/08/2010 02:24 PM, Steven Schveighoffer wrote:
 On Tue, 07 Sep 2010 14:06:58 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 On Tue, 07 Sep 2010 11:37:20 -0400, Pelle <pelle.mansson gmail.com>
 wrote:

 On 09/07/2010 04:33 PM, Steven Schveighoffer wrote:
 Yes, a valid return. Your function should be:

 void foo(void delegate(const(C) f) const

 It helps to understand that inout/const/immutable has NOTHING to do
 with
 code generation, it only has to do with limiting what compiles. For
 this
 reason, an inout function is compiled once, and works on all three
 constancies (4 if you have a nested inout function). For the entire
 function any inout variable is treated as a non-changeable value, just
 like const. Then when you return, it's converted at the call site back
 to the constancy with which it was called. If the return value is void,
 then there's nothing to convert, and no reason to use inout over const.

 I'll repeat -- there is no benefit to inout if you are not returning
 anything.

 -Steve
That's not an equivalent function signature. Or maybe it is, but look at this (sorry it's so long): class C { int x; this(int y) { x = y; } inout(int*) foo() inout { return &x; } void bar(void delegate(int*) f) { f(&x); } void bar(void delegate(const(int*)) f) const { f(&x); } void bar(void delegate(immutable(int*)) f) immutable { f(&x); } } void main() { immutable(int)* wah; void wahwah(immutable(int*) x) { wah = x; } auto c = new immutable(C)(10); wahwah(c.foo); // why is this privilegied with inout c.bar(&wahwah); // and this not? writeln(*wah); } Can't use void delegate(const(int*)) there.
Thanks for clarifying, I didn't quite understand the usage before. This is a limitation of inout's design. Technically inout requires a single inout output, and can have multiple inout inputs. Your example matches that description, so in theory it's possible.
I realized last night that this won't work. Simple reason -- during an inout function, the function promises to treat the arguments as if they were const. If your class instance was mutable, this would not be true, e.g.: class C { int x; void bar(void delegate(inout(int)* f) inout { f(&x); } } void main() { auto c = new C; void dg(int *f) {*f = 10;} c.bar(&dg); // modifies c, even though the function is marked as inout } -Steve
Well, inout was conceived as a counter to where you need to write the exact same function for every type of constness, was it not? :-)
Sep 08 2010
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 08 Sep 2010 12:38:44 -0400, Pelle <pelle.mansson gmail.com> wrote:

 On 09/08/2010 02:24 PM, Steven Schveighoffer wrote:
 On Tue, 07 Sep 2010 14:06:58 -0400, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:

 On Tue, 07 Sep 2010 11:37:20 -0400, Pelle <pelle.mansson gmail.com>
 wrote:

 On 09/07/2010 04:33 PM, Steven Schveighoffer wrote:
 Yes, a valid return. Your function should be:

 void foo(void delegate(const(C) f) const

 It helps to understand that inout/const/immutable has NOTHING to do
 with
 code generation, it only has to do with limiting what compiles. For
 this
 reason, an inout function is compiled once, and works on all three
 constancies (4 if you have a nested inout function). For the entire
 function any inout variable is treated as a non-changeable value,  
 just
 like const. Then when you return, it's converted at the call site  
 back
 to the constancy with which it was called. If the return value is  
 void,
 then there's nothing to convert, and no reason to use inout over  
 const.

 I'll repeat -- there is no benefit to inout if you are not returning
 anything.

 -Steve
That's not an equivalent function signature. Or maybe it is, but look at this (sorry it's so long): class C { int x; this(int y) { x = y; } inout(int*) foo() inout { return &x; } void bar(void delegate(int*) f) { f(&x); } void bar(void delegate(const(int*)) f) const { f(&x); } void bar(void delegate(immutable(int*)) f) immutable { f(&x); } } void main() { immutable(int)* wah; void wahwah(immutable(int*) x) { wah = x; } auto c = new immutable(C)(10); wahwah(c.foo); // why is this privilegied with inout c.bar(&wahwah); // and this not? writeln(*wah); } Can't use void delegate(const(int*)) there.
Thanks for clarifying, I didn't quite understand the usage before. This is a limitation of inout's design. Technically inout requires a single inout output, and can have multiple inout inputs. Your example matches that description, so in theory it's possible.
I realized last night that this won't work. Simple reason -- during an inout function, the function promises to treat the arguments as if they were const. If your class instance was mutable, this would not be true, e.g.: class C { int x; void bar(void delegate(inout(int)* f) inout { f(&x); } } void main() { auto c = new C; void dg(int *f) {*f = 10;} c.bar(&dg); // modifies c, even though the function is marked as inout } -Steve
Well, inout was conceived as a counter to where you need to write the exact same function for every type of constness, was it not? :-)
Not exactly, it was conceived as a solution for the case where you would normally write a const function, but you don't want it to alter your const contract with the object in question. Basically, you want a function that promises not to alter the parameters, but gives you back one of your parameters or a portion of one of them in the same constancy you pass in. The classic example is a property getter. If you are not returning a portion of the input, then you can use const instead. -Steve
Sep 08 2010
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2010-09-07 17:37, Pelle wrote:
 On 09/07/2010 04:33 PM, Steven Schveighoffer wrote:
 Yes, a valid return. Your function should be:

 void foo(void delegate(const(C) f) const

 It helps to understand that inout/const/immutable has NOTHING to do with
 code generation, it only has to do with limiting what compiles. For this
 reason, an inout function is compiled once, and works on all three
 constancies (4 if you have a nested inout function). For the entire
 function any inout variable is treated as a non-changeable value, just
 like const. Then when you return, it's converted at the call site back
 to the constancy with which it was called. If the return value is void,
 then there's nothing to convert, and no reason to use inout over const.

 I'll repeat -- there is no benefit to inout if you are not returning
 anything.

 -Steve
That's not an equivalent function signature. Or maybe it is, but look at this (sorry it's so long): class C { int x; this(int y) { x = y; } inout(int*) foo() inout { return &x; } void bar(void delegate(int*) f) { f(&x); } void bar(void delegate(const(int*)) f) const { f(&x); } void bar(void delegate(immutable(int*)) f) immutable { f(&x); } } void main() { immutable(int)* wah; void wahwah(immutable(int*) x) { wah = x; } auto c = new immutable(C)(10); wahwah(c.foo); // why is this privilegied with inout c.bar(&wahwah); // and this not? writeln(*wah); } Can't use void delegate(const(int*)) there.
That won't work, you can't have inout on return of a function without having inout for a least one parameter. The compiler can't know what to resolve inout to, mutable, immutable or const. -- /Jacob Carlborg
Sep 07 2010