www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why is array truth tied to .ptr?

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Here's a little test program:

void main()
{
     void check(int[] l) {
         if (l) writef("%-10s","true"); else writef("%-10s","false");
         writef("%-10s", (l is null));
         writef("%-10s", (l.length==0));
         writefln;
     }

     int[] list;
     writefln("%-10s%-10s%-10s%-10s",
              " ", "is true","is null","length==0");
     writef("%-10s","initial"); check(list);
     list = new int[10];
     list = null;
     writef("%-10s","nulled"); check(list);

     list = new int[10];
     list.length = 0;
     writef("%-10s", "zeroed"); check(list);
}


and here's the table it generates:

           is true   is null   length==0
initial   false     true      true
nulled    false     true      true
zeroed    true      false     true

Question: which is the bit of information you are more likely interested 
in knowing:

a) whether the array is currently empty.
b) whether the array happens to have a buffer of some unknowable length 
allocated because of a previous history of operations on it.

If you answered a) then we think alike.

So why does the simplest check

     if(array) { ... }

tell us b) ?

In a nutshell,
    if(array)
is synonymous with
    if(array.ptr)
but I believe it makes much more sense for it to be synonymous with
    if(array.length)
since that's the thing you want to be checking 99.9% of the time.

A little while ago I realized I was making the mistake of checking 
if(array) all over my code.  It makes a lot of sense to do that if you 
know Python, since that's how Python works.  But I think Python's way 
makes a lot more sense than D's way.  So it's hard to remember that the 
simple and clear   if(array)  is almost always a bug waiting to happen.


--bb
Dec 09 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
BTW, if someone does feel the current behavior is more rational or 
functional in some way, then I'd love to hear it.  Perhaps it's my 
familiarity with Python, but I just don't get why you'd want if(array) 
to mean anything other than if(array.length).

--bb
Dec 09 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On Dec 10, 2007 2:01 AM, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 BTW, if someone does feel the current behavior is more rational or
 functional in some way, then I'd love to hear it.  Perhaps it's my
 familiarity with Python, but I just don't get why you'd want if(array)
 to mean anything other than if(array.length).

Personally, I'd prefer if(array) to fail to compile, because I don't like the idea of implicit conversions to bool. That would force you to say what you mean - i.e. either if (array.length == 0) or if (array is null) I suspect the current behaviour really means if (array.ptr == null && array.length == 0) which is not entirely unreasonable. Certainly, in the case of strings (as special type of array) the current behaviour allows one to distinguish between an unassigned string and an empty string - which is occasionally desirable.
Dec 10 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On Dec 10, 2007 2:01 AM, Bill Baxter <dnewsgroup billbaxter.com> wrote:
 BTW, if someone does feel the current behavior is more rational or
 functional in some way, then I'd love to hear it.  Perhaps it's my
 familiarity with Python, but I just don't get why you'd want if(array)
 to mean anything other than if(array.length).

Personally, I'd prefer if(array) to fail to compile, because I don't like the idea of implicit conversions to bool. That would force you to say what you mean - i.e. either if (array.length == 0) or if (array is null)

I also would prefer an error to the current behavior of doing something unintuitive that looks like it works correctly but in fact does something slightly different.
 I suspect the current behaviour really means
 
     if (array.ptr == null && array.length == 0)

I guess you are free to look at it it that way, however if you look at the truth table I posted in the original message, the array.length == 0 is redundant there. if array.ptr is null length is always zero.
 which is not entirely unreasonable. Certainly, in the case of strings
 (as special type of array) the current behaviour allows one to
 distinguish between an unassigned string and an empty string - which
 is occasionally desirable.

If the default were changed to check array.length you could still achieve that by explicitly checking "if(array.ptr)" --bb
Dec 10 2007
parent reply "Bruce Adams" <tortoise_74 yeah.who.co.uk> writes:
On Mon, 10 Dec 2007 09:07:13 -0000, Bill Baxter  =

