Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
On 2010-07-31 20:23, Carl Mäsak wrote: * Today we discovered that it's possible to break encapsulation by detaching a method from an object of one class, and calling that method on an object of another class. Which means that breaking the encapsulation of a foreign class is as easy as creating a custom class with all of the same private attributes, and with a method to print (or otherwise reveal) them. * It is my feeling that such encapsulation-breakage shouldn't be allowed. Do you agree, p6l? I don't really agree. The way OOP is implemented in perl 5 allows breaking encapsulation on many different levels, but I believe this has turned out to be a strength, since it allows you to use in those (very rare?) cases where it is needed. When I found that all objects in perl 6 had fields, I was kind of put off, since it looked to Java-ish. What saves the spirit of perl is that people are still free to hack away (and then there are such roles as postcircumflex that reintroduces the very terse syntax, perl 5 is known for, avoiding the dot-hell of Java). I believe we have a much larger task at hand, which is to write documentation that educates newcomers to use the right tools for the right job. I'd never recommend monkeypatching to a rookie programmer (or those silly .* and .+ method invocators) and I believe we owe people outside the perl community to explain the /intent/ behind the different constructs. Regards, Michael.
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
jnthn++ points out in meatspace that the invocant parameter has a constraint (by spec but not in Rakudo), which will carry over to the new class. Which means that only objects of child classes will signature-bind anyway. // Carl
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
Carl Mäsak wrote: * It is my feeling that such encapsulation-breakage shouldn't be allowed. Do you agree, p6l? Time may proof me wrong, but I think it's not such a big issue. Note that encapsulation can be broken in many ways already, wither with MONKEY_TYPING or by using introspection techniques (which aren't fully specced yet, but they *will* exist. In case of doubt you can just parse .perl output). * If it isn't allowed, which of the two steps is disallowed? *Detaching* a method containing references to private accessor slots (thereby extending the syntactic restriction of no private accessors outside of the class block), or *attaching* an anonymous method to an object belonging to a different class than the one from which it was detached (thereby by necessity having to complicate anonymous methods somewhat)? There's a third possiblity - $!foo being bound to the $!foo attribute of the lexically enclosing class at compile-time. So that re-attaching methods make them still refer to the old attribute. Not sure if it's a good idea, just food for thought. Cheeers, Moritz -- Moritz Lenz http://perlgeek.de/ | http://perl-6.de/ | http://sudokugarden.de/
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
Carl (), Moritz (): * If it isn't allowed, which of the two steps is disallowed? *Detaching* a method containing references to private accessor slots (thereby extending the syntactic restriction of no private accessors outside of the class block), or *attaching* an anonymous method to an object belonging to a different class than the one from which it was detached (thereby by necessity having to complicate anonymous methods somewhat)? There's a third possiblity - $!foo being bound to the $!foo attribute of the lexically enclosing class at compile-time. So that re-attaching methods make them still refer to the old attribute. Not sure if it's a good idea, just food for thought. That's indeed what Stefan proposed as well, and what I currently believe to be the right way of looking at this. The fact that you don't mention an error condition in connection to the accessing of the old attribute makes me realize yet another thing: class Parent { has $!a; method foo { say $!a } } class Child is Parent { has $!a } my $child = Child.new( :a(42), Parent{ :a(5) } ); my $parent-foo = Parent.^can('foo'); $child.$parent-foo(); # works, prints 5\n Or, in words, just because one detaches/re-attaches a method doesn't automatically mean that private attribute accesses result in an error. Specifically, they don't in child classes. // Carl
Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
Here's a case where a bug report stumped me and made me feel I'm missing something: http://rt.perl.org/rt3/Ticket/Display.html?id=69260 I'll give a somewhat summarized version of the above page, which gradually turns into a set of questions and not enough answers: * It has been decided that attribute slots of the type $!foo are only allowed *syntactically* within the class block that declares them. (The exception to this, I guess, is the 'trusts' directive.) But this means that something like this anonymous method my $reveal-foo = method { say $!foo } isn't allowed. I think that's good, because it would provide a very easy way to break encapsulation of an object; just call $object.$reveal-foo() on it. * Today we discovered that it's possible to break encapsulation by detaching a method from an object of one class, and calling that method on an object of another class. Which means that breaking the encapsulation of a foreign class is as easy as creating a custom class with all of the same private attributes, and with a method to print (or otherwise reveal) them. * It is my feeling that such encapsulation-breakage shouldn't be allowed. Do you agree, p6l? * If it isn't allowed, which of the two steps is disallowed? *Detaching* a method containing references to private accessor slots (thereby extending the syntactic restriction of no private accessors outside of the class block), or *attaching* an anonymous method to an object belonging to a different class than the one from which it was detached (thereby by necessity having to complicate anonymous methods somewhat)? I only see those three options: a. Allow this form of encapsulation breakage. b. Disallow detaching of certain methods. c. Disallow attaching of certain anonymous methods. I must confess I don't particularly like either option. I'm by no means an OO expert. It would be interesting to hear your views on this. // Carl
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 7/31/10 14:23 , Carl Mäsak wrote: a. Allow this form of encapsulation breakage. b. Disallow detaching of certain methods. c. Disallow attaching of certain anonymous methods. I must confess I don't particularly like either option. I'm by no means an OO expert. It would be interesting to hear your views on this. The whole concept of detaching and attaching methods seems suspect to me; in particular, attaching a method from a class not declared to be related reeks of monkey patching. As such, I'd only allow it when monkey patching is enabled. - -- brandon s. allbery [linux,solaris,freebsd,perl] allb...@kf8nh.com system administrator [openafs,heimdal,too many hats] allb...@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -BEGIN PGP SIGNATURE- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkxUbRAACgkQIn7hlCsL25URzACfeQwHqlQWs4IL6RdSCkkI1inr BasAoM0LyLl19dylqoOcMjCfk3kvC9j3 =FyAF -END PGP SIGNATURE-
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
On Sat, Jul 31, 2010 at 08:23:29PM +0200, Carl Mäsak wrote: * It has been decided that attribute slots of the type $!foo are only allowed *syntactically* within the class block that declares them. (The exception to this, I guess, is the 'trusts' directive.) But this means that something like this anonymous method my $reveal-foo = method { say $!foo } isn't allowed. I think that's good, because it would provide a very easy way to break encapsulation of an object; just call $object.$reveal-foo() on it. There is no $!foo. There is only $!Class::foo, and $!foo is a lexically scoped alias to it. This is necessary to allow privacy from your children to work: class Class { has $!foo; # the mere existance of $!foo is an implementation detail } class SubClass is Class { has $!foo; # hey why doesn't this work? } So $reveal-foo can't be defined because $!foo isn't even in scope. * Today we discovered that it's possible to break encapsulation by detaching a method from an object of one class, and calling that method on an object of another class. Which means that breaking the encapsulation of a foreign class is as easy as creating a custom class with all of the same private attributes, and with a method to print (or otherwise reveal) them. Calling such methods should fail, because the $!OtherClass:: attributes don't exist even if the shortnames are the same. * It is my feeling that such encapsulation-breakage shouldn't be allowed. Do you agree, p6l? It's not. * If it isn't allowed, which of the two steps is disallowed? *Detaching* a method containing references to private accessor slots (thereby extending the syntactic restriction of no private accessors outside of the class block), or *attaching* an anonymous method to an object belonging to a different class than the one from which it was detached (thereby by necessity having to complicate anonymous methods somewhat)? I only see those three options: a. Allow this form of encapsulation breakage. b. Disallow detaching of certain methods. c. Disallow attaching of certain anonymous methods. I must confess I don't particularly like either option. I'm by no means an OO expert. It would be interesting to hear your views on this. Perl philosophy has always been it's not that I have a shotgun, you just weren't invited, so stay out of my living room. I don't see any reason for Perl 6 to break with this - encapsulation should be about helping the programmer, not helping the sysadmin maintain system security. -sorear signature.asc Description: Digital signature
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
On Sat, Jul 31, 2010 at 02:36:02PM -0400, Brandon S Allbery KF8NH wrote: On 7/31/10 14:23 , Carl Mäsak wrote: a. Allow this form of encapsulation breakage. b. Disallow detaching of certain methods. c. Disallow attaching of certain anonymous methods. I must confess I don't particularly like either option. I'm by no means an OO expert. It would be interesting to hear your views on this. The whole concept of detaching and attaching methods seems suspect to me; in particular, attaching a method from a class not declared to be related reeks of monkey patching. As such, I'd only allow it when monkey patching is enabled. Methods are just functions. $object.$method(@args) is simply sugar for $method($object, @args) so disallowing it is not quite that simple. -sorear signature.asc Description: Digital signature
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 7/31/10 14:38 , Stefan O'Rear wrote: On Sat, Jul 31, 2010 at 02:36:02PM -0400, Brandon S Allbery KF8NH wrote: The whole concept of detaching and attaching methods seems suspect to me; in particular, attaching a method from a class not declared to be related reeks of monkey patching. As such, I'd only allow it when monkey patching is enabled. Methods are just functions. $object.$method(@args) is simply sugar for $method($object, @args) so disallowing it is not quite that simple. That would seem to make it worse (type conformability on the first positional parameter; does declaring a method not implicitly declare the type of its positional parameter to be the class that declared it, or a subclass thereof?) --- but I think you addressed that in your other response. - -- brandon s. allbery [linux,solaris,freebsd,perl] allb...@kf8nh.com system administrator [openafs,heimdal,too many hats] allb...@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -BEGIN PGP SIGNATURE- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEUEARECAAYFAkxUbtAACgkQIn7hlCsL25WOkwCgvq2SevYoVtGWSio0q7lVDxWy Qt8AmM8FijA51vxGjylUwuCq1+zpF9k= =XroU -END PGP SIGNATURE-
Re: Breaking encapsulation by detaching a private-variable-accessing method from one object and calling it on another
Carl (), sorear (): * It has been decided that attribute slots of the type $!foo are only allowed *syntactically* within the class block that declares them. (The exception to this, I guess, is the 'trusts' directive.) But this means that something like this anonymous method my $reveal-foo = method { say $!foo } isn't allowed. I think that's good, because it would provide a very easy way to break encapsulation of an object; just call $object.$reveal-foo() on it. There is no $!foo. There is only $!Class::foo, and $!foo is a lexically scoped alias to it. This is necessary to allow privacy from your children to work: class Class { has $!foo; # the mere existance of $!foo is an implementation detail } class SubClass is Class { has $!foo; # hey why doesn't this work? } So $reveal-foo can't be defined because $!foo isn't even in scope. Thanks, that's an excellent way to explain this. It also provides the answer to this whole thread: class A { has $!x; } class B { has $!x; method foo { say $!x } # really 'say $!B::x' } my $b-foo = B.^can(foo); A.new( :x(42) ).$b-foo(); # doesn't work, can't access $!B::x from A This solution is a fourth one that I didn't see, and the first one that I like: d. Disallow illegally accessing a private attribute slot that isn't yours. It also incidentally answers a random thought I had today after posting my original email: Hey, jnthn talked about implementing attribute accesses as array accesses rather than hash accesses -- how the heck will that work if methods can be detached and re-attached to objects of a different class? With $!foo really meaning $!MyClass::foo it makes a lot more sense. // Carl