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

I just wondered if in Perl 6 there is a provision to specify a method on a single object, as in prototype-based languages: e.g. if I have an array @array, I'd like to know if I can define a single method, say, insert(), that would for example push its argument into @array itself if it's not already there. Something like:

# pseudo-code my @array; method @array.insert ($x) { push $_, $x if $x == none($_) }

Replies are listed 'Best First'.
Re: [Perl 6] Object methods on the fly?
by moritz (Cardinal) on Jul 18, 2007 at 06:58 UTC
    First: you can do it for all objects by extending the class that provides the Array functionality. Let's assume it's called Array (I don't know, I have to confess), then you could extend it with the is also trait:

    class Array is also { method insert ($self: $x){ $self.push($x) unless $self.first($x); } }

    Now to return to your original question: There are are surely ways to do it, I don't know if there is a clean one. For example you could write a Role, and assign that Role to the object (I think with the but or does keyword).

      You're on the right track. You want something like:
      @array does role { method insert ($x) { @.push($x) unless any(self) eqv $x; } }
      Arguably we could provide syntactic sugar to reduce that to:
      @array does method insert ($x) { @.push($x) unless any(self) eqv $x; }
      Perhaps that use of does is redundant with but= and could be removed, but it does read better, I think. In any case, doing an operation like this on an object ends up creating an anonymous class that derives from the original class and adds in the extra method, so you don't clobber the original Array class.
        @array does role { method insert ($x) { @.push($x) unless any(self) eqv $x; } }

        Whoa! And it evens runs on Pugs:

        pugs> my @array does role { ....> method insert ($x) { @.push($x) if none(self) eqv $x } ....> } () pugs> my @array=(1..5); pugs> @array.insert($_) for 1,2,6; pugs> say @array 123456 Bool::True

        BTW: Could I put the initialization in the definition too? I tried with

        pugs> my @array does role { ....> method insert ($x) { @.push($x) if none(self) eqv $x } ....> } = (1..5); (1, 2, 3, 4, 5)

        and it works, but it doesn't with the assignment directly to the right of @array, OTOH I'm sure most people would find it to be more intuitive, while this way they would just say: "for clarity, initialize it in a separate statement."

        BTW: why doesn't the following work, instead?

        pugs> my @array does role { ....> multi method insert ($x) { @.push($x) if none(self) eqv $x } ....> multi method insert (@x) { @.insert($_) for @x } ....> } = 1..5; (1, 2, 3, 4, 5) pugs> @array.insert(3..7); pugs> say @array 1234534567 Bool::True

        (If I use *@x, pugs "hangs", instead.)

        BTW: (the last, really!) what is self supposed to be? After all no suitable and short enough variable/pronoun was found? The following is all that pugs can tell me:

        pugs> self macro {Prim ([Pugs.AST.Internals.Val] -> Pugs.AST.Eval.Eval Pugs.AST.I +nternals.Val)}

        Update: Two of the questions asked here were reposted in separate new threads in

      First: you can do it for all objects by extending the class that provides the Array functionality.

      Well, of course I knew that... but I specifically wanted to act on a specific object, which is why I mentioned prototype-based languages.

      Now to return to your original question: There are are surely ways to do it, I don't know if there is a clean one.

      Well, it would be nice if there were: of course what is easy in such relatively simple languages must be simple enough for a language that's supposed to be very complex but still to make hard things easy, and thinking of huffmanization: yes, one wouldn't this kinda things as often as other OO contructs, so it is ok to be slightly more difficult to achieve, but not too much. How much is too much?

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