www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - free functions as attributes

reply Sean Kelly <sean f4.ca> writes:
Given this code:

# void attribute( char[] c ) {}
# void attribute( char c ) {}
# 
# int main()
# {
#     char[] ary;
#     ary.attribute(); // (1) works
#     ary.attribute; // (2) no property 'attribute' for type 'char[]'
#     
#     char c;
#     c.attribute(); // (3) no property 'attribute' for type 'char'
#     c.attribute; // (4) no property 'attribute' for type 'char'
#     return 0;
# }

I'd like to request some consistency.  If (1) works, then (3) should work as
well.  And ideally, all four examples should work if this syntax is to be
supported.  It seems odd that arrays are an exception in this case.


Sean
Aug 04 2004
parent reply Andy Friesen <andy ikagames.com> writes:
Sean Kelly wrote:
 Given this code:
 
 # void attribute( char[] c ) {}
 # void attribute( char c ) {}
 # 
 # int main()
 # {
 #     char[] ary;
 #     ary.attribute(); // (1) works
 #     ary.attribute; // (2) no property 'attribute' for type 'char[]'
 #     
 #     char c;
 #     c.attribute(); // (3) no property 'attribute' for type 'char'
 #     c.attribute; // (4) no property 'attribute' for type 'char'
 #     return 0;
 # }
 
 I'd like to request some consistency.  If (1) works, then (3) should work as
 well.  And ideally, all four examples should work if this syntax is to be
 supported.  It seems odd that arrays are an exception in this case.

It looks handy, but I can't help but think that it's begging to introduce non-obvious behaviour into seemingly straightforward code. I think it would be prudent to leave the rules as they are and see what happens. When work on D 2.0 starts, it can be decided whether it should be removed or extended. (or neither) I do think one small change should be made, however: This behaviour should only occur when the first argument of the function is inout. Things are just begging to get weird if a function mutates an array in some manner and is passed as an 'in' parameter under normal circumstances. Hiding it behind method-like syntax would only make it worse: you don't expect 'real' methods to reallocate the 'this' reference part-way through. :) -- andy
Aug 04 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
On Wed, 04 Aug 2004 14:19:29 -0700, Andy Friesen <andy ikagames.com> wrote:
 Sean Kelly wrote:
 Given this code:

 # void attribute( char[] c ) {}
 # void attribute( char c ) {}
 # # int main()
 # {
 #     char[] ary;
 #     ary.attribute(); // (1) works
 #     ary.attribute; // (2) no property 'attribute' for type 'char[]'
 #     #     char c;
 #     c.attribute(); // (3) no property 'attribute' for type 'char'
 #     c.attribute; // (4) no property 'attribute' for type 'char'
 #     return 0;
 # }

 I'd like to request some consistency.  If (1) works, then (3) should 
 work as
 well.  And ideally, all four examples should work if this syntax is to 
 be
 supported.  It seems odd that arrays are an exception in this case.

It looks handy, but I can't help but think that it's begging to introduce non-obvious behaviour into seemingly straightforward code. I think it would be prudent to leave the rules as they are and see what happens. When work on D 2.0 starts, it can be decided whether it should be removed or extended. (or neither) I do think one small change should be made, however: This behaviour should only occur when the first argument of the function is inout. Things are just begging to get weird if a function mutates an array in some manner and is passed as an 'in' parameter under normal circumstances. Hiding it behind method-like syntax would only make it worse: you don't expect 'real' methods to reallocate the 'this' reference part-way through. :)

If an array is passed as 'in' (the default) you cannot change the array reference, you can change the data, append to the data, change the length, etc.. the 'this' reference is the array reference, and it cannot be changed, so I don't understand what you're saying. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 04 2004
parent reply Andy Friesen <andy ikagames.com> writes:
Regan Heath wrote:

 On Wed, 04 Aug 2004 14:19:29 -0700, Andy Friesen <andy ikagames.com> wrote:
 
 Sean Kelly wrote:

 Given this code:

 # void attribute( char[] c ) {}
 # void attribute( char c ) {}
 # # int main()
 # {
 #     char[] ary;
 #     ary.attribute(); // (1) works
 #     ary.attribute; // (2) no property 'attribute' for type 'char[]'
 #     #     char c;
 #     c.attribute(); // (3) no property 'attribute' for type 'char'
 #     c.attribute; // (4) no property 'attribute' for type 'char'
 #     return 0;
 # }

 I'd like to request some consistency.  If (1) works, then (3) should 
 work as
 well.  And ideally, all four examples should work if this syntax is 
 to be
 supported.  It seems odd that arrays are an exception in this case.

