Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
I, like many people (See the number of Class::* modules on CPAN), have sought to make oop easier in perl. After looking at many different ideas including closure objects, inside-out objects, and Class::Struct I came up with my own way of creating objects that looks something like this:
#!/usr/bin/perl package Foo; use Class::FIOC; use strict; my $nextid=1; sub new { my $class = shift; my %args = @_; my $first = $args{first} || "unknown"; my $surname = $args{surname} || "unknown"; my $id = $nextid++; methods { fullname=>sub { return "$first $surname"; }, surname=>sub{ if (@_==2) { $surname = pop; } return $surname; }, first=>sub { if (@_==2) { $first=pop; } return $first; }, id=>sub{ return $id; }, debug=>sub{ print "First = $first\nSurname=$surname\nID=$id\n\n"; } }; } my $foo = new Foo(first=>"Fred",surname=>"Flintstone"); print $foo->first."\n"; print $foo->surname."\n"; print $foo->id."\n"; print $foo->fullname."\n"; $foo->debug; $foo = new Foo(first=>"Barney",surname=>"Rubble"); print $foo->first."\n"; print $foo->surname."\n"; print $foo->id."\n"; print $foo->fullname."\n"; $foo->debug;
My goals were to make the syntax easy without using source filters, to ensure encapsulation, to allow inheritance, to make access to instance variables inside of methods easy, and to have as little overhead as possible. I call it a functional object because the actually object can be thought of a collection of functions that share some lexical variables, more than a collection of variables that you can call methods on. I call it an inside out object because if you look at the source code for FIOC.pm below, you can see that the functions are actually stored in a hash outside of object and the object is just a key to those hashes like in Abigail-II's inside out objects. It is called a closure object because the functions that make up an object are all closures.
I think I made my goal of making the syntax simple. Class::FIOC imports just one method "methods" which takes a hash of method names and subs and returns a blessed object. I think I made my goal of encapsulation because there is no easy way to access the instance variables and by using an inside-out design for the functions, it makes it difficult to mess with them. I haven't developed the inheritance part very much, but I think because the objects themselves are just keys I could probably modify it so objects blessed as other things could inherit from these objects.
The one thing that I am not sure about is the overhead part. It is my understanding that when closures are used that the different version of a closure share the same code but just use a different set of lexicals. So I think that the overhead for an individual object should just be the set of lexicals plus the references to the CODE objects. Is this a correct understanding of how closures work? My second question about overhead is the use of the "goto" in the methods (See the source for "methods" below). The documentation for goto says:
The "goto-&NAME" form is quite different from the other forms of "g +oto". In fact, it isn't a goto in the normal sense at all, and doesn +'t have the stigma associated with other gotos.
I interperted this as this form of goto does not have the same overhead as other forms of goto. I figure that if there is a little overhead that cost can be made up by the fact that inside the actual method there is no overhead for looking up an instance variable in a hash table or array. Is this a good assumption? Finally, I would like to know what my fellow monks think of this idea. It still needs some fleshing out, but I would like to know if there are some glaring flaws I have overlooked before I work on it anymore. Thanks!
package Class::FIOC; require Exporter; use strict; our @ISA = qw(Exporter); our @EXPORT = qw(methods); our %Classes; our $DEBUG=0; sub methods { my $class = caller(); my %method_map = %{+shift}; # any old ref will work, one day maybe the user can choose the ref my $self = bless [],$class; # see if we already have seen this class before if (my $method_names=$Classes{$class}) { while (my ($name,$ref)=each(%method_map)) { # validate reference refers to CODE if (ref($ref) ne "CODE") { die "values passed to 'methods' hash must be CODE references!\n"; } # validate that this is not a new method name # maybe new method names should be allowed? I don't know if (my $hash=$method_names->{$name}) { $hash->{$self}=$ref; }else { die "Cannot add new method '$name' to class $class!\n"; } } } else { my %method_names; while (my($name,$ref)=each(%method_map)) { my $public = $name=~s/^\+//; my %hash; # validate name is legal identifier if ($name!~/^[A-Za-z_]\w+/) { die "'$name' is not a valid identifier!\n"; } # validate reference refers to CODE if (ref($ref) ne "CODE") { die "values passed to 'methods' hash must be CODE references!\n"; } # create method my $eval = "sub $class\:\:$name { goto \$hash{\$_[0]}}\n"; eval $eval; # save the hash for later so we can store other instance methods + in it $method_names{$name}=\%hash; $hash{$self}=$ref; } $Classes{$class}=\%method_names; no strict 'refs'; *{"$class\:\:DESTROY"} = sub { my $self = shift; while (my($name,$method)=each(%method_names)) { delete $method->{$self}; if ($DEBUG) { print "Destroying '$name' method for $self\n"; } } } } return $self; } 1;

In reply to Functional Inside Out Closure Objects by fletcher_the_dog

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others wandering the Monastery: (5)
    As of 2020-05-29 10:39 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?
      If programming languages were movie genres, Perl would be:















      Results (169 votes). Check out past polls.

      Notices?