www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Error: xxx is not an lvalue

reply flourish <t.spam gmx.de> writes:
Hi,

why does the following code not compile -- or how to declare a (usable)
property of an associative array field?

//////////////////////
class Test
{
  private int[int] _testMap;
  public int[int] testMap() {return _testMap;}
}


void main()
{
  Test test = new Test();
  test.testMap[0] = 1;
}
/////////////////

*** Error: test.testMap() is not an lvalue


Regards,
    flourish
May 02 2009
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
On 02.05.2009 20:44, flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
    private int[int] _testMap;
    public int[int] testMap() {return _testMap;}
 }


 void main()
 {
    Test test = new Test();
    test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue
test.testMap()[0] = 1;
May 02 2009
next sibling parent flourish <t.spam gmx.de> writes:
Thanks for your reply,

but I get the same error when using:

test.testMap()[0] = 1;
May 02 2009
prev sibling parent flourish <t.spam gmx.de> writes:
Thanks for your reply,

but I get the same error when using:

test.testMap()[0] = 1;


== Quote from dennis luehring (dl.soluz gmx.net)'s article
 On 02.05.2009 20:44, flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
    private int[int] _testMap;
    public int[int] testMap() {return _testMap;}
 }


 void main()
 {
    Test test = new Test();
    test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue
test.testMap()[0] = 1;
May 02 2009
prev sibling next sibling parent "Tyro[a.c.edwards]" <nospam home.com> writes:
On 5/3/2009 3:44 AM, flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
    private int[int] _testMap;
    public int[int] testMap() {return _testMap;}
public void opIndexAssign(int val, int ndx){ _testMap[ndx] = val; }
 }
testMap() is a getter and can only return the value it is designed to. You must implement a setter to accomplish what you are trying to do. Unfortunately I'm not sure how to do it with AAs so I'll leave the details to someone that's a little smarter than I. I think that maybe implementing opIndexAssign might do the trick though. See modifications to Test and main().
 void main()
 {
    Test test = new Test();
//test.testMap[0] = 1; // Error: getters cannot be assigned to test[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue


 Regards,
      flourish
May 02 2009
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 03 May 2009 01:02:41 +0400, Tyro[a.c.edwards] <nospam home.com> wrote:

 On 5/3/2009 3:44 AM, flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
    private int[int] _testMap;
    public int[int] testMap() {return _testMap;}
 }
testMap() is a getter and can only return the value it is designed to. You must implement a setter to accomplish what you are trying to di. Unfortunately I'm not sure how you do that with AAs so I'll leave that to someone that's a little smarter than I. I think that maybe implementing opIndexAssign might work for you though: public void opIndexAssign(int val, int ndx){ _testMap[ndx] = val; } Then you can simply "test[0] = 1;" to get the desired effect.
 void main()
 {
    Test test = new Test();
    test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue


 Regards,
      flourish
No, you are wrong, testMap works like a property here. I believe, original code _should_ work. For example, it works if you replace int[int] with int[]. All the trouble is because of an awful properties implementation in D, and temporaries not being able to be passed by reference: struct Foo { private int[] _arr; int[] arr() { return _arr; } } void doSomething(int[] a) { } void doSomethingElse(ref int[] a) { } void doSomethingElseConst(ref const(int)[] a) { } void main() { Foo foo; foo.arr[0] = 1; // works //foo.arr.length = 1; // doesn't foo.arr().doSomething(); // works //foo.arr.doSomething(); // doesn't //foo.arr().doSomethingElse(); // doesn't //foo.arr().doSomethingElseConst(); // doesn't }
May 02 2009
parent "Tyro[a.c.edwards]" <nospam home.com> writes:
On 5/3/2009 6:36 AM, Denis Koroskin wrote:
 On Sun, 03 May 2009 01:02:41 +0400, Tyro[a.c.edwards] <nospam home.com>
 wrote:

 On 5/3/2009 3:44 AM, flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
 private int[int] _testMap;
 public int[int] testMap() {return _testMap;}
 }
testMap() is a getter and can only return the value it is designed to. You must implement a setter to accomplish what you are trying to di. Unfortunately I'm not sure how you do that with AAs so I'll leave that to someone that's a little smarter than I.
[...]
 No, you are wrong, testMap works like a property here. I believe,
 original code _should_ work. For example, it works if you replace
 int[int] with int[].
 All the trouble is because of an awful properties implementation in D,
 and temporaries not being able to be passed by reference:
Thanks for the clarification.
May 02 2009
prev sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
This code works fine (D 2.x only):

class Test
{
   private int[int] _testMap;
   public ref int[int] testMap() {return _testMap;}
}

void main()
{
   Test test = new Test();
   test.testMap[0] = 1;
}

Note the "ref".  Otherwise, a value is returned which is not modifiable. 
  This will also fix test.array.length.  Nothing wrong here, no creepy 
bad temporary property problems.

I suppose you could also try returning a pointer to an associative array 
(e.g. with &) in D 1.x.

-[Unknown]


flourish wrote:
 Hi,
 
 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?
 
 //////////////////////
 class Test
 {
   private int[int] _testMap;
   public int[int] testMap() {return _testMap;}
 }
 
 
 void main()
 {
   Test test = new Test();
   test.testMap[0] = 1;
 }
 /////////////////
 
 *** Error: test.testMap() is not an lvalue
 
 
 Regards,
     flourish
 
 
 
May 03 2009
next sibling parent reply "Tyro[a.c.edwards]" <nospam home.com> writes:
On 5/3/2009 6:25 PM, Unknown W. Brackets wrote:
 This code works fine (D 2.x only):

 class Test
 {
 private int[int] _testMap;
 public ref int[int] testMap() {return _testMap;}
 }

 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }

 Note the "ref". Otherwise, a value is returned which is not modifiable.
 This will also fix test.array.length. Nothing wrong here, no creepy bad
 temporary property problems.