It looks handy, but I can't help but think that it's begging to introduce non-obvious behaviour into seemingly straightforward code. I think it would be prudent to leave the rules as they are and see what happens. When work on D 2.0 starts, it can be decided whether it should be removed or extended. (or neither) I do think one small change should be made, however: This behaviour should only occur when the first argument of the function is inout. Things are just begging to get weird if a function mutates an array in some manner and is passed as an 'in' parameter under normal circumstances. Hiding it behind method-like syntax would only make it worse: you don't expect 'real' methods to reallocate the 'this' reference part-way through. :)

If an array is passed as 'in' (the default) you cannot change the array reference, you can change the data, append to the data, change the length, etc.. the 'this' reference is the array reference, and it cannot be changed, so I don't understand what you're saying.

Actually I'm not sure if I agree with what I wrote when I posted that, but what I meant was that, if you wrote something like this: import std.stdio; void dupe(char[] This, char[] str, int count) { for (int i = 0; i < count; i++) { This ~= str; } } int main() { char[] ni; ni.dupe("NI!", 999); // set ni to "NI!NI!NI!....." writefln(ni); return 0; } You'd be in for a surprise. The string 'ni' is not going to change, because all those concatenations are more than enough to cause D to reallocate the array. Since 'This' is not an inout parameter, the reallocation isn't reflected back to the argument passed. But, I don't think this is such a great idea anymore. This wrinkle in the language is, as far as I know, used primarily for string functions, which typically don't mutate strings in-place anyway. -- andy
Aug 04 2004
parent Regan Heath <regan netwin.co.nz> writes:
On Wed, 04 Aug 2004 16:50:53 -0700, Andy Friesen <andy ikagames.com> wrote:
 Regan Heath wrote:

 On Wed, 04 Aug 2004 14:19:29 -0700, Andy Friesen <andy ikagames.com> 
 wrote:

 Sean Kelly wrote:

 Given this code:

 # void attribute( char[] c ) {}
 # void attribute( char c ) {}
 # # int main()
 # {
 #     char[] ary;
 #     ary.attribute(); // (1) works
 #     ary.attribute; // (2) no property 'attribute' for type 'char[]'
 #     #     char c;
 #     c.attribute(); // (3) no property 'attribute' for type 'char'
 #     c.attribute; // (4) no property 'attribute' for type 'char'
 #     return 0;
 # }

 I'd like to request some consistency.  If (1) works, then (3) should 
 work as
 well.  And ideally, all four examples should work if this syntax is 
 to be
 supported.  It seems odd that arrays are an exception in this case.

It looks handy, but I can't help but think that it's begging to introduce non-obvious behaviour into seemingly straightforward code. I think it would be prudent to leave the rules as they are and see what happens. When work on D 2.0 starts, it can be decided whether it should be removed or extended. (or neither) I do think one small change should be made, however: This behaviour should only occur when the first argument of the function is inout. Things are just begging to get weird if a function mutates an array in some manner and is passed as an 'in' parameter under normal circumstances. Hiding it behind method-like syntax would only make it worse: you don't expect 'real' methods to reallocate the 'this' reference part-way through. :)

If an array is passed as 'in' (the default) you cannot change the array reference, you can change the data, append to the data, change the length, etc.. the 'this' reference is the array reference, and it cannot be changed, so I don't understand what you're saying.

Actually I'm not sure if I agree with what I wrote when I posted that, but what I meant was that, if you wrote something like this: import std.stdio; void dupe(char[] This, char[] str, int count) { for (int i = 0; i < count; i++) { This ~= str; } } int main() { char[] ni; ni.dupe("NI!", 999); // set ni to "NI!NI!NI!....." writefln(ni); return 0; } You'd be in for a surprise. The string 'ni' is not going to change, because all those concatenations are more than enough to cause D to reallocate the array. Since 'This' is not an inout parameter, the reallocation isn't reflected back to the argument passed.

I don't think it matters whether it reallocates or not, I think it's simply a matter of the original string having a length of 0 and the modified data (if not reallocated) being longer than that. You can however modify a character within the original string length and that change is reflected back to the argument passed. See my test case below.
 But, I don't think this is such a great idea anymore.  This wrinkle in 
 the language is, as far as I know, used primarily for string functions, 
 which typically don't mutate strings in-place anyway.

The current concept makes me slightly uncomfortable for no reason I can put into words. I still think 'in' should enforce 'const', and there should be a way to specify const data that an array references, which cannot be changed by any reference to that data. import std.stdio; void addOne(char[] s) { s.length = s.length+1; s[s.length-1] = 'A'; } void changeOne(char[] s) { s[0] = s[0]+1; } int main() { char[] ni = "NO!"; ni.length = 100; ni.length = 3; addOne(ni); writefln(ni); changeOne(ni); writefln(ni); return 0; } Regan. -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 04 2004