www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - array.length++ not an lvalue

reply Erik Lechak <prochak netzero.net> writes:
Hello all,

I just wanted to start by thanking you for the great responses to my previous
questions.  I appreciate the knowledgeable and friendly nature of this
newsgroup.

I ran into my first WTF moment with D.  I spent way too much time figuring out
why 'array'.length++ was a compiler error (Error: x.length is not an lvalue).

This is a newsgroup entry describing the problem: 
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=39179

Is there a document detailing these "special exceptions" so that I don't have
to blindly stumble upon them?  If not are there any more that should be
documented so that I can add them to my Wiki
(http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?  

For what it's worth, I think 'array'.length++ and 'array'.length += 1 should be
valid.  If that is not an option, it would be nice if the error message could
be changed to something like "Error: x.length is a special property that
prohibits the use of the increment (++) and add_and_assign (+=) operators".  

Thanks,
Erik Lechak
Jun 18 2008
next sibling parent Lutger <lutger.blijdestin gmail.com> writes:
Erik Lechak wrote:

...
 For what it's worth, I think 'array'.length++ and 'array'.length += 1
 should be valid.  If that is not an option, it would be nice if the error
 message could be changed to something like "Error: x.length is a special
 property that prohibits the use of the increment (++) and add_and_assign
 (+=) operators".
 
 Thanks,
 Erik Lechak

All properties behave like that, it's mentioned in the spec: "Note: Properties currently cannot be the lvalue of an op=, ++, or -- operator." In between the spec and the wiki4d, everything can be found but I'm not aware of any site that has a list of common pitfalls specifically, except yours of course...
Jun 18 2008
prev sibling next sibling parent reply "Koroskin Denis" <2korden gmail.com> writes:
On Wed, 18 Jun 2008 17:12:19 +0400, Erik Lechak <prochak netzero.net>  
wrote:

 Hello all,

 I just wanted to start by thanking you for the great responses to my  
 previous questions.  I appreciate the knowledgeable and friendly nature  
 of this newsgroup.

 I ran into my first WTF moment with D.  I spent way too much time  
 figuring out why 'array'.length++ was a compiler error (Error: x.length  
 is not an lvalue).

 This is a newsgroup entry describing the problem:
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=39179

 Is there a document detailing these "special exceptions" so that I don't  
 have to blindly stumble upon them?  If not are there any more that  
 should be documented so that I can add them to my Wiki  
 (http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?

 For what it's worth, I think 'array'.length++ and 'array'.length += 1  
 should be valid.  If that is not an option, it would be nice if the  
 error message could be changed to something like "Error: x.length is a  
 special property that prohibits the use of the increment (++) and  
 add_and_assign (+=) operators".

 Thanks,
 Erik Lechak

Length property of the array is not a member variable, but rather a member function: int[] array = new int[42]; assert(array.length() == 42); but you can also omit paranthesis (that's merely a syntax sugar): assert(array.length == 42); The same way the following: array.length = 100 is translated into a function call: array.length(100); which does array resizing. Note that you should normally call array.length(array.length() + 1) (or array.length = array.length + 1) in order to increase array size by 1, and what you write is this: array.length() += 1; array.length()++; It doesn't make much sense, since you increment a temporary variable! D *could* do the following trick: array.length()+=1 -> array.length(array.length() + 1); but it would break too much of the existing code and makes a little of sense. Other solution would be to return some object that would behave like int (be opImplicitCast'able to it) and have an overloaded opAssign, opAddAssign, etc, but does anybody *really* interested in it? P.S. I just checked and it appears that you don't have an option of having paranthesis, unlike usual member functions, i.e. the following is not semantically correct (although it ought to be, IMO): // trying to resize an array array.length(42); // error, use array.length = 42 instead. But the logic is the same. Please, correct me if I'm wrong.
Jun 18 2008
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Koroskin Denis" <2korden gmail.com> wrote in message 
news:op.ucx7xdubenyajd proton.creatstudio.intranet...

 D *could* do the following trick:
 array.length()+=1 -> array.length(array.length() + 1);

 but it would break too much of the existing code and makes a little of 
 sense.

It makes perfectly good sense. Good enough that most languages that have built-in properties translate augmenatation assignments into exactly what you've written.
Jun 18 2008
prev sibling next sibling parent Fawzi Mohamed <fmohamed mac.com> writes:
On 2008-06-18 16:30:39 +0200, "Koroskin Denis" <2korden gmail.com> said:

 [some nice points]
 D *could* do the following trick:
 array.length()+=1 -> array.length(array.length() + 1);
 
 but it would break too much of the existing code and makes a little of  sense.

actually I think that in some cases for properties it makes sense (for example for my slices of multidimensional arrays) and does not break code *but* normally it defeats the performance reason to do +=. In fact it is a good idea not to hide things that have a speed penalty, and the extra typing is minimal. In the case of the length property this is very much so. Arrays are not the correct data structure for step by step resizes... either try to have the correct size from the beginning, or switch datastructure.
Jun 18 2008
prev sibling next sibling parent Erik Lechak <prochak netzero.net> writes:
Koroskin Denis Wrote:

 On Wed, 18 Jun 2008 17:12:19 +0400, Erik Lechak <prochak netzero.net>  
 wrote:
 
 Hello all,

 I just wanted to start by thanking you for the great responses to my  
 previous questions.  I appreciate the knowledgeable and friendly nature  
 of this newsgroup.

 I ran into my first WTF moment with D.  I spent way too much time  
 figuring out why 'array'.length++ was a compiler error (Error: x.length  
 is not an lvalue).

 This is a newsgroup entry describing the problem:
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=39179

 Is there a document detailing these "special exceptions" so that I don't  
 have to blindly stumble upon them?  If not are there any more that  
 should be documented so that I can add them to my Wiki  
 (http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?

 For what it's worth, I think 'array'.length++ and 'array'.length += 1  
 should be valid.  If that is not an option, it would be nice if the  
 error message could be changed to something like "Error: x.length is a  
 special property that prohibits the use of the increment (++) and  
 add_and_assign (+=) operators".

 Thanks,
 Erik Lechak

Length property of the array is not a member variable, but rather a member function:

When I compile this: import std.stdio; void main(){ int x[23]; writefln(x.length()); } I get this: Error: undefined identifier length Error: function expected before (), not length of type int So the compiler is telling me length is of type int.
 int[] array = new int[42];
 assert(array.length() == 42);

This does not compile.
 but you can also omit paranthesis (that's merely a syntax sugar):

It's not syntactic sugar if it does not compile with the parens.
 assert(array.length == 42);

Yep, this works, but it does not show that array.length is a method/function.
 The same way the following:
 array.length = 100
 
 is translated into a function call: array.length(100); which does array  
 resizing.

Ok. Maybe it gets translated into a method call. But that does not mean that array.length is a method. It sounds more like a tied variable in perl.
 Note that you should normally call array.length(array.length() + 1)

I would love to do that because it makes sense. But it does not compile.
 D *could* do the following trick:
 array.length()+=1 -> array.length(array.length() + 1);

array.length(array.length() + 1) is not a trick. It is logical.
 but it would break too much of the existing code and makes a little of  
 sense.

It would break code but it would make sense at least to me:) So I either have to look at properties as methods that are called without parens or integers that restrict my use of operators. That's a bummer. Thanks, Erik Lechak
Jun 18 2008
prev sibling parent Georg Wrede <georg nospam.org> writes:
Koroskin Denis wrote:
 D *could* do the following trick:
 array.length()+=1 -> array.length(array.length() + 1);

Since D already obfuscates learning D with functions that look like properties, this would be polite to have in D.
Jun 19 2008
prev sibling next sibling parent "Koroskin Denis" <2korden gmail.com> writes:
On Wed, 18 Jun 2008 19:11:39 +0400, Fawzi Mohamed <fmohamed mac.com> wrote:

 On 2008-06-18 16:30:39 +0200, "Koroskin Denis" <2korden gmail.com> said:

 In the case of the length property this is very much so.
 Arrays are not the correct data structure for step by step resizes...  
 either try to have the correct size from the beginning, or switch  
 datastructure.

D arrays only grow exponentially, so no worries here (although it does consume some time to understand if the capacity is large enough to avoid resizing).
Jun 18 2008
prev sibling next sibling parent janderson <askme me.com> writes:
Erik Lechak wrote:
 Hello all,
 
 Is there a document detailing these "special exceptions" so that I don't have
to blindly stumble upon them?  If not are there any more that should be
documented so that I can add them to my Wiki
(http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?  

This might be useful. http://prowiki.org/wiki4d/wiki.cgi?ShortFrequentAnswers
 
 Thanks,
 Erik Lechak
 

No problem.
Jun 18 2008
prev sibling next sibling parent reply Mike <vertex gmx.at> writes:
This could work if we had real properties. I'd really like to see an
extended/modified version of the C# property syntax in D:

private int _length;
public property int length
{
    opSet() { return _length = value; }
    opGet() { return value; }
    opPostIncrement() { _length++; }
    // ...
}

That would solve the problem.

-Mike

Erik Lechak Wrote:

 Hello all,
 
 I just wanted to start by thanking you for the great responses to my previous
questions.  I appreciate the knowledgeable and friendly nature of this
newsgroup.
 
 I ran into my first WTF moment with D.  I spent way too much time figuring out
why 'array'.length++ was a compiler error (Error: x.length is not an lvalue).
 
 This is a newsgroup entry describing the problem: 
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=39179
 
 Is there a document detailing these "special exceptions" so that I don't have
to blindly stumble upon them?  If not are there any more that should be
documented so that I can add them to my Wiki
(http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?  
 
 For what it's worth, I think 'array'.length++ and 'array'.length += 1 should
be valid.  If that is not an option, it would be nice if the error message
could be changed to something like "Error: x.length is a special property that
prohibits the use of the increment (++) and add_and_assign (+=) operators".  
 
 Thanks,
 Erik Lechak
 

Jun 18 2008
parent "Nick Sabalausky" <a a.a> writes:
"Mike" <vertex gmx.at> wrote in message 
news:g3bcub$11dk$1 digitalmars.com...
 This could work if we had real properties. I'd really like to see an 
 extended/modified version of the C# property syntax in D:

 private int _length;
 public property int length
 {
    opSet() { return _length = value; }
    opGet() { return value; }
    opPostIncrement() { _length++; }
    // ...
 }

 That would solve the problem.

 -Mike

"Mike" <vertex gmx.at> wrote in message news:g3bcub$11dk$1 digitalmars.com...
 This could work if we had real properties. I'd really like to see an 
 extended/modified

version of the C# property syntax in D:
 private int _length;
 public property int length
 {
    opSet() { return _length = value; }
    opGet() { return value; }
    opPostIncrement() { _length++; }
    // ...
 }

 That would solve the problem.

 -Mike

That's just what I was going to post. The way this currently works is insanely inconsistent: -------- 1. D doesn't have accessors (to borrow C# terminology), and yet 'array'.length *is* separate getter/setter functions called using member variable syntax, which of course is the very definition of an accessor. So what, D has accessors, but doesn't let you create any? (I like accessors BTW, because I'm of the mind that "member variable" vs "member function" is often an implementation detail and therefore should be hidable just like any other implementation detail.) -------- 2. The statement/expression "x++" is considered to be shorthand for: yield x; // C#-inspired psuedo-code // Execute the rest of the statement or expression x = x + 1; So, *even if* "x = a.length" and "a.length = x" are turned into "x = a.length()" and "a.length(x)" by the compiler, then logically, "a.length++" should *first* turn into: yield a.length; // Execute the rest of the statement or expression a.length = a.length + 1; Which then turns into: yield a.length(); // Execute the rest of the statement or expression a.length(a.length() + 1); Since this substitution isn't happening, that means that "x++" is only *sometimes* equivilent to the "yield x, execute the rest, x = x + 1" sequence that "x++" is normally considered to be. So, the definition goes "'x++' means ... unless x is something like 'array'.length". Inconsistency. So I don't see the problem here, unless there's some reason why the compiler *has* to proccess the "'array'.length" part *before* the "'PostfixExpression'++" part.
 It was to prevent:
 array [array.length ++] = 45;
 Which is dependent on undefined behaviou

If I'm understanding postfix right, then: array[array.length++] = 45; Becomes => array[array.length] = 45; array.length++; The first line, of course, is an index-out-of-bounds error. So where's the undefined behavior? Is the index-out-of-bounds error the undefined behavior part? But then what makes this scenario any more special than any other index-out-of-bounds error? Is "++a.length" allowed? I assume not, and if that's the case, then that simplifies the argument somewhat: ++a.length; Becomes => a.length = a.length + 1; yield a.length; Becomes => a.length(a.length() + 1); yield a.length(); And: array[++array.length] = 45; Becomes => array.length = array.length + 1; array[array.length] = 45; Becomes => array.length(array.length() + 1); array[array.length()] = 45; // Index Out-of-Bounds -------- 3. Regarding the following:
 Walter thought that
 array.length++;
 hid too much complexity.  That statement can cause:
 * realloc
 * malloc/memcpy (if realloc has to move the array)
 * GC run (if malloc doesn't have space)

If that's the case, then that means he's against the concept of accessors. While I don't agree with it, I can certainly understand it. BUT, "array.length = array.length + 1" hides the exact same complexity, and overloaded operators can also hide that sort of complexity. So...inconsistent reasoning. If the problem with the hidden complexity in "array.length++;" is that a useless temporary copy of the array might be made, then well, part of my above argument still applies, so combine that with all the usual ins and outs of "postfix" vs. "prefix". -------- So if the ability to create accessors was both 1. considered a good thing and 2. implemented, then all that stuff would solve itself. Accessors wouldn't be a "kinda/sorta exists" thing as they are now. The fact that "array.length = array.length + 1" hides complexity wouldn't matter because, hey, so can any other accessor. The statement/expression "a.length++" could get turned into the appropriate function calls, just as in any other language that supports accessors. And, of course, things *other* than built-in properties like "'array'.length" would be able to hide the implementation detail of "is ColorChangingHighGlossPaint.Color implemented as a member variable, or as get/set member functions?". "But accessors can hide the fact that an operation is resource-intensive or computationally expensive." So can overloaded operators, but as far as I can tell we all seem to be ok with those being allowed in D.
Jun 18 2008
prev sibling next sibling parent "Koroskin Denis" <2korden gmail.com> writes:
On Wed, 18 Jun 2008 20:14:27 +0400, Erik Lechak <prochak netzero.net>  
wrote:

 Koroskin Denis Wrote:

 On Wed, 18 Jun 2008 17:12:19 +0400, Erik Lechak <prochak netzero.net>
 wrote:

 Hello all,

 I just wanted to start by thanking you for the great responses to my
 previous questions.  I appreciate the knowledgeable and friendly  

 of this newsgroup.

 I ran into my first WTF moment with D.  I spent way too much time
 figuring out why 'array'.length++ was a compiler error (Error:  

 is not an lvalue).

 This is a newsgroup entry describing the problem:
  

 Is there a document detailing these "special exceptions" so that I  

 have to blindly stumble upon them?  If not are there any more that
 should be documented so that I can add them to my Wiki
 (http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?

 For what it's worth, I think 'array'.length++ and 'array'.length += 1
 should be valid.  If that is not an option, it would be nice if the
 error message could be changed to something like "Error: x.length is a
 special property that prohibits the use of the increment (++) and
 add_and_assign (+=) operators".

 Thanks,
 Erik Lechak

Length property of the array is not a member variable, but rather a member function:

When I compile this: import std.stdio; void main(){ int x[23]; writefln(x.length()); } I get this: Error: undefined identifier length Error: function expected before (), not length of type int So the compiler is telling me length is of type int.
 int[] array = new int[42];
 assert(array.length() == 42);

This does not compile.
 but you can also omit paranthesis (that's merely a syntax sugar):

It's not syntactic sugar if it does not compile with the parens.
 assert(array.length == 42);

Yep, this works, but it does not show that array.length is a method/function.
 The same way the following:
 array.length = 100

 is translated into a function call: array.length(100); which does array
 resizing.

Ok. Maybe it gets translated into a method call. But that does not mean that array.length is a method. It sounds more like a tied variable in perl.
 Note that you should normally call array.length(array.length() + 1)

I would love to do that because it makes sense. But it does not compile.
 D *could* do the following trick:
 array.length()+=1 -> array.length(array.length() + 1);

array.length(array.length() + 1) is not a trick. It is logical.
 but it would break too much of the existing code and makes a little of
 sense.

It would break code but it would make sense at least to me:) So I either have to look at properties as methods that are called without parens or integers that restrict my use of operators. That's a bummer. Thanks, Erik Lechak

You missed the P.S. section. Actually, I knew it doesn't compile while posting, but posted anyway because even though it doesn't compile, it is subject to the same rule. Array's `length` is a built-in property, not an int. Can an array capacity increase upon integer assignment :) Properties are methods. Methods can be called with or without parens (except bult-in ones, like length, stringof, etc. Those are called without).
Jun 18 2008
prev sibling parent jcc7 <technocrat7 gmail.com> writes:
== Quote from Erik Lechak (prochak netzero.net)'s article
...
 I ran into my first WTF moment with D.  I spent way too much time figuring out

 This is a newsgroup entry describing the problem:

 Is there a document detailing these "special exceptions" so that I
 don't have to blindly stumble upon them?  If not are there any more
 that should be documented so that I can add them to my Wiki
(http://www.lechak.info/wiki/index.php?title=D_Programming_Language)?

Perhaps this is what you're looking for... http://www.prowiki.org/wiki4d/wiki.cgi?ErrorMessages
Jun 19 2008