<dnewsgroup billbaxter.com> wrote:

 Janice Caron wrote:
 On Dec 10, 2007 2:01 AM, Bill Baxter <dnewsgroup billbaxter.com> wrot=


 BTW, if someone does feel the current behavior is more rational or
 functional in some way, then I'd love to hear it.  Perhaps it's my
 familiarity with Python, but I just don't get why you'd want if(arra=



 to mean anything other than if(array.length).



 like the idea of implicit conversions to bool. That would force you t=


 say what you mean - i.e. either
      if (array.length =3D=3D 0)
  or
      if (array is null)

I also would prefer an error to the current behavior of doing somethin=

 unintuitive that looks like it works correctly but in fact does  =

 something slightly different.

should not even be a warning in the core language. In linted variant you are free to enforce stricter rules. I thought I saw a link to a dlint someti= me ago.
 I suspect the current behaviour really means
      if (array.ptr =3D=3D null && array.length =3D=3D 0)

I guess you are free to look at it it that way, however if you look at=

 the truth table I posted in the original message, the array.length =3D=

 is redundant there.  if array.ptr is null length is always zero.

=3D 0 as in: foo[5] x; //not initialised if (x) { ... }
 which is not entirely unreasonable. Certainly, in the case of strings=


 (as special type of array) the current behaviour allows one to
 distinguish between an unassigned string and an empty string - which
 is occasionally desirable.

If the default were changed to check array.length you could still =

 achieve that by explicitly checking "if(array.ptr)"

Dec 10 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Bruce Adams wrote:
 I suspect you are moving into the realms of lint here. I would say it 
 should not
 even be a warning in the core language. In linted variant you are
 free to enforce stricter rules. I thought I saw a link to a dlint sometime
 ago.

Optional warnings are also a planned feature for Descent. But that's the future.
Dec 10 2007
prev sibling next sibling parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Mon, 10 Dec 2007 10:52:00 +0900, Bill Baxter wrote:
 
 In a nutshell,
     if(array)
 is synonymous with
     if(array.ptr)
 but I believe it makes much more sense for it to be synonymous with
     if(array.length)
 since that's the thing you want to be checking 99.9% of the time.

I'm guessing that this behaviour is due to the commonly used idiom for all reference types, namely that the test is against the 'pointer' value rather than any other aspect of the item being referenced. class Foo {}; Foo f = new Foo(); Foo g; if (f) ... if (g) ... long *lp; if (lp) ... Personally, I regard this as a shorthand option that should be avoided on legibility grounds. I prefer the more explicit versions ... if (array.ptr !is null) if (array.length != 0) if (f !is null) if (lp !is null) only because this is harder to misunderstand. -- Derek (skype: derek.j.parnell) Melbourne, Australia 10/12/2007 2:17:38 PM
Dec 09 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Derek Parnell wrote:
 ...
 
 Personally, I regard this as a shorthand option that should be avoided on
 legibility grounds. 
 
 I prefer the more explicit versions ...
 
    if (array.ptr !is null)
    if (array.length != 0) 
    if (f !is null)
    if (lp !is null)
 
 only because this is harder to misunderstand.

I actually went and created a pseudo-property for just this purpose: /// Tests the array to see if it's of non-zero length. bool nz(T)(T arr) { return arr.length != 0; } /// Tests the array to see if it's of zero length. bool z(T)(T arr) { return arr.length == 0; } if( "foo".nz() || "bar".z() ) ... Much quicker to type, and more legible (at least, for me.) -- Daniel
Dec 09 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Janice Caron wrote:
 On Dec 10, 2007 4:21 AM, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 I actually went and created a pseudo-property for just this purpose:

 /// Tests the array to see if it's of non-zero length.
 bool nz(T)(T arr) { return arr.length != 0; }
 /// Tests the array to see if it's of zero length.
 bool z(T)(T arr) { return arr.length == 0; }

What is relevant to this whole question is the fact the I recall Walter saying he was thinking of changing the representation of an array from struct { ptr, length } to struct { ptr, end }. I suggested at that time that all arrays should be given an isEmpty property, because isEmpty() is just a sensible idea for collections in general. I have to say though, that I don't like the function names z() and nz(). I don't equate "zero" with "zero length". To me, the only meaning I could attribute to "is zero" would be "is full of zeroes". That is, I would expect the array [ 0, 0, 0, 0 ] to pass a test called z() and fail a test called nz(). That's why I'd suggest isEmpty() as the preferred name.

I never suggested z and nz as standard names; that would be a ridiculous proposition, as I doubt many people would be able to work out what they meant at first glance. I use them because a. they're shorter than isEmpty and !isEmpty, b. I'm lazy when it comes to typing and c. because they're actually named after jnz and jz from assembler, which I don't expect *anyone* to pick up on. I'm not a big fan of 'isEmpty' because I think it's too long, *and* it requires me to hit shift [1]. 'empty' would be OK, but then that's both a noun and a verb, which leads to ambiguity over exactly what it does. [2] All things considered, 'isEmpty' is probably the best choice for inclusion as a standard property. That said, I'll keep my lovely .z & .nz properties. :) -- Daniel [1] I realise the irony of this, in that .z and .nz require me to type a set of parens. None the less, I find typing '.z()' much faster and easier than '.isEmpty' due to the way my hands move as I type. [2] Sometimes, I really wish '?' and '!' were valid characters in identifiers, like in Ruby.
Dec 10 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Daniel Keep wrote:
 [2] Sometimes, I really wish '?' and '!' were valid characters in
 identifiers, like in Ruby.