Is this an intended or even desirable "feature" of the language or just something that happens to work in D 2.x? I ask because to the untrained eye, it is unclear exactly what is happening. There is nothing to inform me that _testMap can be modified from outside the class. Even with "ref" there it doesn't make it any clearer. Matter of fact, I just had a problem in Phobos 2 where a function was defined like that and I had to comment out the "ref" for it to work. Kept telling me that some array was not an lvalue. The minute I commented out the "ref", everything worked like a charm. Also it makes more sense to me to have separate functions as getters and setters. Maybe that's only because I lacking proper training in the art of computer programming though.
 I suppose you could also try returning a pointer to an associative array
 (e.g. with &) in D 1.x.

 -[Unknown]

 flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
 private int[int] _testMap;
 public int[int] testMap() {return _testMap;}
 }


 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue


 Regards,
 flourish
May 03 2009
parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
Well, if you really want a "protected" associative array, or array for 
that matter, you probably should define a wrapper class that inlines the 
access you're willing to allow.

 From a basic perspective, _testMap is a structure of data.  Although it 
is private, there's no reason it can't be modified through an accessor.

Without a setter, the only thing that should fail is test.testMap = 
something.  Requiring a setter for any minor change makes no sense.

Compare it to this: if you have a class that has a member object (e.g. a 
User with a Socket member variable), should it be necessary to have a 
setter to change the Socket?  Can't the Socket handle its own 
private/public-ness?

Arrays and associative arrays are the same, except that the members you 
use are public.

-[Unknown]


Tyro[a.c.edwards] wrote:
 On 5/3/2009 6:25 PM, Unknown W. Brackets wrote:
 This code works fine (D 2.x only):

 class Test
 {
 private int[int] _testMap;
 public ref int[int] testMap() {return _testMap;}
 }

 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }

 Note the "ref". Otherwise, a value is returned which is not modifiable.
 This will also fix test.array.length. Nothing wrong here, no creepy bad
 temporary property problems.
Is this an intended or even desirable "feature" of the language or just something that happens to work in D 2.x? I ask because to the untrained eye, it is unclear exactly what is happening. There is nothing to inform me that _testMap can be modified from outside the class. Even with "ref" there it doesn't make it any clearer. Matter of fact, I just had a problem in Phobos 2 where a function was defined like that and I had to comment out the "ref" for it to work. Kept telling me that some array was not an lvalue. The minute I commented out the "ref", everything worked like a charm. Also it makes more sense to me to have separate functions as getters and setters. Maybe that's only because I lacking proper training in the art of computer programming though.
 I suppose you could also try returning a pointer to an associative array
 (e.g. with &) in D 1.x.

 -[Unknown]

 flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
 private int[int] _testMap;
 public int[int] testMap() {return _testMap;}
 }


 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue


 Regards,
 flourish
