Re: Encapsulating the contents of container types

2011-09-10 Thread Martin D Kealey


On Fri, 9 Sep 2011, Carl Mäsak wrote:
> Patrick Michaud said something (I think AFK) that seems essential to
> me: the non-rw-ness of these objects isn't a trait of *the object
> itself*, it's a trait of *the context in which the object is used*.

In one sense that is true, but if that's the only kind of constancy that
gets implemented, then it's only half the story.

It is of course useful to be able to send a "value" to a sub and know that
it won't be mangled when the sub returns, and you do get that from the
"const reference" approach that's implied by Patrick's comment.

But it's also useful, when in the sub, to know that the someone else won't
mess with a "value" while you're working with it. I can't see any way to
enforce that without constancy being a feature of the object rather than the
reference to it.

Moritz Lenz wrote:
> I think we should consider the implications of
> immutability-all-the-way-down before we jump to any conclusions. In
> particular list cases where typical Perl 5 code fails when ported to Perl
> 6.

Perhaps if we could tag the type/class/pmc/whatever when it's constructed
as to whether it defaults to r/o or r/w? Hence things like file handles
would be r/w by default, and most other things would be r/o.

Actually, I'm inclined to think that r/o vs r/w for sub params is a bit of a
blunt instrument. What about the option of treating a "r/w" param as a
shorthand for both an r/o param AND an r/o return? So in effect, changes to
the "container" don't take effect until after the sub returns. (BTW this
would have a lot of benefits for auto-threading code.)

-Martin


Re: Encapsulating the contents of container types

2011-09-09 Thread Carl Mäsak
Moritz (>):
> I think we should consider the implications of immutability-all-the-way-down
> before we jump to any conclusions. In particular list cases where typical
> Perl 5 code fails when ported to Perl 6.

Indeed. Clearly I'm missing at least one piece of the puzzle here.

Back to the drawing-board... :-)

// Carl


Re: Encapsulating the contents of container types

2011-09-09 Thread Moritz Lenz

Am 09.09.2011 12:44, schrieb Carl Mäsak:

Non-rw attributes, non-rw parameters, and non-rw return values all
share the same mechanism. Fine. Makes sense.

[...]

Non-rw-ness in this case should be "all the way", not one level down.


(I hope I didn't change the meaning by stripping parts of your quote).

Woah there. Every routine that returns something mutable would have to 
indicate that in its signature, and there are a lot of routines that 
return mutable objects, or lists thereof (map, sort, grep, first, 
constructors of ref types, ...)


That would basically move Perl 6 to a level where you have to declare 
mutability in an almost Haskell-ish way.


I think we should consider the implications of 
immutability-all-the-way-down before we jump to any conclusions. In 
particular list cases where typical Perl 5 code fails when ported to Perl 6.


Basically any code that deals with file handles, database handles, 
statement handles etc. (all mutable objects) would need to take care 
while passing them around, because a single non-rw return would render 
them immutable, and thus useless.


I used to be in favor of the immutability approach, but the more I think 
about its effect on actual code I've written in the past, the more I get 
scared by the thought.


Cheers,
Moritz


Re: Encapsulating the contents of container types

2011-09-09 Thread Carl Mäsak
Thanks to everyone for your replies. I've been wanting to write a
summary + further thoughts for a while, but have been a bit
time-constrained.

The central tension in this issue is nicely captured by what Damian
wrote contrasted with what Stefan wrote:

Damian (>):
> Doing nothing should result in the safe behaviour (i.e. full encapsulation).
> You ought to have to explicitly request anything else.
>
> One of the *big* selling points of Perl 6 is the prospect of "OO done right".
> Leaky encapsulation ain't that.

Stefan (]):
] I am [fine with leaky encapsulation], personally.  It's not a problem unique
] to Perl 6 and I have yet to see a solution (in any language) that fails
] to be worse than the original
] problem.

I find both sides very reasonable, each in its own way. I'd *like* to
see a solution materialize along the lines of what Damian recommends,
but it's not going to happen by itself and without a concrete proposal
for how it should work. If we just leave things be, what we'll end up
with will be the status quo ante bellum, along the lines of what
Stefan recommends.

I'd be fine with finding some part-way solution that would make life
easier and less monotonous for people who care about defensive
copying. I'd even be fine with defensive copying semantics being a
(non-core) module, but it would feel like defeat in some ways.

However, having read the whole thread, various pages on the web (see
references), and IRC discussions, I see a vaguely hopeful picture
emerging. Not sure where it leads yet.

