preparing for const, final, and invariant
Daniel Keep
daniel.keep.lists at gmail.com
Fri May 18 04:45:17 PDT 2007
Aarti_pl wrote:
> Daniel Keep pisze:
>>
>> Aarti_pl wrote:
>>> I want to ask about something opposite to above example...
>>>
>>> Will it be possible to pass ownership of object? I mean that when you
>>> pass object by reference to function/class/member variable you can still
>>> modify this object from outside of function/class. It breaks
>>> encapsulation in program.
>>>
>>> Example:
>>>
>>> import std.stdio;
>>> public class TestX {
>>> char[] value;
>>> char[] toString() {
>>> return value;
>>> }
>>> }
>>> public class TestMain {
>>> TestX x;
>>> }
>>>
>>> void main(char[][] args) {
>>> TestX parameter = new TestX();
>>> parameter.value = "First assignment";
>>>
>>> TestMain tmain = new TestMain();
>>> tmain.x = parameter;
>>>
>>> parameter.value = "Second assignment";
>>> writefln(tmain.x);
>>> }
>>>
>>> Notice that tmain.x value has changed although I would like just to set
>>> once, and have second assignment to parameter illegal... When using
>>> setters and getters problem is even more visible....
>>>
>>> How to achieve proper behavior with new final/const/invariant/scope??
>>>
>>> Regards
>>> Marcin Kuszczak
>>> (aarti_pl)
>>
>> I don't think the new const, final & invariant are going to help you
>> any. Basically, you seem to be complaining that reference semantics
>> are... well, reference semantics.
>>
>> That's like complaining that water is wet :P
>>
>
> The problem here is that current behavior breaks encapsulation - you can
> change already passed value from outside of object, when contract is
> that you can set it only with setter. Imagine consequences in
> multithreaded application, when in the middle of function your data
> suddenly change... But also with single threaded application it can be
> real problem when you change referenced object by mistake.
>
> So it is more like complaining that water is dry when it should be wet
> in fact :-)
>
> I know that other languages also have same problem, but I think that D
> can do better.
Ok: so the problem is that because D's class system doesn't have a
concept of ownership, encapsulation can be violated. That said, I've
never seen an OO language that *did* have a concept of ownership, so I
don't know what we could do to "fix" it :P
>> There's a few things I can think of to get the behaviour you want.
>>
>> 1. Use a write-once setter for 'value'. You can either create a
>> nullable template, or use a flag to ensure external code can only set it
>> once.
>>
>
> Could you please give example? I don't know how to achieve this behavior
> with this method...
class TestX
{
private
{
char[] _value;
bool _value_set = false;
}
char[] value(char[] v)
{
if( _value_set )
assert(false, "cannot set value more than once!");
_value = v;
_value_set = true;
return v;
}
char[] value()
{
return _value;
}
}
>> 1.a. A "nicer" approach would be to set it in the constructor, and then
>> either mark it "final" (with the new final), or only write a public
>> getter function.
>
> I think that rather invariant? Final will not disallow changing of
> referenced object. And I am afraid that it won't help anyway, it would
> be still possible to change value from outside... Using only getter and
> passing reference in constructor also doesn't help. You can still also
> modify variable from outside...
Since D2.0 hasn't been released yet, I don't know for certain, but I
would hope it would be possible to create a final invariant member. In
this case, you can assign to it *only* during the constructor, and you
can only assign something to it which will never change.
But then, I'm not sure if that would really work or not.
>>
>> 2. Use a struct instead; no references, no indirect changes.
>>
>
> Ok. I didn't think about it. But it is basically same as below, so
> please see comment below. Probably you have also problem when struct has
> references inside...
Mmm.
>> 3. Take a private copy of the object by writing a .dup method.
>>
>
> Yes that is possible solution, but program would be much faster (no
> unnecessary copies) with other solution...
>
>> -- Daniel
>>
>
> BR
> Marcin Kuszczak
> (aarti_pl)
Here's another idea I had. This *might* work come D2.0 (but again, I
don't know for certain). The idea here is that if we are passed a
possibly mutable value, we take a private copy of it since this is the
only way we can ensure no one else can mutate it.
BUT, if we are passed an invariant string, we just take a reference
since the compiler is effectively guaranteeing that its contents will
never, ever change.
Incidentally, I'm also assuming the whole "casting to const" thing works.
class TestX
{
private
{
char[] _value;
}
// Copy v: no external mutations!
char[] value(char[] v)
{
_value = v.dup;
return v;
}
// Invariant, so a reference to it is fine
char[] value(invariant char[] v)
{
_value = v;
return v;
}
// Return const: no one calling this can modify it, even though they
// have a reference!
const char[] value()
{
return cast(const char[])_value;
}
}
So maybe you will be able to get what you want. Will be interesting to
find out :)
-- Daniel
--
int getRandomNumber()
{
return 4; // chosen by fair dice roll.
// guaranteed to be random.
}
http://xkcd.com/
v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D
i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
More information about the Digitalmars-d-announce
mailing list