May 03 2009
parent reply "Tyro[a.c.edwards]" <nospam home.com> writes:
On 5/3/2009 8:17 PM, Unknown W. Brackets wrote:
 Well, if you really want a "protected" associative array, or array for
 that matter, you probably should define a wrapper class that inlines the
 access you're willing to allow.

  From a basic perspective, _testMap is a structure of data. Although it
 is private, there's no reason it can't be modified through an accessor.

 Without a setter, the only thing that should fail is test.testMap =
 something. Requiring a setter for any minor change makes no sense.
I was following until now... If I can modify said private member at a whim, why on earth would I prevent this case? Is this because I would be assigning it a completely new value vice simply modifying its content? If that is the case, am I correct in saying that this characteristic is applicable only to arrays?
 Compare it to this: if you have a class that has a member object (e.g. a
 User with a Socket member variable), should it be necessary to have a
 setter to change the Socket? Can't the Socket handle its own
 private/public-ness?

 Arrays and associative arrays are the same, except that the members you
 use are public.

 -[Unknown]
Got you... I think I understand. That being the case though, wouldn't it be just as useful to build the same "accessor" capability into opAssign such that you can: class Foo { private sometype _data; public ref typeof(_data) opAssign() { return _data; } } Foo b = new foo; b[0] = 1; Why is it necessary to have a separate/different "accessor" function?
 Tyro[a.c.edwards] wrote:
 On 5/3/2009 6:25 PM, Unknown W. Brackets wrote:
 This code works fine (D 2.x only):

 class Test
 {
 private int[int] _testMap;
 public ref int[int] testMap() {return _testMap;}
 }

 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }

 Note the "ref". Otherwise, a value is returned which is not modifiable.
 This will also fix test.array.length. Nothing wrong here, no creepy bad
 temporary property problems.
Is this an intended or even desirable "feature" of the language or just something that happens to work in D 2.x? I ask because to the untrained eye, it is unclear exactly what is happening. There is nothing to inform me that _testMap can be modified from outside the class. Even with "ref" there it doesn't make it any clearer. Matter of fact, I just had a problem in Phobos 2 where a function was defined like that and I had to comment out the "ref" for it to work. Kept telling me that some array was not an lvalue. The minute I commented out the "ref", everything worked like a charm. Also it makes more sense to me to have separate functions as getters and setters. Maybe that's only because I lacking proper training in the art of computer programming though.
 I suppose you could also try returning a pointer to an associative array
 (e.g. with &) in D 1.x.

 -[Unknown]

 flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
 private int[int] _testMap;
 public int[int] testMap() {return _testMap;}
 }


 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue


 Regards,
 flourish
May 03 2009
parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
You can do that something similar to that, sure.

But, you'd be implementing a class and doing an opIndexAssign.  That's 
totally different from just returning the associative array outright.

What you'd do to make a non-modifyable array is this:

class Foo(T)
{
    private T[] data;
    public ref T opIndex(int i)
    {
       return this.data[i];
    }
/*
    public ref T opIndexAssign(int i, T val)
    {
       // Do some sort of validation.
       this.data[i] = val;
       return this.data[i];
    }
*/
}

But, maybe you want the associative array to be modifiable?  For 
example, I have an XPath library, and in it I just have a namespaces 
member.  I place no logic on this, so the interface to add namespaces is 
as simple as modifying the associative array (e.g. .namespaces["xhtml"] 
= "http://www.w3.org/1999/xhtml".)

You have the control to do either one.  But, a member being private just 
means the user of the class cannot access the member *though that method 
or means*.  It does not affect the data, it doesn't make it special or 
non-modifiable, and it shouldn't.

As to your other question - there are good reasons for that.  For 
example, suppose I had a database class.  If I have an instance of the 
database connection as a member of the result class, I don't mind if you 
modify the connection through that member variable.

However, if you were to reassign the member (e.g. = new DBConnection()), 
that wouldn't make sense and could cause me serious problems.  The 
connection class can manage what parts of it you can modify or not, so 
as long as I force you to use the one I already have, I'm safe.

-[Unknown]


Tyro[a.c.edwards] wrote:
 On 5/3/2009 8:17 PM, Unknown W. Brackets wrote:
 Well, if you really want a "protected" associative array, or array for
 that matter, you probably should define a wrapper class that inlines the
 access you're willing to allow.

  From a basic perspective, _testMap is a structure of data. Although it
 is private, there's no reason it can't be modified through an accessor.

 Without a setter, the only thing that should fail is test.testMap =
 something. Requiring a setter for any minor change makes no sense.