That gives me the answer to the Object.toString() vs. Object.toUtf8() problem posed before... just change it to Object.wtf?()
Dec 10 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Robert Fraser wrote:
 Daniel Keep wrote:
 [2] Sometimes, I really wish '?' and '!' were valid characters in
 identifiers, like in Ruby.

That gives me the answer to the Object.toString() vs. Object.toUtf8() problem posed before... just change it to Object.wtf?()

'?' is used for function that check a property of a type, '!' is used for functions that perform in-place modification. if( "my string".empty? ) [3,1,2].sort --> int[] [3,1,2].sort! --> void Without "?", you can get away by putting "is" in front of everything, but "!" is a hard one, unless you come up with some sort of trailing sigil using normal characters (like _ip). -- Daniel
Dec 10 2007
parent reply Leandro Lucarella <llucax gmail.com> writes:
Daniel Keep, el 11 de diciembre a las 13:37 me escribiste:
 
 
 Robert Fraser wrote:
 Daniel Keep wrote:
 [2] Sometimes, I really wish '?' and '!' were valid characters in
 identifiers, like in Ruby.

That gives me the answer to the Object.toString() vs. Object.toUtf8() problem posed before... just change it to Object.wtf?()

'?' is used for function that check a property of a type, '!' is used for functions that perform in-place modification. if( "my string".empty? ) [3,1,2].sort --> int[] [3,1,2].sort! --> void Without "?", you can get away by putting "is" in front of everything, but "!" is a hard one, unless you come up with some sort of trailing sigil using normal characters (like _ip).

