Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Class::SelfMethods

by John M. Dlugosz (Monsignor)
on Sep 15, 2003 at 20:00 UTC ( [id://291640]=perlmeditation: print w/replies, xml ) Need Help??

I was looking at Class::SelfMethods as a possible module to use in a project. I would like to share my thoughts and musings on it.

First of all, I think it's very beautiful and simple. It apparently was written by someone who had also written a more straightforward Self-like programming model for Perl, and he was familiar with others. But this design took a step back and meant to offer the interesting charcteristcs that Self-programming brings to the table but integrated nicely with the Perl way of doing things.

In that, it does indeed. Basically, you can write a class in the normal way, inheriting from other classes and whatever. But you can include this mechanism to autogenerate accessors that can call a normal package-based method or an overridden attribute or per-instance code override.

The code is very small, and it's easy enough to understand so the lack of enlightenment in the docs is not a big issue. The docs explain things ok I guess, but leave me wondering about the right way to apply it. Specifically, what about setting attributes?

My impression from the docs is that the _SET suffixed function is for setting up a new per-instance slot. I thought of the slot itself as distinct from the current value within that slot. So, consider a method that returns the current value or sets a new value:

$oldval= $x->name(); # get name $x->name ("Smith"); # set name
Although not addressed, a member that alters the state (like name above, or with separatly-named functions) would certainly be callable and Selfable using the SelfMethod mechanism, though he always speaks of accessors never mutators.

But, the confusing part is that he seems to like the _SET suffixed function for setting values as well as slots. Consider the member name("Smith") above will call the code to operate on the parameter. The method can check that the value "Smith" is legal, massage it, update other dependant fields, clear cached data, and whatever else. That's why we like mutators instead of reaching in and altering data fields directly.

But, $x->name_SET("Smith") will not call that mutator code, but will in fact replace it in this instance with a constant. That is, using the _SET feature for values as opposed to new slot behavior is exactly like direct access to field data, only worse because it will bypass and dispose the existing mutator.

It also defeats any error checking. If I access something that doesn't exist, such as $x->nane, this gives an error. But $x->nane_SET("Smith") will not. This is the same problem as for un-declared globals without using strict, or direct field access via a hash.

So, I think that it should generate methods that read and write, for the hash-field case. That is, if there is a field called name then SelfMethods will arrange that calling $x->name() will return $$x{name}, and calling $x->name_SET("Smith") will set $${name}="Smith". I would like to not use the _SET form for changing the value, but have the SelfMethods</code> support $x->name("Smith"). Right now that statement will still fetch the field, ignore the parameter, and give no warning.

(whether it overloads the same function for get/set or has distinct names for each is not the issue. Point is, auto-generate a mutator for field-based properties that is distinct from changing the slot itself.)

Another thing SelfMethods does is use an underscore prefix for package-based methods. That is, you write a sub _foo that will be called if $x->foo has no per-instance override. This makes sence, and is a minimal solution. My issue isn't with the semantics, but rather that we already use names beginning with an underscore for private methods. I think a different sort of decoration is in order for this new purpose.

—John

Replies are listed 'Best First'.
Re: Class::SelfMethods
by gjb (Vicar) on Sep 15, 2003 at 22:34 UTC

    I don't want to sound like a spoil sport, but recently Allen Holub has written a rather interesting article for JavaWorld with the provoking title "Why getter and setter methods are evil".

    In the article he cites a variety of reasons why to avoid getters/setters and maintains that an abundance of such methods is a sure sign of poor OO design. It's definitely worth the read.

    Just my 2 cents, -gjb-

      Thanks for the reference.

      I have a beef against getters/setters myself, but from the point of view that automatically generating get/set methods to match all the data fields is missing the point. Holub is against obtaining information from an object in general, summed up by his description from the CRC methodology:

      You may not ask for the information you need to do something. Rather, you must ask the collaborator who has the information to do the work. It's okay to pass to that collaborator information he needs to do the work, but keep this interaction to a minimum.
      I intuit that to some extent. In my OO design, if code asks X for a bunch of stuff and then does something, then that something really should have been a member of X.

      I don't follow what he said about how he puts the drawYourself member in the class but really implements it someplace else. Hmm, maybe I do: user of the object calls drawYourself, but it just turns around and calls a function in the UI layer, passing it the relevant information (not the whole object). I see, that's an example of "send it out but don't ask for it".

      I don't see how that fits his thesis about being able to change the types involved. Which ever class really implements the code (assuming it's implemented in only one place) still needs to change. All the code it calls out to, passing the information needed, needs to have their parameters changed. How is that different from changing the types of variables where information is asked for?

      --John

Re: Class::SelfMethods
by simonm (Vicar) on Sep 16, 2003 at 22:17 UTC
    I'm not entirely sure I understand the precise behavior that the OP would like to see, but perhaps something like this is closer to what they have in mind:
    package MyObj; use Class::MakeMethods::Autoload { 'new' => 'Template::Hash::new', '.*' => 'Template::Inheritable::code_or_scalar -method', };

    The usage is only slightly different from Class::SelfMethod:

    my $person = MyObj->new(); # Simple string get/set $person->name("Smith"); print $person->name(); # Define a method on the class so all instances will share it MyObj->greeting( sub { "Hello, " . (shift)->name } ); print $person->greeting(); # Override the method for a particular instance $person->greeting( sub { "Hi " . (shift)->name } ); print $person->greeting(); # You can change the method repeatedly with the same syntax: $person->greeting( sub { "Hi there!" } ); print $person->greeting();
    If you want a different interface, you may be able to specify it by changing the parameters passed to Class::MakeMethods::Autoload.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://291640]
Approved by Enlil
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (2)
As of 2024-04-26 03:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found