p5-mop Inside-Out object problem
Now, p5-mop-redux is implemented by Inside-Out object.
p5-mop is not using the standard scheme where an object is simply a blessed structure (usually a HashRef). Instead, it’s using InsideOut objects, where all you get as an object is some kind of identification number (usually a simple reference), which is used internally to retrieve the object properties, only accessible from within the class. (p5-mop: a gentle introduction)
Inside-Out object hidde attribute values from out of object. Is it good?
Inside-Out object has big inconvenient feature. that is we can't see attribute values by Data::Dumper.
In hash-based object, we can see attribute values by Data::Dumper;
use Data::Dumper; print Dumper $obj;
But Inside-Out object is not.
use Data::Dumper; # Oh! what data contain? We can't see these data. print Dumper $obj;
In many cases, object has multiple hierarchy.
In this case, Let's think you dump object.
$obj1->{obj2} = $obj2; $obj2->{obj3} = $obj3; $obj3->{obj4} = $obj4;
Perl5 design is "No restriction to programmer".
so I like hash-based object.
It is a work in progress, but I think for now you can do this to get information about your object:
You can then use
$meta->dump
to give you a hashref describing your attributes and methods, or either$meta->attributes
or$meta->methods
to get arrayrefs of either attributes or methods. Each item is either amop::attribute
ormop::method
object that you can call adump
method on, to get their values:Interestingly "secure" objects - as implemented by inside-out techniques have become a commodity feature to me.
It is a bit like with strictures and warnings.
You get the "guarantee" to not inadvertently corrupt your objects by setting a value in a transparent hash structure. You get sort of a guarantee that no-one else corrupts your objects and then sends you spurious bug reports.
I am very happy to hear that the mop intends to give us introspection facilities because a lack of this feature indeed seems inconvenient.
If in any way possible I would of course favour to be able and dump whole objects as suggested.
say Dumper $obj;
Convenience and safety in one - every (Perl) programmer's dream, I guess. :-)
This is really just a limitation of what Data::Dumper can do. It's not really intended as an OO debugging tool, even if it's frequently used that way.
It's not especially hard to write a dumper designed for mop objects. (I've been lazy here and not accounted for cyclical data structures - that wouldn't be especially tough to add though.)
Of course, once mop is in core, it's not inconceivable that another core module (Data::Dumper) might add special hooks for it. Perhaps instead of outputting something along the lines of:
...it could output for mop objects something more like:
Dammit, it looks like someone (presumably STEVAN or DOY) beat me to it. There's already a
dump
method in mop::object!Yeah, I realized it too when I accidentally did
$object->dump
on my Reply terminal lolexcellent! :-)
Yuki, for the moment, we have mop::object;:dump, which Tobyink already commented about. It recursively calls the &dump method and so should serve all your debugging needs (and it only costs 6 extra characters).
I would love to support something that allowed users to dump the object directly without needing to call &dump, if that is possible you can be sure that we will support it.
The point of this topic is that we don't dump object information easily in Inside-out object.
I know the existence of the way to dump object information in Inside-out object.
Perl5 design is "Programmer don't have no restriction".
I think many people is misled. The truth is that hash based object is secure. Hash based object never have security issue.
In hash based object, programmer can access attribute values, but this is not danger. It is convenient because you can see what attribute value is set.
I think simple is best. mop is not bad. but mop is implemented by inside-out object is very inconvenient because we can't see object information easily.
dump method belong to object. If objects have hierarchy, we can't call dumper method easily.
We don't use "use Data::Dumper; print Dumper $obj" in inside-out object.
Modules is not consist of only mop objecst. There are mix of mop object and hash based object.
If all of the world is mop object, you idea is good, but the world is mix of mop object and hash based object.
User can't know the object is mop or not mop easily. That is inconvenient.
Yes, but you seem to be making the assumption that because
Dumper($obj)
doesn't currently work for mop objects, it will never work.Assuming mop becomes part of Perl core, that would be a very good argument for modifying Data::Dumper to give it explicit mop support, whatever internal structure mop ends up using for its attribute storage.
Here's an example of how Data::Dumper can be patched with mop-specific support.
The implementation of
mop::anoint
(envisaged to be a mop-specific equivalent ofbless
, which doesn't bypass constructors, etc) is left as an exercise for the reader.I understand the way to display mop object information recursively by Data::Dumper. Your idea "Perl core provide Data::Dumper to dump mop object" is good.
I personally prefer hash-based objects myself, mostly because I am familiar with it and the concept is simple.
I don't know about the "security" aspect, but hash-based object is viewed as less _safe_ because typos like $obj->{referer} (instead of $obj->{referrer}) are not caught at compile-time. People do make typos, sometimes often.
Perhaps Stevan Little et al want to make the object system in Perl be more like Ruby instead of like Perl 5 (and Python). Some can argue that Ruby is "purer" in OO aspect than Perl 5 and Python.
Steven - Actually I am going very strongly for Perl 6 and not Ruby.
Steven - And actually, the argument that Ruby is somehow more pure is usually associated with the fact that in Ruby everything is an object (String, Number, etc). This is not the direction I am trying to take things at all.
Of course, can't believe I forgot about Perl 6. I was thinking about "every attribute going through an accessor in Ruby" for the reason some people claim Ruby is more OO-pure. I personally know very little about OO and wouldn't make that claim myself.
As Toby and Stevan said (and I said so myself, in the very beginning,) it is all a work in progress. Toby's idea of Data::Dumper being able to dump mop objects just like regular hashrefs is probably the way to go, so I think it is early for you to dismiss mop just yet.
Still, I also think it is good to keep a critical eye on this, especially being a "redux", so thanks for the feedback! :)
thanks for comment. I also like hash based object because it is simple and easy and enough to do OO program.
My afraid is that if mop is more complex, appending mop to core is more later. if mop is more complex because we seek Perl6 dream, it is more difficult to add mop to Perl5 core.
I think we need minimal mop. And we need mop that Perl5 user can use it by similar way of Perl5, and easy to migration Perl5 OO program to mop.
Big jump is hard, but small jump is easy.
@yuki - We are trying to keep the mop very minimal, and we are especially trying to keep the changes that MOP requires in the core minimal.
I think what you perceive as complexity is really unfamiliarity.
Is there a case where external code would want access to the internal state of an object that would not also be provided by introspection via the meta object? Pretty much the point of a MOP is to mediate this kind of access.
@chris - Yes, currently you have to do this:
Kind of long, but still accessible.
Hash-based objects are indeed simple, and easy to understand. However, as others pointed out, they are also easily modifiable by the users of your classes.
Even if they are easily dumpable, the most you can get is the information about the attributes. You can't really get any information about the methods provided by the class by using Data::Dumper. There is at least one other module, Data::Printer, which does display the list of public and private methods, but not more than that.
The new mop provides much better capabilities for introspecting objects, and I expect the existing dumper modules on CPAN will be suitably updated to take advantage of these and provide a richer experience.
The future with mop-in-core-Perl can only be brighter. I just hope it's sooner than later.
>Hash-based objects are indeed simple, and easy to understand. However, as others pointed out, they are also easily modifiable by the users of your classes.
The users of your classes is programmer, not dangerous attacker. If accessor is provided, programer can use only accessor and don't need to touch internal data. There is no problem.
Even mop provide attribute value getting method. This mean that data is not hidden from outside.
mop::get_meta('MyClass')->get_attribute('$!foo')->fetch_data_in_slot;
so I don't understand inside-out object meaning. I think inside-out object make implementation more difficult.
Yuki: It's not about the users of your class "attacking". It's for their own safety that object implementations are better to be opaque and the internals are available only via defined interfaces.
Yes, it's true that mop allows you to access the internal data. But only via it's own interface.
Not allowing the internals of an object to be accessed directly, but only via advertised interfaces, means the class implementation and the use of the class are not tightly coupled, and either can change without affecting the other.
>Yuki: It's not about the users of your class "attacking". It's for their own safety that object implementations are better to be opaque and the internals are available only via defined interfaces.
I don't understand advantage of this. If document provide only accessor, user don't need to know internal data. Accessor work as public interface. This is not relevant that internal data is saved as hash reference or inside-out object.
The advantage of hash reference is simplicity and visible and understandable. you ignore this big advantage.
So you have a class. It’s a useful class, so you put it on CPAN. Because it’s useful, many people use it. Some people write subclasses for it. Some of these subclasses store their own data in the object. One of them uses a key, say, _total, with an underscore because it didn’t want to break your class. You are unaware of this. You write a new version of the class, and for some feature you want to store a total as private information… and you don’t want to break subclasses, so you put an underscore and store it in _total. You release this new version to CPAN. Now that subclass is broken (or your class, or actually most probably both).
This is not about dangerous attackers.
It’s not because of dangerous attackers that we use lexical variables either, instead of just using global variables and
local
everywhere. It’s so that when we read one piece of code we can understand it without first needing to read, understand and keep in mind every single other piece of the code also.Is it less convenient when every piece of the code is strictly isolated? Of course it is.
E.g. if everything were written using global variables and
local
, you could achieve some cool inheritance-like behaviours by locally temporarily overriding global values. (Much like you can do now by locally overriding subs, which are after all stored in package globals…) This can be very useful in shell programming. But that doesn’t mean I would write any large system in shell.If the storage of instance data is automatically strictly isolated by class, you can write OO code without worrying about how not to cause unintended interactions or choosing to simply live with the risk and then very rarely paying a high price for that. In the example with your popular class on CPAN, the person who writes the subclass won’t stop to put an underscore on the attribute to avoid accidental conflicts, because accidental conflicts cannot happen. And when you write your new version of the class, you will not think about it either. You simply needn’t think about conflicts, because they cannot happen accidentally.
I don’t understand why
$obj->dump
is supposed to be so much less convenient thanDumper($obj)
anyway (as long as there aren’t 1,500 different ways to dump things which all depend on what kind of thing it is). (And as mentioned, if p5-mop becomes core, there’s no reason Data::Dumper couldn’t support it directly, in which case the argument would seem to me to evaporate entirely. I understand even less what you think is still a problem then.)