Non-rw attributes, non-rw parameters, and non-rw return values all
share the same mechanism. Fine. Makes sense. The Rakudo devs have
introduced the concept of "decontainerization" for scalar values that
need to be stripped of their surrounding scalar container when they
are passed through any of these barriers. This makes the values
effectively immutable, since there's no container to put a new value
in. The concept doesn't seem to apply cleanly to container types, but
the parallel is perhaps noteworthy.

Non-rw-ness in this case should be "all the way", not one level down.
If it's good, non-leaky encapsulation we care about, it *has* to be
all the way. One problem here is not hard-coding any semantics to the
usual Array and Hash types -- it has to work even for container types
we haven't dreamed up yet. It has to work for objects. Likely there'll
have to be some contract that authors of new container types will have
to adhere to.

Patrick Michaud said something (I think AFK) that seems essential to
me: the non-rw-ness of these objects isn't a trait of *the object
itself*, it's a trait of *the context in which the object is used*.
(Note the similarity to what Ruud suggested.) Some actual code shows
what this means:

> my %hash = foo => { bar => 42 }

> # works, shouldn't:
> sub parameter-barrier(%h) { %h = "OH NOES"; say %h }
> parameter-barrier(%hash)
("foo" => {"bar" => "OH NOES"}).hash

> # works, shouldn't:
> sub return-value-barrier(%h is rw) { %h }
> return-value-barrier(%hash) = "OH NOES twice"; say %hash
("foo" => {"bar" => "OH NOES twice"}).hash

> # works, should:
> sub let-me-through(%h is rw) is rw { %h }
> let-me-through(%hash) = "42 again"; say %hash
("foo" => {"bar" => "42 again"}).hash

> # works, shouldn't:
> class NonLeaky { has %.h }
> my $instance = NonLeaky.new(:h(%hash))
> $instance.h = "OH NOES thrice"; say $instance.h
("foo" => {"bar" => "OH NOES thrice"}).hash

> # works, should:
> %hash = 5; say %hash
("foo" => {"bar" => 5}).hash

Note that there's only ever *one* hash of hashes here. No defensive
copying. Just references to the same one.

So you see, it's not so much the *object* having a
write-me-don't-write-me flag on it -- that simply won't fly. It's more
like were passing a reference around through various (routine or
object) boundaries, and each of these boundaries has the right to
deprive the reference of its writeability. And then, somehow, all
indexings into that same reference are affected too.

I know that the specifics of this aren't trivial -- and in fact, the
issues one runs into with this are likely exactly what Stefan suggests
will be "worse than the original problem" -- but at least this forms a
seemingly consistent model of how containers should work in order not
to be leaky. A model that we could use as a starting point for further
discussion and maybe even implementation.

So, my question is now: does this make sense? Objects don't have to be
defensively copied, but when passing through non-rw barriers they (and
all their indexing descendants) can be deprived of their writeability.

Some references. It all comes down, in the case of OO, to the object
being able to protect its invariants. Over at c2, some people question
whether this is always necessary.

 
 


// Carl


Re: Encapsulating the contents of container types

2011-08-22 Thread Patrick R. Michaud
On Mon, Aug 22, 2011 at 06:39:25AM +0100, Nicholas Clark wrote:
> Is it? If, at the implementation layer, all accesses to objects are actually
> function calls called via vtables, then surely it's *relatively* simple to
> change the vtable to replace
> 
> * mutator methods with methods which croak (the shallow read-only part)
> * accessor methods for internal storage with methods which return proxy
>   objects which are read-only

At present I don't think we have anything that identifies
mutator methods and/or accessor methods, so perhaps that's where
we would need to start.

Pm


Re: Encapsulating the contents of container types

2011-08-21 Thread Nicholas Clark
On Sun, Aug 21, 2011 at 08:10:46PM -0400, Mark J. Reed wrote:
> The whole point of objects is to encapsulate state, accepting messages
> which operate and report on that state.  Making a new object every
> time the state changes sort of defeats the purpose; I certainly
> wouldn't call it "object orientation done right".
> 
> Total immutability is very powerful, but it's not the way Perl 6 is
> designed, and would represent a radical departure in that design.

It wouldn't be fit to be called Perl if it defaulted to total immutability.

> However, I do think that we need selective immutability.  I firmly
> agree in principle that "readonly all the way down" should just work,
> without the programmer having to jump through hoops to make defensive
> copies. Of course, the plumbing to make that happen strikes me as
> likely to be complex and therefore fragile.

Is it? If, at the implementation layer, all accesses to objects are actually
function calls called via vtables, then surely it's *relatively* simple to
change the vtable to replace

* mutator methods with methods which croak (the shallow read-only part)
* accessor methods for internal storage with methods which return proxy
  objects which are read-only