I was following until now... If I can modify said private member at a whim, why on earth would I prevent this case? Is this because I would be assigning it a completely new value vice simply modifying its content? If that is the case, am I correct in saying that this characteristic is applicable only to arrays?
 Compare it to this: if you have a class that has a member object (e.g. a
 User with a Socket member variable), should it be necessary to have a
 setter to change the Socket? Can't the Socket handle its own
 private/public-ness?

 Arrays and associative arrays are the same, except that the members you
 use are public.

 -[Unknown]
Got you... I think I understand. That being the case though, wouldn't it be just as useful to build the same "accessor" capability into opAssign such that you can: class Foo { private sometype _data; public ref typeof(_data) opAssign() { return _data; } } Foo b = new foo; b[0] = 1; Why is it necessary to have a separate/different "accessor" function?
 Tyro[a.c.edwards] wrote:
 On 5/3/2009 6:25 PM, Unknown W. Brackets wrote:
 This code works fine (D 2.x only):

 class Test
 {
 private int[int] _testMap;
 public ref int[int] testMap() {return _testMap;}
 }

 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }

 Note the "ref". Otherwise, a value is returned which is not modifiable.
 This will also fix test.array.length. Nothing wrong here, no creepy bad
 temporary property problems.
Is this an intended or even desirable "feature" of the language or just something that happens to work in D 2.x? I ask because to the untrained eye, it is unclear exactly what is happening. There is nothing to inform me that _testMap can be modified from outside the class. Even with "ref" there it doesn't make it any clearer. Matter of fact, I just had a problem in Phobos 2 where a function was defined like that and I had to comment out the "ref" for it to work. Kept telling me that some array was not an lvalue. The minute I commented out the "ref", everything worked like a charm. Also it makes more sense to me to have separate functions as getters and setters. Maybe that's only because I lacking proper training in the art of computer programming though.
 I suppose you could also try returning a pointer to an associative 
 array
 (e.g. with &) in D 1.x.

 -[Unknown]

 flourish wrote:
 Hi,

 why does the following code not compile -- or how to declare a 
 (usable)
 property of an associative array field?

 //////////////////////
 class Test
 {
 private int[int] _testMap;
 public int[int] testMap() {return _testMap;}
 }


 void main()
 {
 Test test = new Test();
 test.testMap[0] = 1;
 }
 /////////////////

 *** Error: test.testMap() is not an lvalue


 Regards,
 flourish
May 03 2009
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 May 2009 05:25:09 -0400, Unknown W. Brackets  
<unknown simplemachines.org> wrote:

 This code works fine (D 2.x only):

 class Test
 {
    private int[int] _testMap;
    public ref int[int] testMap() {return _testMap;}
 }

 void main()
 {
    Test test = new Test();
    test.testMap[0] = 1;
 }

 Note the "ref".  Otherwise, a value is returned which is not modifiable.  
   This will also fix test.array.length.  Nothing wrong here, no creepy  
 bad temporary property problems.
The original code should work, this is a problem. An AA is not a value type. -Steve
May 04 2009
parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
I've always though of arrays and associative arrays as structs (which 
really is what they are.)  Thinking that way, this behavior makes exact 
sense - down to .length being unchangeable and associative arrays being 
unchangeable.

I mean, you wouldn't want to make it work the way you suggest by making 
arrays and associative arrays simply pointers to their current structs 
(just like a class would be.)  You could make such a class easily 
yourself, anyway.

If you are right, I guess the right solution would be to make the ref 
implicit when returning (or, I suppose, passing?) such arrays and 
associative arrays.  But that seems wrong to me too, and wouldn't come 
free (speaking of efficiency) either.

-[Unknown]


Steven Schveighoffer wrote:
 On Sun, 03 May 2009 05:25:09 -0400, Unknown W. Brackets 
 <unknown simplemachines.org> wrote:
 
 This code works fine (D 2.x only):

 class Test
 {
    private int[int] _testMap;
    public ref int[int] testMap() {return _testMap;}
 }

 void main()
 {
    Test test = new Test();
    test.testMap[0] = 1;
 }

 Note the "ref".  Otherwise, a value is returned which is not 
 modifiable.   This will also fix test.array.length.  Nothing wrong 
 here, no creepy bad temporary property problems.
