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