ie there's no need to internally actually make defensive copies, or have
some complex flag-checking system. It should be possible* to implement it
in a small, incremental "obviously no bugs" fashion, instead of a monolithic,
large "no obvious bugs" fashion.**

Nicholas Clark

*  "should be possible" in that I've not tried this, because I know that it
   distinctly isn't possible in Perl 5, which is stuck in the centaury of
   direct structure access.
** but there will be bugs. Sadly.


Re: Encapsulating the contents of container types

2011-08-21 Thread Mark J. Reed
The whole point of objects is to encapsulate state, accepting messages
which operate and report on that state.  Making a new object every
time the state changes sort of defeats the purpose; I certainly
wouldn't call it "object orientation done right".

Total immutability is very powerful, but it's not the way Perl 6 is
designed, and would represent a radical departure in that design.

However, I do think that we need selective immutability.  I firmly
agree in principle that "readonly all the way down" should just work,
without the programmer having to jump through hoops to make defensive
copies. Of course, the plumbing to make that happen strikes me as
likely to be complex and therefore fragile.

On Sun, Aug 21, 2011 at 12:00 AM, Darren Duncan  wrote:
> Patrick R. Michaud wrote:
>>
>> On Sat, Aug 20, 2011 at 04:41:08PM -0700, Darren Duncan wrote:
>>>
>>> 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.
>>> ...
>>
>> To make sure I understand correctly, you're essentially
>> saying that @a.push(3) should not modify @a directly -- someone
>> would have to write something like
>>
>>     @a = @a.push(3)  # or @a .= push(3)
>>
>> And to do a "shift", one would have to do something like
>>   ($value, @a) = @a;
>> since @a.shift would be unable to mutate the array.  (I'm not exactly sure
>> what pop would look like.)
>>
>> Is that correct?
>
> Yes, that's what I'm saying.
>
> And we've already been making moves in that direction.
>
> As I recall, regular expression substitutions were already changed to work
> that way, returning the modified string rather than modifying the argument,
> so there is precedent.
>
> Moreover, thanks to meta-operators, one can typically get a mutating variant
> of any otherwise non-mutating operator very tersely with just a single added
> "=" character.
>
> This aids learnability as there's a relatively simple mnemonic, where nearly
> any given operator foo is non-mutating, but by adding an "=" to it you get a
> mutating variant, so people can look for the "=" to know if it would mutate.
> The comparison ops are the rare exception to the rule.
>
> -- Darren Duncan
>



-- 
Mark J. Reed 


Re: Encapsulating the contents of container types

2011-08-21 Thread Darren Duncan

Moritz Lenz wrote:

Moving into the direction of immutability doesn't help with the problem
at hand -- it only helps here if we force everything(*) to be immutable,
or at least encapsulating every mutable object into special types, like
Monads in Haskell.

(*) ok, not everything, but everything that can be stored in an object

And I'd be very disappointed if Perl 6 turned into Haskell so late in
its development stage (remember that we have working compilers, a
growing number of modules and active users), especially since it's not
tailored to be a language that is tailored towards immutability.


Well, you do what works for you.

For my part, I have been evolving my new Muldis D language to be essentially 
what Perl 6 might have been if it were tailored towards immutability.


In fact, I would say that is the single largest difference between the 2 
languages.  I started out more different, and over time came to see the light on 
how other Perl 6 aspects are actually better for Muldis D than what I had before.


The next largest differences are the built-in database functionality, and the 
fact that mine doesn't even have a hello-world implementation yet.  But when I 
have the time, you will see it run.


-- Darren Duncan


Re: Encapsulating the contents of container types

2011-08-21 Thread Moritz Lenz
On 08/21/2011 06:00 AM, Darren Duncan wrote:
> Patrick R. Michaud wrote:
>> On Sat, Aug 20, 2011 at 04:41:08PM -0700, Darren Duncan wrote:
>>> 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.
>>> ...
>> 
>> To make sure I understand correctly, you're essentially
>> saying that @a.push(3) should not modify @a directly -- someone
>> would have to write something like
>> 
>>  @a = @a.push(3)  # or @a .= push(3)
>> 
>> And to do a "shift", one would have to do something like
>>($value, @a) = @a;
>> since @a.shift would be unable to mutate the array.  (I'm not 
>> exactly sure what pop would look like.)
>> 
>> Is that correct?
> 
> Yes, that's what I'm saying.
> 
> And we've already been making moves in that direction.

Moving into the direction of immutability doesn't help with the problem
at hand -- it only helps here if we force everything(*) to be immutable,
or at least encapsulating every mutable object into special types, like
Monads in Haskell.

(*) ok, not everything, but everything that can be stored in an object

