digitalmars.D.learn - Question about operations on class/struct properties
- Uranuz (32/32) Aug 18 2014 I think there is something that I don't understand about concept
- anonymous (7/18) Aug 18 2014 This comes up every once in a while. I don't know if there are
- Phil Lavoie (17/17) Aug 18 2014 All you said makes sense. If there is a direct connection between
I think there is something that I don't understand about concept
of *properties*. I thing that property is sort of object
attribute that belongs to it. Currently property considered as
two functions: *get* and/or *set*. So we can do two sort of
operations on concept that called *property*: *assign to it* and
*read it*. If property doesn't return reference value all other
manipulations are forbidden. A will illustrate it with example:
import std.datetime, std.stdio;
void main()
{
auto date = Date(1991, 5, 7);
//date.day += 5; //Not working
//date.day++; //Not working
date.day = date.day + 1;
}
Because day property is of ubyte (not reference) type, we can
only read it into some other variable or assign to it, but other
other operations couldn't be done.
It is a common case when I want to increment, decrement or using
some other 'op=' - operation, but it is not working and I get
compile-time error. I always was thinking that
date.day++;
date.day -= 5;
Should be treated as:
date.day = date.day + 1;
date.day = date.day - 5;
if the were not oveloaded. So if we have get and set property
methods I see that it could be calculated and this should working.
Of course I can define return value of get property as *ref* but
in this case I don't understand how I should use it with *setter*
method.
It's interesting to see any thinkings about it.
Aug 18 2014
On Monday, 18 August 2014 at 15:35:26 UTC, Uranuz wrote:date.day++; date.day -= 5; Should be treated as: date.day = date.day + 1; date.day = date.day - 5; if the were not oveloaded. So if we have get and set property methods I see that it could be calculated and this should working.This comes up every once in a while. I don't know if there are any subtle problems, or if it's just that no one's found the time to implement it.Of course I can define return value of get property as *ref* but in this case I don't understand how I should use it with *setter* method.When you return a mutable reference, a setter doesn't make all that much sense, as it can easily be circumvented, even accidentally.
Aug 18 2014
All you said makes sense. If there is a direct connection between
getter, setter and member than yes, returning it by reference is
usually more convenient:
private T _member;
property ref inout(T) member() inout {return _member;}
However, sometimes, there is no direct connection between field
and mutators. Sometimes, it is calculated on the fly.
Date {
...
property auto hour() {return magic / someNumber;}
property void hour(int newHour) {//complicated algorithm to set
the hour.}
}
Now, assuming we have these two mutators, operators could be
automagically implemented.
Date myDate;
myDate.hour += 4; //myDate.hour(myDate.hour() + 4)
Aug 18 2014
On Monday, 18 August 2014 at 18:07:09 UTC, Phil Lavoie wrote:
All you said makes sense. If there is a direct connection
between getter, setter and member than yes, returning it by
reference is usually more convenient:
private T _member;
property ref inout(T) member() inout {return _member;}
However, sometimes, there is no direct connection between field
and mutators. Sometimes, it is calculated on the fly.
Yes. As you said often it calculated on the fly. And sometimes
when setting some value you need to trigger some *event handler*.
This is one of use cases that properties were designed in
different languages. Another case is to check value and throw
exception or something else. So using getter that returns
reference is very close to just exposing class/ struct field and
allowing to modify it directly. I think that *setter* should
shadow *ref getter* in opAssign and opOpAssign expressions. And
opOpAssign should rewrite into *read -> execute operation ->
write* sequence.
Also I have another interesting question. For example I have some
struct (value object) that has method, that modifies it's state.
Then I declare some class/ struct that has property of value type.
Problem is that logically I could expect that this method should
modify property of class, but instead some value return from
property method returned (by value) and then it is was modified.
I'll give short illustration.
struct PropType
{
}
Aug 18 2014
I posted it suddenly. I don't know why.I'll give short illustration.struct PropType { void append(int value) { //implementation } } class Test { PropType myProp() property { return _propValue; } private PropType _propValue; } void main() { Test test = new Test; //This line looks like I want to append value //to field of *test* object. But it cant't modify //it and just doing useless job. test.myProp.append(10); } I don't know intentions of language designers in part of properties. But in this code I see some logical contradiction. What I see and thinking of this line of code it is not what it really does. I don't know much about properties behaviour in different languages but there is something that confuses me. I believe that this problem deserves more attention. There are 5 DIP's in dlang wiki. So I think it's important
Aug 18 2014
I have another similar example illustrating this problem at
semantic level.
import std.stdio, std.typecons;
struct Test
{
//ref
Nullable!int prop() property
{
return _value;
}
private Nullable!int _value = 10;
}
void main()
{
auto test = Test();
//This looks like I want to modify property with *nullify*,
//but instead it creates variable that will never be used and
modify it
test.prop.nullify();
assert( test.prop.isNull ); //This fails
}
So when using with value types I should always look if property
is *ref* or not and it's not very good.
I have another question. How could I implement in this example if
I uncomment it to call some function after modifying property? Do
I need some sort of class wrapper for property or is there some
other ideas?
What I expect:
void main()
{
auto test = Test();
test.prop.nullify();
//Callback called after this operation
test.prop = 15;
//Callback called after this operation too
}
Callback is simple method of Test like:
void callback(Nullable!int value)
{
if( value.isNull )
//Do smth
else if( value <= 0 )
//Do smth else
else //Just assign to internal field
_value = value;
}
So I think it is possible to do this with some class wrapper
around Nullable!int that should implement al of it's methods or
for example dispatching calls to them via opDispacth. But this
approach looks slightly complicated. What if I have complicated
interface (for example std.datetime.Date as such property) so I
need to reimplement or dispatch a lot of methods.
Could you advise another more simple approach to this problem?
Aug 19 2014









"anonymous" <anonymous example.com> 