Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

defining methods on the fly

by flogic (Acolyte)
on Aug 02, 2006 at 19:59 UTC ( [id://565310]=perlmeditation: print w/replies, xml ) Need Help??

I sure this breaks some rules of good programming practice, but it's still cool. And yes I'm planing on using it.
#!/usr/local/bin/perl use warnings; use strict; use Want; sub lvalueMethod($) { my ($name) = @_; my ($package) = caller; my ($fn) = $package . "::" . $name; no strict 'refs'; *{$fn} = sub : lvalue { my $self = shift; local *call = sub { $self->{$name}->(@_); }; if ( !want('LVALUE') && ref( $self->{$name} ) eq 'CODE' ) { goto &call; } $self->{$name}; }; } { package Foo; sub new { bless {}, shift; } main::lvalueMethod("bar"); } my ($x) = Foo->new(); print "$x\n"; $x->bar = 5; print $x->bar, "\n"; $x->bar = sub { print( @_, "\n" ); }; $x->bar("Hello World");

Replies are listed 'Best First'.
Re: defining methods on the fly
by davidrw (Prior) on Aug 02, 2006 at 21:46 UTC
      Hmmm beaten to the punch again... Well at least it was an interesting learning experience.
Re: defining methods on the fly
by diotalevi (Canon) on Aug 03, 2006 at 01:51 UTC

    Just keep in mind that you invalidate your method-lookup cache everytime you invoke that code. Normally once perl knows what function belongs to a method call on an object from a particular class it's able to cache that and not do the work of looking all around ISA. Whenever you change something that could cause the cached value to be incorrect, perl discards all it's cached information. Those somethings are changing @ISA anywhere or altering the symbol table. Glob assignments like you did are one of those explicit reasons. Your code won't even work unless perl does this.

    So just be aware you're making perl's OO slow for you. It has to do work that most people's perl won't have to.

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      hmm... Does the cache get rebuilt? And does the second glob assignment cause the same problem? Class::Accessor::Lvalue (mentioned above) uses an eval. Is the eval faster?

        Yes, the cache is rebuilt. You're just resetting it. All new method lookups after it's been reset are cached until it's reset again. Here's some code I ran in bleadperl which includes a function to look at the version number of the method lookup cache. Things that you do once during setup aren't usually of any account. It's worth blowing your cache then because you get all the utility of whatever it is that you stopped to do and you don't usually incur lots of extra runtime work. When you blow your cache during your run you impact your overall performance because now you're penalizing all the time consuming regular stuff too.

        use B 'sub_generation'; sub show_cache_version { print sub_generation, "\n" } show_cache_version; # 554 { show_cache_version; # 554 local *call = sub { }; show_cache_version; # 555 <- @ISA cache reset } show_cache_version; # 555

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: defining methods on the fly
by Anonymous Monk on Aug 02, 2006 at 22:15 UTC
    I sure this breaks some rules of good programming practice, but it's still cool. And yes I'm planing on using it.

    I hate this attitude. :-(

    In all those threads that asked why people were abandoning Perl: well, I think it's mostly this point of view: the belief that "cool" trumps "good practice", "flexible" trumps "well defined", and "clever" trumps "simple".

    I hate "cool" code. I like simple code that works. :-(

      I hate "cool" code. I like simple code that works.

      I hate this attitude. "Cool", or idiomatic Perl is simply code that uses the full expressive power of Perl.

      If you do not appreciate just how much your every day Perl programmer relies on Perl's coolness, go learn Cobol'74 (or even '85), or Fortran IV. Once you've spent a few days dealing with the "simplicity" of those languages, you'll soon realise that almost every line of every Perl program is packed with "cool" idioms--including your own code.

      The difference between the judgement of "acceptable cool", and unacceptable cool Perl idioms generally amounts to whatever point the person judging reached before they decided that they had learnt enough Perl. At that point, anything they did not bother to familiarise themselves with--so that they could read and understand "advanced Perl idioms", rather than throwing their arms up in disgust at anything that requires them to think twice about--is distained.

      Cool it not an antonym of good practice.

      Flexible is not an antonym of well defined.

      Clever is not an antonym of simple.

      That does not mean that you cannot write bad code using cool idioms, but it is equally possible, just as easy, and arguably more prevelent, to write bad code using "simple" Perl.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Don't lose sight of the fact that the OP was unabashedly admitting that 'good programming practices' were being ignored in favor of the 'coolness' of the idiom. That's where I draw the line -- use all the expressive power of Perl you like, but do it consistently and carefully and, for crying out loud, thoroughly comment anything that is especially clever, elegant or obscure. I've had several occasions to bewail the unnecessary complexity of some code I had to maintain, only to discover that it was something I wrote (in one case, only a few months before).


        No good deed goes unpunished. -- (attributed to) Oscar Wilde

        I'm curious, did you read and understand the entire code you are commenting on? Your response is like someone saying "I'm sure it won't be good for me but I love the taste of mad cow brains in my dog stew" and then responding with a list of many fine Cambodian restaurants that serve dog stew*.

        The primary feature of the code is not auto generation of methods, but of allowing methods to be replaced at will by assigning a code ref to an invocation of the method to be replaced.

        I am not too surprised that there may be rare situations where replacing method implementations willy nilly might be somewhat appropriate. I also suspect that I would manage to avoid such situations by virtue of a more restrained design sense and likely would eventually regret it if I didn't.

        But I agree with even the original poster that using the same one mechanism to change attribute values and to replace the methods used to implement an attribute is a violation of good coding practices. Such radically different operations should look different. Further, assigning a value to an attribute should look fairly innocuous while replacing a method implementation long after the object(s) have been created should provide visual cues as to how unusual of an operation it is.

        * Yes, that is a horrible analogy, which is appropriate as also being an analogy of the other horrible analogy. :)

        Applauses++


        Cool it not an antonym of good practice.

        Yes, it is. "Cool" means the ego of the programmer has somehow gotten involved, emotion has gotten involved, and the programmmer has run off the rails of professionalism.

        Good code is not "cool", because ego is not involved. The code is correct, and works. How the programmer *feels* about the code is irrelevant. Good code and good practice stands on it's own merits; "cool", and other subjective, emotional metrics do not.

        Flexible is not an antonym of well defined.

        "This function is ultimately flexible, just like a Turing machine!!! In fact, it emulates a Turing machine!" Which means, means, by definitiion, that it's impact on the problem to be solved is vaguely defined; absolutely nothing has been specified about the behaviour of how the final result will be generated. Running one turing machine inside another is the ultimate in power, flexiblity... and pointlessness.

        Clever is not an antonym of simple.

        Clever code requires thought to understand, because it's clever and tricky, and showcases the ego of the programmer. Simple code instead seeks to document the program requires, even as it fulfills them.

        idiomatic Perl is simply code that uses the full expressive power of Perl

        And using the full expressive power of any language is a mistake. I'm writing this in comprehensible English, not using the full expressive power of the language. If I tried to do so, neither one of us could understand it.

        The goal of programming is to write simple, correct, understandable code, not to stroke programmer ego, to be cool, to appeal to mathematical sensibilities, or any of a thousand mental pitfalls that modern programmers fall prey to.

        The difference between the judgement of "acceptable cool", and unacceptable cool Perl idioms generally amounts to whatever point the person judging reached before they decided that they had learnt enough Perl.

        Ad hominem, and unfair. I refuse to use many of the ugly idioms perl provides, because they grow increasingly complicated to understand, and I know, from experience, that my fellow programmers will fail to understand them even if I myself feel ever-so-clever for using them.

        I once wrote a "clever" one-line regexp, as an intellectual diversion. It never went near production. I showed it to my co-workers, wrote the requisite 20 lines of documentation to explain it, then re-wrote it as ten simple lines of obvious code, and put those into production, because that was the obvious thing, so that was the correct thing to write.

        That does not mean that you cannot write bad code using cool idioms, but it is equally possible, just as easy, and arguably more prevelent, to write bad code using "simple" Perl.

        Anyone can fix simple code, good or bad. You may not agree with what it does, but what it does is obvious. No one can fix bad, clever code without serious effort; it masks both the intent and effect of the code *simultaneously*, whereas simple code is bad at hiding both.

        I'm tired of tracing through 3,000 line mazes only to find out that partway through, some idiot quietly re-defined the function I was tracking...

          A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (8)
As of 2024-04-23 10:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found