And I'd be very disappointed if Perl 6 turned into Haskell so late in
its development stage (remember that we have working compilers, a
growing number of modules and active users), especially since it's not
tailored to be a language that is tailored towards immutability.

Cheers,
Moritz


Re: Encapsulating the contents of container types

2011-08-20 Thread Darren Duncan

Patrick R. Michaud wrote:

On Sat, Aug 20, 2011 at 04:41:08PM -0700, Darren Duncan wrote:

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.
...


To make sure I understand correctly, you're essentially
saying that @a.push(3) should not modify @a directly -- someone
would have to write something like

 @a = @a.push(3)  # or @a .= push(3)

And to do a "shift", one would have to do something like
   ($value, @a) = @a;
since @a.shift would be unable to mutate the array.  (I'm not 
exactly sure what pop would look like.)


Is that correct?


Yes, that's what I'm saying.

And we've already been making moves in that direction.

As I recall, regular expression substitutions were already changed to work that 
way, returning the modified string rather than modifying the argument, so there 
is precedent.


Moreover, thanks to meta-operators, one can typically get a mutating variant of 
any otherwise non-mutating operator very tersely with just a single added "=" 
character.


This aids learnability as there's a relatively simple mnemonic, where nearly any 
given operator foo is non-mutating, but by adding an "=" to it you get a 
mutating variant, so people can look for the "=" to know if it would mutate. 
The comparison ops are the rare exception to the rule.


-- Darren Duncan


Re: Encapsulating the contents of container types

2011-08-20 Thread Patrick R. Michaud
On Sat, Aug 20, 2011 at 04:41:08PM -0700, Darren Duncan wrote:
> 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.
> ...

To make sure I understand correctly, you're essentially
saying that @a.push(3) should not modify @a directly -- someone
would have to write something like

 @a = @a.push(3)  # or @a .= push(3)

And to do a "shift", one would have to do something like
   ($value, @a) = @a;
since @a.shift would be unable to mutate the array.  (I'm not 
exactly sure what pop would look like.)

Is that correct?

Pm


Re: Encapsulating the contents of container types

2011-08-20 Thread Darren Duncan

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


Re: Encapsulating the contents of container types

2011-08-20 Thread Stefan O'Rear
On Thu, Aug 18, 2011 at 04:06:47PM +0200, Carl Mäsak wrote:
> I was working on the Little Animal Farm game yesterday, and wanted to
> make it totally safe against tampering from the outside. (See
> .)
> 
> 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.

This is not specific to Perl 6 at all, and is a well-known problem in
object-oriented languages.  Some quick playing with search engines
turns up the phrase "defensive copy".

> Quoting from S06:639, which talks about readonly routine parameters:
> 
> ] By default, all parameters are readonly aliases to their corresponding
> ] arguments--the parameter is just another name for the original
> ] argument, but the argument can't be modified through it.  This is
> ] vacuously true for value arguments, since they may not be modified in
> ] any case.  However, the default forces any container argument to also
> ] be treated as an immutable value.  This extends down only one level;
> ] an immutable container may always return an element that is mutable if
> ] it so chooses.
> 
> Applying this semantics to readonly attributes would make the above
> issue go away. The problem with the semantics is that there doesn't
> seem to be a way to implement it that is both performant and free from
> surprising side effects.

To me it is obvious that non-rw attributes, non-rw parameters, and non-rw
block returns should use the same semantics.  Of course that leaves the
question of what those semantics should be.

> I solved this in my code by writing my own accessor that clones the array:
> 
> $ perl6
> > class A { has @!numbers; method add($n) { @!numbers.push($n); return }; 
> > method numbers { @!numbers.clone } }
> > my $a = A.new
> > $a.add(1); $a.add(2); $a.add(3)
> > $a.numbers[1] = "OH NOES"
> > $a.numbers
> 1 2 3
> 
> It felt kinda silly to write that accessor. Note also that I had to
> explicitly 'return' from the .add method, because .push returns the
> array acted on, and that would otherwise have been return, and the
> class would again be vulnerable. So it's not just accessors that are
> the problem.

You didn't have to add that return.  Method add is not declared
C, which means that its return value is automatically
protected against modification in the same sort of way as a non-rw
attribute.