One thing that I think Ruby doesn't have is automatic not-in-place function generation. I mean, if I have implemented SomeClass.sort! but not SomeClass.sort, the later can be created by copying the object, sorting the copy in-place and returning that copy. You can see it as a copy constructor in C++, which is generated by default by the compiler, if you don't provide one. In D it could be something like: class T { void sort() { // in-place sort implementation } T dupsort() // default compiler implementation { auto t = new T(this); t.sort(); return t; } } I think the regular name in D should be used for the in-place version, and dup<name> (or d<name> for short) could be used for the copying version, because there is also a well known .dup property (and I think it fits better in D the in-place because of it's high performance orientation). Maybe some syntactic sugar can be used too when using the dup version, something like: auto t = new T(); auto w = t.sort.dup(); // calls dupsort() You can see it as function were objects (like in Python, or Ruby AFAIK) which has a property "dup" =) Which makes me think that it could be defined as: class T { void sort() { // in-place sort implementation T dup() // default compiler implementation { auto t = new T(this); t.sort(); return t; } } } The dup() nested function could be not present (if the default implementation is enought(). I know we have a problem to access to dup() nested function because it needs a stack frame, but maybe the compiler can be aware of that and use it as a special case. Or maybe we can use the syntax for pre/post conditions: class T { void sort() body { // in-place sort implementation } dup // default compiler implementation { auto t = new T(this); t.sort(); return t; } } Again, you should only have to provide a dup function if the compilers default is not enought. Too much? =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Y tuve amores, que fue uno sólo El que me dejó de a pie y me enseñó todo...
Dec 11 2007
next sibling parent renoX <renosky free.fr> writes:
Leandro Lucarella a écrit :
 Daniel Keep, el 11 de diciembre a las 13:37 me escribiste:
 Robert Fraser wrote:
 Daniel Keep wrote:
 [2] Sometimes, I really wish '?' and '!' were valid characters in
 identifiers, like in Ruby.

problem posed before... just change it to Object.wtf?()

for functions that perform in-place modification. if( "my string".empty? ) [3,1,2].sort --> int[] [3,1,2].sort! --> void Without "?", you can get away by putting "is" in front of everything, but "!" is a hard one, unless you come up with some sort of trailing sigil using normal characters (like _ip).

One thing that I think Ruby doesn't have is automatic not-in-place function generation. I mean, if I have implemented SomeClass.sort! but not SomeClass.sort, the later can be created by copying the object, sorting the copy in-place and returning that copy. You can see it as a copy constructor in C++, which is generated by default by the compiler, if you don't provide one. In D it could be something like: class T { void sort() { // in-place sort implementation } T dupsort() // default compiler implementation { auto t = new T(this); t.sort(); return t; } } I think the regular name in D should be used for the in-place version, and dup<name> (or d<name> for short) could be used for the copying version, because there is also a well known .dup property (and I think it fits better in D the in-place because of it's high performance orientation). Maybe some syntactic sugar can be used too when using the dup version, something like: auto t = new T(); auto w = t.sort.dup(); // calls dupsort() You can see it as function were objects (like in Python, or Ruby AFAIK) which has a property "dup" =) Which makes me think that it could be defined as: class T { void sort() { // in-place sort implementation T dup() // default compiler implementation { auto t = new T(this); t.sort(); return t; } } } The dup() nested function could be not present (if the default implementation is enought(). I know we have a problem to access to dup() nested function because it needs a stack frame, but maybe the compiler can be aware of that and use it as a special case. Or maybe we can use the syntax for pre/post conditions: class T { void sort() body { // in-place sort implementation } dup // default compiler implementation { auto t = new T(this); t.sort(); return t; } } Again, you should only have to provide a dup function if the compilers default is not enought. Too much? =)

I like it but I think that the calls are a bit confusing: - t.dup.sort(): duplicate t then sort in-place the duplicate. - t.sort().dup: sort in-place t then duplicate it. - t.sort.dup(): by default duplicate t then sort in-place the duplicate, so it's the equivalent of t.dup.sort() except that it can be overloaded in the sort function to provide a faster implementation. OK, it all make sense when you look closely and it's D-ish but it's also a pitfall: "t.sort().dup" and "t.sort.dup()" do very different things yet look very very similar.. The ruby way is more concise and less risky IMHO (though a bit obscure for beginners/non-rubyist). I wish that D have copied more things from Ruby's syntax which I like very much.. renoX
Dec 11 2007
prev sibling next sibling parent reply Robert DaSilva <sp.unit.262+digitalmars gmail.com> writes:
Leandro Lucarella wrote:
 Daniel Keep, el 11 de diciembre a las 13:37 me escribiste:
 Robert Fraser wrote:
 Daniel Keep wrote:
 [2] Sometimes, I really wish '?' and '!' were valid characters in
 identifiers, like in Ruby.

problem posed before... just change it to Object.wtf?()

for functions that perform in-place modification. if( "my string".empty? ) [3,1,2].sort --> int[] [3,1,2].sort! --> void Without "?", you can get away by putting "is" in front of everything, but "!" is a hard one, unless you come up with some sort of trailing sigil using normal characters (like _ip).

One thing that I think Ruby doesn't have is automatic not-in-place function generation. I mean, if I have implemented SomeClass.sort! but not SomeClass.sort, the later can be created by copying the object, sorting the copy in-place and returning that copy. You can see it as a copy constructor in C++, which is generated by default by the compiler, if you don't provide one. In D it could be something like: class T { void sort() { // in-place sort implementation } T dupsort() // default compiler implementation { auto t = new T(this); t.sort(); return t; } } I think the regular name in D should be used for the in-place version, and dup<name> (or d<name> for short) could be used for the copying version, because there is also a well known .dup property (and I think it fits better in D the in-place because of it's high performance orientation). Maybe some syntactic sugar can be used too when using the dup version, something like: auto t = new T(); auto w = t.sort.dup(); // calls dupsort()

Don't you mean t.dup.sort(). t.sort.dup() would do a inplace sort and then duplicate it. (t.dup().sort and t.dup.sort() mean the *exact* same thing, the ending () are optional for *all* function that don't tack arguments.)
Dec 11 2007
parent reply Leandro Lucarella <llucax gmail.com> writes:
Robert DaSilva, el 11 de diciembre a las 19:26 me escribiste:
 Maybe some syntactic sugar can be used too when using the dup version,
 something like:
 
 auto t = new T();
 auto w = t.sort.dup(); // calls dupsort()

Don't you mean t.dup.sort().

No.
 t.sort.dup() would do a inplace sort and then duplicate it.
 (t.dup().sort and t.dup.sort() mean the *exact* same
 thing, the ending () are optional for *all* function that don't tack
 arguments.)

Ok, good catch, maybe that syntax is not right but you missed the big picture (a compiler generated default implementation for a copying function that can be overrideable). If you now write t.sort.dup(), you are exactly doing that: duplicating t and then sorting it (in-place I guess). If the implementor has a more eficient way to use the copy while sorting, you miss that, or you have to change the syntax (to t.dupsort() for example). -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- El discman vuelve locos a los controles, te lleva a cualquier lugar. Ajústense pronto los cinturones, nos vamos a estrellar. Evidentemente, no escuchaste el speech, que dio la azafata, antes de despegar.
Dec 11 2007
parent reply Robert DaSilva <sp.unit.262+digitalmars gmail.com> writes:
Leandro Lucarella wrote:
 Robert DaSilva, el 11 de diciembre a las 19:26 me escribiste:
 Maybe some syntactic sugar can be used too when using the dup version,
 something like:

 auto t = new T();
 auto w = t.sort.dup(); // calls dupsort()


No.
 t.sort.dup() would do a inplace sort and then duplicate it.
 (t.dup().sort and t.dup.sort() mean the *exact* same
 thing, the ending () are optional for *all* function that don't tack
 arguments.)

Ok, good catch, maybe that syntax is not right but you missed the big picture (a compiler generated default implementation for a copying function that can be overrideable). If you now write t.sort.dup(), you are exactly doing that: duplicating t and then sorting it (in-place I guess). If the implementor has a more eficient way to use the copy while sorting, you miss that, or you have to change the syntax (to t.dupsort() for example).

I'm just saying that t.sort.dup() can *only* mean sort t then duplicate what sort returns (an error as sort returns void); unless sort is a struck that overloads opCall, but it's not.
Dec 11 2007
parent reply Leandro Lucarella <llucax gmail.com> writes:
Robert DaSilva, el 11 de diciembre a las 21:31 me escribiste:
 Ok, good catch, maybe that syntax is not right but you missed the big
 picture (a compiler generated default implementation for a copying
 function that can be overrideable).
 
 If you now write t.sort.dup(), you are exactly doing that: duplicating t
 and then sorting it (in-place I guess). If the implementor has a more
 eficient way to use the copy while sorting, you miss that, or you have to
 change the syntax (to t.dupsort() for example).
 

I'm just saying that t.sort.dup() can *only* mean sort t then duplicate what sort returns (an error as sort returns void); unless sort is a struck that overloads opCall, but it's not.

I was talking about a new feature proposal. I know it doesn't work now. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Hey you, dont help them to bury the light Don't give in without a fight.
Dec 12 2007
parent reply Robert DaSilva <sp.unit.262+digitalmars gmail.com> writes:
Leandro Lucarella wrote:
 Robert DaSilva, el 11 de diciembre a las 21:31 me escribiste:
 Ok, good catch, maybe that syntax is not right but you missed the big
 picture (a compiler generated default implementation for a copying
 function that can be overrideable).

 If you now write t.sort.dup(), you are exactly doing that: duplicating t
 and then sorting it (in-place I guess). If the implementor has a more
 eficient way to use the copy while sorting, you miss that, or you have to
 change the syntax (to t.dupsort() for example).

what sort returns (an error as sort returns void); unless sort is a struck that overloads opCall, but it's not.

I was talking about a new feature proposal. I know it doesn't work now.

I'm say it could *NEVER* work because that already has a well defined behaver and a sub-function can only be called by it's direct parent function, it own sub-function or sibling sub functions and their sub-functions, because it *needs* a context pointer to it's parent functions' stack.
Dec 12 2007
parent Leandro Lucarella <llucax gmail.com> writes:
Robert DaSilva, el 12 de diciembre a las 21:23 me escribiste:
 Leandro Lucarella wrote:
 Robert DaSilva, el 11 de diciembre a las 21:31 me escribiste:
 Ok, good catch, maybe that syntax is not right but you missed the big
 picture (a compiler generated default implementation for a copying
 function that can be overrideable).

 If you now write t.sort.dup(), you are exactly doing that: duplicating t
 and then sorting it (in-place I guess). If the implementor has a more
 eficient way to use the copy while sorting, you miss that, or you have to
 change the syntax (to t.dupsort() for example).

what sort returns (an error as sort returns void); unless sort is a struck that overloads opCall, but it's not.

I was talking about a new feature proposal. I know it doesn't work now.


I don't like to repeat myself, but you force me :)
 I'm say it could *NEVER* work because that already has a well defined
 behaver

 Ok, good catch, maybe that syntax is not right but you missed the big
 picture (a compiler generated default implementation for a copying
 function that can be overrideable).




 and a sub-function can only be called by it's direct parent
 function, it own sub-function or sibling sub functions and their
 sub-functions, because it *needs* a context pointer to it's parent
 functions' stack.

From my first e-mail: "I know we have a problem to access to dup() nested function because it needs a stack frame, but ..." Are you even reading my e-mails? =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- aFR [afr my.farts.cause.nuclear.reaction.org] has quit IRC (Ping timeout)
Dec 13 2007
prev sibling parent Oskar Linde <oskar.lindeREM OVEgmail.com> writes:
Leandro Lucarella wrote:
 Daniel Keep, el 11 de diciembre a las 13:37 me escribiste:
 Robert Fraser wrote:
 Daniel Keep wrote:
 [2] Sometimes, I really wish '?' and '!' were valid characters in
 identifiers, like in Ruby.

problem posed before... just change it to Object.wtf?()

for functions that perform in-place modification. if( "my string".empty? ) [3,1,2].sort --> int[] [3,1,2].sort! --> void Without "?", you can get away by putting "is" in front of everything, but "!" is a hard one, unless you come up with some sort of trailing sigil using normal characters (like _ip).


One convention I have grown comfortable with is using the adjective form of the verb to define the non-in place versions: sort - sorted reverse - reversed transpose - transposed capitalize - capitalized strip - stripped rotate - rotated normalize - normalized project - projected But doesn't work in 100 % of the cases, and I would prefer if the in-place version wasn't the shortest form and stood out a bit more.
 One thing that I think Ruby doesn't have is automatic not-in-place
 function generation. I mean, if I have implemented SomeClass.sort! but not
 SomeClass.sort, the later can be created by copying the object, sorting
 the copy in-place and returning that copy. You can see it as a copy
 constructor in C++, which is generated by default by the compiler, if you
 don't provide one.

One problem here is that the functional version is the generic one. Not all algorithms have in-place versions and some that do are much more complicated. -- Oskar
Dec 13 2007
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Janice Caron wrote:
 On Dec 10, 2007 4:21 AM, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 I actually went and created a pseudo-property for just this purpose:

 /// Tests the array to see if it's of non-zero length.
 bool nz(T)(T arr) { return arr.length != 0; }
 /// Tests the array to see if it's of zero length.
 bool z(T)(T arr) { return arr.length == 0; }

What is relevant to this whole question is the fact the I recall Walter saying he was thinking of changing the representation of an array from struct { ptr, length } to struct { ptr, end }. I suggested at that time that all arrays should be given an isEmpty property, because isEmpty() is just a sensible idea for collections in general. I have to say though, that I don't like the function names z() and nz(). I don't equate "zero" with "zero length". To me, the only meaning I could attribute to "is zero" would be "is full of zeroes". That is, I would expect the array [ 0, 0, 0, 0 ] to pass a test called z() and fail a test called nz(). That's why I'd suggest isEmpty() as the preferred name.

Agreed. I might be ok with "zero" and "nonzero" but I'd rather have it be called empty() or isEmpty(). Anyway seems we agree there should be a default property like this. It's kind of STL 101 that you should always call a container's 'empty' rather than checking 'size==0'. --bb
Dec 10 2007
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Derek Parnell wrote:
 On Mon, 10 Dec 2007 10:52:00 +0900, Bill Baxter wrote:
  
 In a nutshell,
     if(array)
 is synonymous with
     if(array.ptr)
 but I believe it makes much more sense for it to be synonymous with
     if(array.length)
 since that's the thing you want to be checking 99.9% of the time.

I'm guessing that this behaviour is due to the commonly used idiom for all reference types, namely that the test is against the 'pointer' value rather than any other aspect of the item being referenced. class Foo {}; Foo f = new Foo(); Foo g; if (f) ... if (g) ... long *lp; if (lp) ... Personally, I regard this as a shorthand option that should be avoided on legibility grounds. I prefer the more explicit versions ... if (array.ptr !is null) if (array.length != 0) if (f !is null) if (lp !is null) only because this is harder to misunderstand.

I'm just too lazy to type that much. :-) --bb
Dec 09 2007
prev sibling next sibling parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Bill Baxter wrote:
 Here's a little test program: [...] So why does the simplest check
 
 if(array) { ... }
 
 tell us b) ?

Hmmm... bad luck?
 [...]  But I think Python's way makes a lot more sense than D's way.  So
 it's hard to remember that the simple and clear   if(array)  is almost
 always a bug waiting to happen.

While I'm not used to this shorthand (as I don't regularly meddle in things Pythonic), I surely could get so quite quickly. I like it. ++votes I think D's current behaviour makes little sense indeed, as an array is not just another reference type or object, but something special. If there was a built-in type "set" in D, I'd expect it to be true when it's not empty. Same goes for the array type. regards, frank
Dec 09 2007
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Bill Baxter wrote:
 Here's a little test program:
 
 void main()
 {
     void check(int[] l) {
         if (l) writef("%-10s","true"); else writef("%-10s","false");
         writef("%-10s", (l is null));
         writef("%-10s", (l.length==0));
         writefln;
     }
 
     int[] list;
     writefln("%-10s%-10s%-10s%-10s",
              " ", "is true","is null","length==0");
     writef("%-10s","initial"); check(list);
     list = new int[10];
     list = null;
     writef("%-10s","nulled"); check(list);
 
     list = new int[10];
     list.length = 0;
     writef("%-10s", "zeroed"); check(list);
 }
 
 
 and here's the table it generates:
 
           is true   is null   length==0
 initial   false     true      true
 nulled    false     true      true
 zeroed    true      false     true
 
 Question: which is the bit of information you are more likely interested 
 in knowing:
 
 a) whether the array is currently empty.
 b) whether the array happens to have a buffer of some unknowable length 
 allocated because of a previous history of operations on it.
 
 If you answered a) then we think alike.
 
 So why does the simplest check
 
     if(array) { ... }
 
 tell us b) ?
 
 In a nutshell,
    if(array)
 is synonymous with
    if(array.ptr)
 but I believe it makes much more sense for it to be synonymous with
    if(array.length)
 since that's the thing you want to be checking 99.9% of the time.
 
 A little while ago I realized I was making the mistake of checking 
 if(array) all over my code.  It makes a lot of sense to do that if you 
 know Python, since that's how Python works.  But I think Python's way 
 makes a lot more sense than D's way.  So it's hard to remember that the 
 simple and clear   if(array)  is almost always a bug waiting to happen.
 
 
 --bb

me too
Dec 09 2007
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Dec 10, 2007 4:21 AM, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 I actually went and created a pseudo-property for just this purpose:

 /// Tests the array to see if it's of non-zero length.
 bool nz(T)(T arr) { return arr.length != 0; }
 /// Tests the array to see if it's of zero length.
 bool z(T)(T arr) { return arr.length == 0; }

What is relevant to this whole question is the fact the I recall Walter saying he was thinking of changing the representation of an array from struct { ptr, length } to struct { ptr, end }. I suggested at that time that all arrays should be given an isEmpty property, because isEmpty() is just a sensible idea for collections in general. I have to say though, that I don't like the function names z() and nz(). I don't equate "zero" with "zero length". To me, the only meaning I could attribute to "is zero" would be "is full of zeroes". That is, I would expect the array [ 0, 0, 0, 0 ] to pass a test called z() and fail a test called nz(). That's why I'd suggest isEmpty() as the preferred name.
Dec 10 2007