dragonchild has asked for the wisdom of the Perl Monks concerning the following question:

I've got a function that defines a class and is called as so:
package Foo; class { attr qw( foo bar ); method floober => signature ( Int, Int ), body { ... }; };

It's defined as so:

sub class (&) { my ($sub) = @_; $sub->(); # Do some book-keeping in the caller's namespace. }

I would really like to optionally call it as so:

class 'Foo' is { };
where is() is defined as a syntactic sugar passthrough as so:
sub is (&) { return @_ }

This would mean that the prototype for class() would have to be ($&), not (&). Is this even possible with P5's borken prototypes?


My criteria for good software:
  1. Does it work?
  2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

Replies are listed 'Best First'.
Re: Prototypes and hand-written MMD (Ah! No!!)
by tye (Sage) on Jan 10, 2006 at 07:46 UTC

    Your question was nearly incomprehensible because you start out with a code example that is simply a syntax error. My first guess was that you were asking a Perl6 question but didn't bother to say so.

    The problem you'll run into is more likely that you can't have two different prototypes for class() (plus a bunch of other problems). But ignoring your first proposal, sub class(&), (since it is probably incompatible with your primary question) you are incorrect in your thinking on how to make class 'Foo' is { ... } work...

    The prototype for sub class shouldn't be ($&) since you aren't putting a block as the second argument to class() (tho, & only really works for first arguments anyway). Your second argument to class() is a plain expression that returns a code reference. The prototype of is() is what handles the bare block, not the prototype of class() at all.

    The next problem is that you don't want to put a comma between 'Foo' and is{...}. That means you've got that extra-vague syntax that /might/ get interpretted as indirection object syntax (but might not, and is pretty easy to break besides).

    So, Perl might interpret your code as 'Foo'->class( is { ... } ) (but it might not, depending).

    But my primary advice is to turn back now. Please don't make another module that tries to fool the perl interpretter into understanding some non-Perl5 syntax. Let the people reading Perl5 code and expecting to find Perl5 code understand the code. Attempts to invent alternate syntax always end up being quite fragile; that is, they often confuse the computer in addition to confusing the human.

    Next you can try source filters. I hope you have the sense not to, however.

    - tye        

      Sorry about that. I should have posted a link to How does strict determine if something is legally declared? which explains where I get that syntax and what I'm doing. I'm not asking a P6 question in disguise - it really is a P5 question. And, I don't (currently) intend on releasing this code to CPAN - this is just a fun little "Yet Another Perl OO Framework" for my own edification of some squirrelly P5 corners I haven't explored yet. So, to better phrase the question . . .

      I have a function defined as so:

      sub foo (&) { my ($sub) = @_; ... } # Usage: foo { ... };
      I want to also support the following usage: foo 'Bar' is { ... }; which requires a ($$) prototype. (You are correct in that it's $$, not $&.)

      Is there a way to do it using the same function name or do I have to use two different functions?


      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

        You'd need two different functions. The prototype is to help perl parse your code and perl doesn't provide for conditional prototypes.

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Prototypes and hand-written MMD
by PodMaster (Abbot) on Jan 10, 2006 at 04:24 UTC
    From what I've read, you would need (&@). 'perldoc perlsub'
    The interesting thing about "&" is that you can generate new syntax with it, provided it's in the initial position:
    sub try (&@) { my($try,$catch) = @_; eval { &$try }; if ($@) { local $_ = $@; &$catch; } } sub catch (&) { $_[0] } try { die "phooey"; } catch { /phooey/ and print "unphooey\n"; };
    Although I'm not quite sure it would work.

    update: 2006-01-10 00:06:08 PST The prototype magic that allows you to avoid a comma only works with codeblocks (just like do/grep/map), so I'm pretty sure now that you can't avoid it.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: Prototypes and hand-written MMD
by ysth (Canon) on Jan 10, 2006 at 08:25 UTC
    I think the best you're going to get is
    sub class ($$) { ... } sub is (&) { return @_ } class Foo => is { ... };
Re: Prototypes and hand-written MMD
by ph713 (Pilgrim) on Jan 11, 2006 at 01:36 UTC
    Don't forget that closures created by using & prototypes can be dangerous. They leak memory under certain patterns of usage, and can generally be a PITA to debug.

    Honestly, anything you could do in the past with the & prototype can probably be done cleaner and without closure-leakage issues using Source Filters (see perldoc perlfilter). The only reason to avoid that route is if you need to support pre-5.8 perls without installing optional modules or something.

      Do you have any references to information on this leak?

      Or you're sane and avoid source filters. Source filters are for plague bearers, silly!

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