> But it gets worse.
> 
> $ perl6
> > class B { has %!info = foo => { bar => 42 }; method info { %!info.clone } }
> > my $b = B.new
> > $b.info.perl
> {"foo" => {"bar" => 42}}
> 
> > $b.info = "OH NOES"
> Cannot modify readonly value
> > $b.info = 42
> > $b.info.perl
> {"foo" => {"bar" => 42}}
> 
> > $b.info = "OH NOES"
> > $b.info.perl
> {"foo" => {"bar" => "OH NOES"}}
> 
> We've done the cloning, so we're safe from changes on the shallow
> level. But changes on the levels below go through. (Same goes for
> arrays?) Why? When we clone the hash, we copy over the keys/values to
> a new hash. The value in this case is a hash reference, so the new
> hash gets the same hash reference.
> 
> I ended up writing a custom deep-cloner for hashes in order not to
> leak any information from the class:
> 
> $ perl6
> > sub deepclone(%h) { hash map -> $k, $v {; $k => ($v ~~ Hash ?? 
> > deepclone($v) !! $v ) }, %h.kv }
> > class B { has %!info = foo => { bar => 42 }; method info { 
> > deepclone(%!info) } }
> > my $b = B.new
> > $b.info = "OH NOES"
> > $b.info.perl
> {"foo" => {"bar" => 42}}
> 
> This solves it, but in a specialized and ad-hoc way.
> 
> The whole thing leaves me with the following questions:
> 
> * What do we mean when we say 'has @.a is readonly'? What do we want it to 
> mean?

It means has @!a; method a() { @!a }.  @!a is returned in a way that is
readonlyified in accordance with the rules of non-rw blocks.

> * Are we fine with references from readonly attributes leaking out of
> the class? Should we be?

I am, personally.  It's not a problem unique to Perl 6 and I have yet to
see a solution (in any language) that fails to be worse than the original
problem.

> * What language components could be provided to put class implementors
> on t

Re: Encapsulating the contents of container types

2011-08-20 Thread Michael Zedeler

On 2011-08-20 12:02, Damian Conway wrote:

Carl asked:

* What language components could be provided to put class implementors
on the right path so that their classes end up encapsulated by
default?

Doing nothing should result in the safe behaviour (i.e. full encapsulation).
You ought to have to explicitly request anything else.

One of the *big* selling points of Perl 6 is the prospect of "OO done right".
Leaky encapsulation ain't that.
Sorry if I am hijacking the thread, but how does the .* and .+ fit into 
"OO done right" idea?


As I understand it, having a class hierarchy like so:

class A { method m { say "A.m called" } }
class B is A { method m { say "B.m called" } }
class C is A { method m { say "C.m called" } }
class D is B is C { method m { say "D.m called" } }

calling

D.new().+m();

Produces

D.m called
B.m called
C.m called
A.m called

Making it an option (and I suspect sometimes even the responsibility) of 
the caller (reading "Calling sets of methods" in S12) to choose how 
dispatch should be done, can hardly be said to be encapsulation (a 
subset of OO) "done right"?


In other words, any class using .+, .* or $something.WALK( ... ) is - in 
the best case - violating the responsibilities of its superclasses. The 
.+ and .* operators still look to me as if someone has been mixing up 
the chain of responsibility pattern with normal OO method dispatch. On 
one hand, there is no reason that .* and .+ should use the inheritance 
hierarchy as the dispatch order if we're looking for some generalized 
chain of responsibility. On the other hand, explicitly calling each 
method all the way up the inheritance hierarchy, ignoring the efforts of 
the individual methods to carry out their specialization of their super 
classes, just doesn't seem to make any sense.


Regards,

Michael.



Re: Encapsulating the contents of container types

2011-08-20 Thread Damian Conway
Carl asked:

> * What do we mean when we say 'has @.a is readonly'?
> What do we want it to mean?

Not sure about "we", but I want that to mean that nothing outside the
class can alter any component of @.a, no matter how deeply nested that
component may be.


> * Are we fine with references from readonly attributes leaking out of the 
> class?
>   Should we be?

No.
No.


> * What language components could be provided to put class implementors
> on the right path so that their classes end up encapsulated by
> default?

Doing nothing should result in the safe behaviour (i.e. full encapsulation).
You ought to have to explicitly request anything else.


One of the *big* selling points of Perl 6 is the prospect of "OO done right".
Leaky encapsulation ain't that.

Damian


Re: Encapsulating the contents of container types

2011-08-18 Thread Ruud H.G. van Tol

On 2011-08-18 16:06, Carl Mäsak wrote:


I was working on the Little Animal Farm game yesterday, and wanted to
make it totally safe against tampering from the outside. (See
.)

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.
[...]

* Are we fine with references from readonly attributes leaking out of
the class? Should we be?

* What language components could be provided to put class implementors
on the right path so that their classes end up encapsulated by
default?

* Could someone restate this whole problem space in a way that doesn't
make my head hurt?


How about having scoped permission limits?
(such that a code block can be disallowed to change data)

--
Ruud