Carl Mäsak wrote:
I ended up implementing a custom accessor method and a sub to
deep-clone hashes, just to make sure that data belonging to readonly
attributes doesn't get changed.

This worries me.

Concrete example (useless output left out):

$ perl6
class A { has @.numbers; method add($n) { @!numbers.push($n) } }
my $a = A.new
$a.add(1); $a.add(2); $a.add(3)
$a.numbers[1] = "OH NOES"
$a.numbers
1 OH NOES 3

Notice that the attribute @.numbers is readonly (since it's not
declared 'is rw'). But that does us a fat lot of good here; it just
means that I'm not allowed to reassign the array reference itself. The
contents are just as writable as any array's.

What worries me -- and the reason I turn to p6l for this -- is that a
lot of class authors will fail to notice this fact and write code that
isn't properly encapsulated and, depending on the circumstances, maybe
even insecure.

I've been worried about this for years, and said so on p6l years ago. I believe that if you declare something readonly, it should be a guarantee that nothing can mutate what is stored there to any level of recursive depth, with the sole exception of elements that are explicitly references.

I believe the general solution to this problem is to make all objects immutable, with the only exception being explicit references, and so mutating an object isn't an option; rather you have to derive a new object.

"Values" of all types should be immutable, even if that type is Array or whatever, and only "Variables" should be mutable.

You should have to go out of your way to mutate something rather than this happening by default, rather than having to go out of your way to prevent mutation.

As a side benefit, things like concurrency become a lot easier with immutables.

You can fake object mutability with syntax, or only allow what references point to to change.

-- Darren Duncan

Reply via email to