The original code should work, this is a problem. An AA is not a value type. -Steve
May 04 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 04 May 2009 14:53:41 -0400, Unknown W. Brackets  
<unknown simplemachines.org> wrote:

 I've always though of arrays and associative arrays as structs (which  
 really is what they are.)  Thinking that way, this behavior makes exact  
 sense - down to .length being unchangeable and associative arrays being  
 unchangeable.

 I mean, you wouldn't want to make it work the way you suggest by making  
 arrays and associative arrays simply pointers to their current structs  
 (just like a class would be.)  You could make such a class easily  
 yourself, anyway.

 If you are right, I guess the right solution would be to make the ref  
 implicit when returning (or, I suppose, passing?) such arrays and  
 associative arrays.  But that seems wrong to me too, and wouldn't come  
 free (speaking of efficiency) either.

 -[Unknown]
The underlying struct of an AA is: struct AA { AA_Implementation *impl; } or something like that ;) Look at the D runtime source. But in any case, if you return an array slice, would you not want to be able to update an element of the slice? I think there is a difference between a value struct (where all internals are non-reference types), and a reference struct (where at least one element is a reference type). A reference struct should be able to pass those references to other functions without having to be ref'd. It forces non-transparent type wrapping if that isn't the case. I should be able to replace a reference or pointer type with a wrapper struct where I can modify the interface, and it should be transparent that I have done so (except for the interface changes of course). I think this is one of the goals D2 is working towards. It makes sense that a value struct or the value types inside a reference struct (i.e. the length of an array) should not be changeable as rvalues, since you aren't going to use them later. Both arrays (as the current implementation) and AA's are reference structs. -Steve
May 04 2009
parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
If that's the structure, then yes, I agree.

Long time ago (before D 1.x?) I looked at the associative array 
implementation and it was a struct with a few members.  I didn't realize 
it had changed.  Or maybe I'm just remembering wrong.

-[Unknown]


Steven Schveighoffer wrote:
 On Mon, 04 May 2009 14:53:41 -0400, Unknown W. Brackets 
 <unknown simplemachines.org> wrote:
 
 I've always though of arrays and associative arrays as structs (which 
 really is what they are.)  Thinking that way, this behavior makes 
 exact sense - down to .length being unchangeable and associative 
 arrays being unchangeable.

 I mean, you wouldn't want to make it work the way you suggest by 
 making arrays and associative arrays simply pointers to their current 
 structs (just like a class would be.)  You could make such a class 
 easily yourself, anyway.

 If you are right, I guess the right solution would be to make the ref 
 implicit when returning (or, I suppose, passing?) such arrays and 
 associative arrays.  But that seems wrong to me too, and wouldn't come 
 free (speaking of efficiency) either.

 -[Unknown]
The underlying struct of an AA is: struct AA { AA_Implementation *impl; } or something like that ;) Look at the D runtime source. But in any case, if you return an array slice, would you not want to be able to update an element of the slice? I think there is a difference between a value struct (where all internals are non-reference types), and a reference struct (where at least one element is a reference type). A reference struct should be able to pass those references to other functions without having to be ref'd. It forces non-transparent type wrapping if that isn't the case. I should be able to replace a reference or pointer type with a wrapper struct where I can modify the interface, and it should be transparent that I have done so (except for the interface changes of course). I think this is one of the goals D2 is working towards. It makes sense that a value struct or the value types inside a reference struct (i.e. the length of an array) should not be changeable as rvalues, since you aren't going to use them later. Both arrays (as the current implementation) and AA's are reference structs. -Steve
May 04 2009
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 04 May 2009 16:28:06 -0400, Unknown W. Brackets  
<unknown simplemachines.org> wrote:

 If that's the structure, then yes, I agree.

 Long time ago (before D 1.x?) I looked at the associative array  
 implementation and it was a struct with a few members.  I didn't realize  
 it had changed.  Or maybe I'm just remembering wrong.
You had me doubting myself ;) So I looked it up From the aaA.d file (of dmd 1.043): struct aaA { aaA *left; aaA *right; hash_t hash; /* key */ /* value */ } struct BB { aaA*[] b; size_t nodes; // total number of aaA nodes } /* This is the type actually seen by the programmer, although * it is completely opaque. */ struct AA { BB* a; } -Steve
May 04 2009