www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Using unary expressions with property functions

reply Andrej Mitrovic <none none.com> writes:
So I was a bit surprised today to find out that this sample C# code works:

class LibraryItem
{
    private int _numCopies;

    // Property
    public int NumCopies
    {
        get { return _numCopies; }
        set { _numCopies = value; }
    }
    
    public void BorrowItem(string name)
    {
        NumCopies--;
    }  
}

Apparently you can use the -- and ++ unary ops on property functions, which
might be convenient, I guess. But this won't work in D:

class LibraryItem
{
    private int _numCopies;

     property
    int NumCopies()
    {
        return _numCopies;
    }
    
     property
    void NumCopies(int value)
    {
        _numCopies = value;
    }
    
    public void BorrowItem(string name)
    {
        NumCopies--;
    }
}

void main()
{
}

I get this back: Error: this.NumCopies() is not an lvalue

So D tries to call the getter method "int NumCopies()" and apply -- on it. One
way around this is to make the getter method return by reference:

import std.stdio;

class LibraryItem
{
    private int _numCopies;

     property
    ref int NumCopies()
    {
        return _numCopies;
    }
    
     property
    void NumCopies(int value)
    {
        _numCopies = value;
    }
    
    public void BorrowItem(string name)
    {
        NumCopies--;
        writeln(NumCopies);     // writes -1 after the call
    }
}

void main()
{
    auto lib = new LibraryItem();
    lib.BorrowItem("TDPL");
}

So this works. But now the getter method acts both as a getter and a setter,
which contradicts the idea of having separate get/set methods, don't you agree?

I'm not sure how C# works. Does it use the getter method and return a reference
for the -- op like in the last D example, or does it rewrite the whole
operation as "NumCopies(-1)"? Maybe we can have a functionality like that in D
without having to change the getter method to return a reference.. What do you
think?
Dec 13 2010
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, December 13, 2010 11:10:55 Andrej Mitrovic wrote:
 So I was a bit surprised today to find out that this sample C# code works:
 
 class LibraryItem
 {
     private int _numCopies;
 
     // Property
     public int NumCopies
     {
         get { return _numCopies; }
         set { _numCopies = value; }
     }
 
     public void BorrowItem(string name)
     {
         NumCopies--;
     }
 }
 
 Apparently you can use the -- and ++ unary ops on property functions, which
 might be convenient, I guess. But this won't work in D:
 
 class LibraryItem
 {
     private int _numCopies;
 
      property
     int NumCopies()
     {
         return _numCopies;
     }
 
      property
     void NumCopies(int value)
     {
         _numCopies = value;
     }
 
     public void BorrowItem(string name)
     {
         NumCopies--;
     }
 }
 
 void main()
 {
 }
 
 I get this back: Error: this.NumCopies() is not an lvalue
 
 So D tries to call the getter method "int NumCopies()" and apply -- on it.
 One way around this is to make the getter method return by reference:
 
 import std.stdio;
 
 class LibraryItem
 {
     private int _numCopies;
 
      property
     ref int NumCopies()
     {
         return _numCopies;
     }
 
      property
     void NumCopies(int value)
     {
         _numCopies = value;
     }
 
     public void BorrowItem(string name)
     {
         NumCopies--;
         writeln(NumCopies);     // writes -1 after the call
     }
 }
 
 void main()
 {
     auto lib = new LibraryItem();
     lib.BorrowItem("TDPL");
 }
 
 So this works. But now the getter method acts both as a getter and a
 setter, which contradicts the idea of having separate get/set methods,
 don't you agree?
 
 I'm not sure how C# works. Does it use the getter method and return a
 reference for the -- op like in the last D example, or does it rewrite the
 whole operation as "NumCopies(-1)"? Maybe we can have a functionality like
 that in D without having to change the getter method to return a
 reference.. What do you think?

I would think that it would be doable if something ++lib.NumCopies were lowered to lib.NumCopies(++lib.NumCopies()). If it were post-increment, it would then probably turn it into something more like this: auto toInc = lib.NumCopies(); auto temp = toInc; lib.NumCopies(++toInc); Of course, given that you could use pre and post-increment in the middle of an expression, that could get quite a bit more complicated, and a simple lowering could be rather difficult, but the basic idea should still hold. I don't see why it couldn't be done other than that figuring out the exact way to lower it in order to deal with the fact that it could be in the middle of an expression could be a bit entertaining. I say open an enhancement request for it. Perhaps someone else can point out why it would be a bad idea, but on the surface, it seems quite doable. - Jonathan M Davis
Dec 13 2010
prev sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 13 Dec 2010 14:29:34 -0500, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:
 On Monday, December 13, 2010 11:10:55 Andrej Mitrovic wrote:
 So I was a bit surprised today to find out that this sample C# code  
 works:

 class LibraryItem
 {
     private int _numCopies;

     // Property
     public int NumCopies
     {
         get { return _numCopies; }
         set { _numCopies = value; }
     }

     public void BorrowItem(string name)
     {
         NumCopies--;
     }
 }

 Apparently you can use the -- and ++ unary ops on property functions,  
 which
 might be convenient, I guess. But this won't work in D:

 class LibraryItem
 {
     private int _numCopies;

      property
     int NumCopies()
     {
         return _numCopies;
     }

      property
     void NumCopies(int value)
     {
         _numCopies = value;
     }

     public void BorrowItem(string name)
     {
         NumCopies--;
     }
 }

 void main()
 {
 }

 I get this back: Error: this.NumCopies() is not an lvalue

 So D tries to call the getter method "int NumCopies()" and apply -- on  
 it.
 One way around this is to make the getter method return by reference:

 import std.stdio;

 class LibraryItem
 {
     private int _numCopies;

      property
     ref int NumCopies()
     {
         return _numCopies;
     }

      property
     void NumCopies(int value)
     {
         _numCopies = value;
     }

     public void BorrowItem(string name)
     {
         NumCopies--;
         writeln(NumCopies);     // writes -1 after the call
     }
 }

 void main()
 {
     auto lib = new LibraryItem();
     lib.BorrowItem("TDPL");
 }

 So this works. But now the getter method acts both as a getter and a
 setter, which contradicts the idea of having separate get/set methods,
 don't you agree?

 I'm not sure how C# works. Does it use the getter method and return a
 reference for the -- op like in the last D example, or does it rewrite  
 the
 whole operation as "NumCopies(-1)"? Maybe we can have a functionality  
 like
 that in D without having to change the getter method to return a
 reference.. What do you think?

I would think that it would be doable if something ++lib.NumCopies were lowered to lib.NumCopies(++lib.NumCopies()). If it were post-increment, it would then probably turn it into something more like this: auto toInc = lib.NumCopies(); auto temp = toInc; lib.NumCopies(++toInc); Of course, given that you could use pre and post-increment in the middle of an expression, that could get quite a bit more complicated, and a simple lowering could be rather difficult, but the basic idea should still hold. I don't see why it couldn't be done other than that figuring out the exact way to lower it in order to deal with the fact that it could be in the middle of an expression could be a bit entertaining. I say open an enhancement request for it. Perhaps someone else can point out why it would be a bad idea, but on the surface, it seems quite doable. - Jonathan M Davis

I know this concept has been extensively discussed before, i.e. the problem of a.b.c.d = 1, when b, c or d happen to be a method/property.
Dec 14 2010