Beefy Boxes and Bandwidth Generously Provided by pair Networks DiBona
laziness, impatience, and hubris
 
PerlMonks  

Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI ;)

by LanX (Abbot)
on Dec 13, 2013 at 18:30 UTC ( #1067053=perlmeditation: print w/ replies, xml ) Need Help??

Perl is like one of these old text adventures, you keep collecting things from perldoc and suddenly you can open secret doors ...

There has always been much discussion (well flames) about a language idiom called "autoboxing"² missing in Perl.

I just stumbled over a way of emulating it in Perl by using "method" references.

The idiom

Write an anonymous sub like a method, i.e. take $_[0] as $self.

Then call thing->$method_ref(args) and thing doesn't need to be blessed.

DB<158> %h=(); DB<159> ref $h{a}{b}[2]{c} # not an object => "" DB<160> $cycle = sub { $_[0]++; $_[0] %= $_[1] } DB<161> $h{a}{b}[2]{c}->$cycle(3); \%h => { a => { b => [undef, undef, { c => 1 }] } } DB<162> $h{a}{b}[2]{c}->$cycle(3); \%h => { a => { b => [undef, undef, { c => 2 }] } } DB<163> $h{a}{b}[2]{c}->$cycle(3); \%h => { a => { b => [undef, undef, { c => 0 }] } }

The documentation
See perlop:

The Arrow Operator

...

Otherwise, the right side is a method name or a simple scalar variable containing either the method name or a subroutine reference, and the left side must be either an object (a blessed reference) or a class name (that is, a package name). See perlobj.

I used this technique in the past to either

  • speed up method calls (no lookup necessary) and/or
  • to realize 100% private methods (lexical scoping)
IIRC it's explained in detail somewhere in the "perloo*" group of perldocs...

The reasoning

See wikipedia, in short autoboxing allows to use a method call syntax on "things" which aren't blessed objects, like

DB<100> $a=5 => 5 DB<101> $a->inc Can't call method "inc" without a package or object reference

The general idea is to combine the flexibility of method call syntax, avoiding the overhead to create a real object.

For instance a (contrived) example is JS which has the primitive type "string" and the class¹ "String". This allows to write

'literal string'.match(/string/)

One way Perl could profit from such a syntax are nested data structures, where often manipulations result in ugly unDRYness and lots of nested punctuation.

A simple example: ¹

push @newelements, @{ $a{blossom}{caterpillar}{$loopvalue}[CONSTANT] +{Iforgot} }

in JS you can not only avoid the sigil, you can also _chain_ method calls

a["blossom"]["caterpillar"][loopvalue][CONSTANT]["Iforgot"].push(ele +ments).shift()

The alternatives

There are more reasons to like autoboxing, there were attempts to overload -> to allow this in autobox but this is considered to be a too fragile hack.

Attempts to include this syntax as a language feature were regularly rejected / ignored / postponed.

IIRC does Perl6 intend to have it right away from the start.

And now ->$RFC

I was urged in the CB to write a meditation ASAP, so pardon me for typos, broken links and untested code³ which will need updates.

Being aware of fundamentalists hating this coding style I'm now counting the seconds till the outrage starts... =)

Others may want to add some other use cases ...

Cheers Rolf

( addicted to the Perl Programming Language)

Footnotes

1) yes I know that push was extended "recently" to allow $arr_refs but 5.10 is still relevant

²) aka "boxing" aka "wrapper-classes" see also: wikipedia

³) and euphoria induced by coffee abuse

Comment on Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI ;)
Select or Download Code
Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI )
by taint (Hermit) on Dec 13, 2013 at 19:43 UTC
    OMG It's PPV (Pure Perl Voodoo). It's magic!

    I'll be chewing on this for quite some time.
    Thanks LanX, for sharing this!

    ++

    --Chris

    Yes. What say about me, is true.
    
Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI )
by BrowserUk (Pope) on Dec 13, 2013 at 20:25 UTC
    ... the flexibility of method call syntax ...

    Does ... not ... compute.

    (It is the very antithesis of TIMTOWTDI.)


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      wow, took you nearly 2 hours...

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      I agree, but to be slightly more constructive...

      A truly "flexible" solution would be to use the existing function call syntax, but extend it to call methods. (You can do this now with a UNIVERSAL::AUTOLOAD override, though that's fiddly and slow.) Writing foo($x,$y) as $x->foo($y) makes the first argument look special, where it is not for functions and multi-methods. Common Lisp got this right.

        > but to be slightly more constructive...

        indeed! =)

        > Writing foo($x,$y) as $x->foo($y) makes the first argument look special, where it is not for functions and multi-methods.

        How is the first argument not special in the shown examples?

        For instance does push @a, 3 change the first parameter.

        Equally the ->cycle() example.

        And how is the bind operator matches= $x=~ /regex/ not special in Perl? Is it really better than @matches = $x->match(/regex/) ?

        Though I agree that something like $y= $x->plus(5) breaks symmetry, but thats not my intention.

        So in short: I think your critic doesn't apply to mutators, where the first arg IS special.

        Additionally in cases where dereferencing is needed, this can significantly simplify the syntax (multiple nested curlies around HoAoH do not facilitate readability)

        Anyway I don't claim it to be a full replacement of real autoboxing, holding the method in $variable namespace is - well - not "optimal".

        And the fact that only scalars are allowed on LHS is also a limitation!

        I hope it's obvious that "Yes we can!" and "How I finally learned to love ..." were ironic references.

        I wanted to share and discuss this idiom, but I don't expect a Nobel prize for coolness like Obama or consider me half as genius as Dr Strangelove...

        In this sense Hail! Mr President! xD

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        update

        > Common Lisp got this right.

        Could you plz elaborate, I don't know Common Lisp, (only eLISP¹)!

        Something like wrapper functions which check the type of the first argument (ref) and call a method based on their own name (caller) are no problem in Perl.

        footnotes

        ¹) mentioned to please Your Mother :)

        I agree, but to be slightly more constructive...

        Having shown the "reasoning" given in the OP is a total logical fallacy, there is no foundation upon which to construct anything positive. Further comment would be unchivalrous.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI )
by choroba (Abbot) on Dec 13, 2013 at 20:52 UTC
    Genial!

    One of the interesting features might be that chains of functions like grep could be read left to right, not right to left. The arrow does not work on lists nor arrays (it imposes scalar context, so it operates on the last member or size, respectively):

    #!/usr/bin/perl use warnings; use strict; my $join = sub {join pop, @{shift()} }; my $grep = sub { my $f = pop; [ grep {$f->($_)} @{shift()} ]}; my $say = sub { print @_, "\n" }; [1 .. 120]->$grep(sub { /0/ } ) ->$grep(sub { /1/ } ) ->$join("\n") ->$say("\nIt works!");

    You can also define a grep-like "method" of a regex or code ref, or make the function decide based on the type of the argument:

    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; my $grep = sub { my $f = shift; return { CODE => sub { grep $f->($_), @_ }, Regexp => sub { grep /$f/, @_ }, q() => sub { grep $_ <= $f, @_ }, }->{ref $f}->(@_); }; say for qr/[01]/->$grep(1 .. 100); say '-' x 20; say for sub { not $_ % 10 }->$grep(1 .. 100); say '-' x 20; say for 5->$grep(1 .. 100);
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      > The arrow does not work on lists nor arrays (it imposes scalar context, so it operates on the last member or size, respectively):

      Sadly yes, thats one advantage of autobox, were (IIRC¹) one needs to overload arrow to achieve this.

      OTOH it's far faster then a normal method call, there is no inheritance chain look-up at run time.

      Another important difference is that a method "pollutes" the variable namespace, i.e. variables called '$grep' could cause conflicts.

      Also importing lexical variables from packages won't be easy ( while I can imagine an eval -hack in importer). So importing such methods could lead to package vars.

      But "Pro" or "Con" depends on the perspective.

      If the intention is to port an OO language like JS or Ruby and to reflect syntax and semantic this should be a cool approach, since most of those languages have no separate namesspaces (no sigils!)

      Another use case is to have local ad-hoc wrapper methods for objects w/o manipulating corresponding classes.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      Update

      ¹) at least thats what I figured out the last time I looked into it, but my Perl foo was limited back then..

      The arrow does not work on lists nor arrays (it imposes scalar context +, so it operates on the last member or size, respectively):

      Deeper meditation ...=)

      Non-scalars are usually simple variables, so the normal function-call syntax can be comfortably applied, for the nested cases you can use the method syntax:

      DB<134> sub multi (\@) { print "@{$_[0]}" } DB<135> $multi=\&multi => sub { "???" } DB<136> @array=1..5 => (1, 2, 3, 4, 5) DB<137> multi @array 1 2 3 4 5 DB<141> (\@array)->$multi() 1 2 3 4 5 DB<138> $h[0][1][2]=\@array => [1, 2, 3, 4, 5] DB<139> $h[0][1][2]->$multi() 1 2 3 4 5

      I can think of cases were this flexibility of interface comes handy.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI ;)
by Anonymous Monk on Dec 13, 2013 at 22:07 UTC

    There has always been much discussion (well flames) about a language idiom called "autoboxing"² missing in Perl.

    Sure there hasn't, autobox in convenient form since 2003 ...

      Well as mentioned...

      tl;dr ?!?

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI ;)
by tobyink (Abbot) on Dec 13, 2013 at 22:10 UTC

    There are a number of modules on CPAN that already do this - e.g. Safe::Isa, Fauxtobox.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      Thanks, I didn't expect to be the first! =)

      Though the two modules you listed are from 2012 and 2013.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI ;)
by boftx (Hermit) on Dec 14, 2013 at 04:05 UTC

    Someone much wiser than me once said it is better to remain silent and be thought a fool than to open one's mouth and remove all doubt.

    That being said ... I feel compelled to ask the (obvious?) question of what does this buy us? To me, it looks a lot like using postfix notation in a way that does not contribute to making Perl read like English. That is, where next unless $foo > $bar; reads like a sentence in English, @foo->push($bar) doesn't, to me at least. (I should point out that I take strong exception to PBP discouraging postfix notation.)

    I think my point can be demonstrated even better when given something like 'Hello, world!'->upper();. There is no need whatsoever for an argument to "upper" in that case. How is that more clear as to intent than upper('Hello, world!');? (I will grant that a modification-in-place such as $foo->upper() might be more concise that $foo = upper($foo), but clarity would still be open to debate, especially given a use-case such as say $foo->upper();.)

    I can see where this could be useful for a language that is not as flexible or useful as Perl (i.e. strongly typed languages that resemble a straight-jacket) but I don't see that it adds to Perl other than contributing to (excessive?) code bloat in an effort to add something that Perl might not really need given its existing versatility.

    It helps to remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.
      > what does this buy us?

      What does it cost us?

      For me the method notation is an _alternative_ not an obligation (TIMTOWTDI).

      YMMV and I'm not radical about it.

      I don't wanna repeat all given arguments in details, so just telegram style:

      • autoboxing allows a method API at primitive types, that is normal operations like ++ have no speed penalty.
      • avoid multiple parens, e.g for dereferencing like @{ ...}
      • readability! With 2 arguments the methodname and not a comma separates in between like a binary operator  xxxxx->push yyyyy
      • in deeply nested datastructures the operation is written next to the addressed element
      • ease of porting from other languages
      • no need for prototypes
      • mutators highlight the changed argument on LHS

      I agree that upper $foo is easier than $foo->$upper but I personally prefer

      $personal{Berlin}{employee}[9]{name}->$upper to see that the name is uppercased.

      and better $personal{Berlin}{employee}->length() than scalar @{ $personal{Berlin}{employee} }

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      update

      > reads like a sentence in English,

      After some meditation, I realize that many exceptions to "reads naturally" rule in Perl are just ignored, which cause a logical break.

      For instance nobody says

      "rewrite from personal in Berlin which is employee of Number 9 the name".

      rewrite( $personal{Berlin}{employee}[9]{name} )

      You rather say "rewrite the name of the 9th employee in the Berlin catalog of employees"

      The problem is that nested data structures are top-down, but we can't code

      rewrite {name}<-[9]<-{employee}<-{Berlin}<-$personal

      (well we could, but how likely is that to be implemented?)

      OTOH human language is flexible enough to use a passive voice construct

      "From the catalog of Berlin the employee number 9's name has to be (or is) rewritten."

      $personal{Berlin}{employee}[9]{name}->rewrite()

      I hope you get the point, with deeply nested top-down data structures a method call helps to put the verb near the subject.

      Just read methods as passive constructs.

      Greetings boftx.

      While I completely see, and can agree on your point. I think it exemplifies Perl's ability to cater to some areas (or edge cases) that any other language wouldn't even consider making possible. But maybe that's because it's an "interpreted" language? Dunno. I'll really need to ponder that more. But initially, that's my take on it. And let us not forget; Wall was trained as a linguist, and the design of Perl is very much informed by linguistic principles.

      Say what you will about programing languages. But if there's any comparison to the spoken language, if I've learned anything. I've learned, it's all a matter of interpretation -- what's one to one, is something completely different, to another. Or, in other terms; TMTOWTDI ;)

      No disrespect intended. Just my take on it. :)

      --Chris

      Yes. What say about me, is true.
      
      My last answer was more about the general properties of method-syntax.

      But there is also a very specific Perl issue, which became clearer after playing around.

      Perl has a syntactical ambiguity between scalars and one element lists.

      So writing something like $ref->functionality clearly operates on the referenced elements while  functionality $ref might operate on the "listed" reference itself.

      Methodcall gives us an opportunity to add new flavors of grep which operate on references without the need to rename it grepref.

      Think of a hashgrep which could be written  $href->grep sub { $_->key =~ /x/ }

      (the need to write sub is due to another syntactic ambiguity: "block" vs "literal hash")

      background

      For instance it's not trivial/possible to augment the classical

       grep BLOCK  LIST

      to also mean

       grep BLOCK AREF

      Because it's not possible to rule out that  grep {...} $aref means "operate on the list with the one element $aref".

      Languages where "everything is an object/reference" w/o lists don't have this abiguity.

      They need workarounds for lists, for instance do some JS dialects introduce list-assignments by using array syntax:

       [a,b] = [b,a] ;// swap elements Mozilla JS 1.7

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: Autoboxing ... "Yes We Can" ( or how I learned to love TIMTOWTDI ;)
by hdb (Parson) on Dec 14, 2013 at 10:03 UTC

    Again, a fascinating discussion on PerlMonks. To me, it is completely incomprehensible, why there are such strong opinions put forward.

    After all, no change to the language is required, there is no performance implication to anyone who does not want to make use of this proposal. No existing feature of the language will be disabled or discarded. Everything is legal Perl since long time.

    Just a clash of philosophies.

    No need to get excited.

    Calm down, fellow monks.

    P.S.: If one could now find out how postfix dereference can be done this way, we can end another fruitless discussion.

    P.P.S.: Like this (ugly)

    my $asArray = sub { @{ $_[0] } }; my $aref = [ 1, 2, 3 ]; print "$_\n" for $aref->$asArray;

      First consider, how does eschewing all the possible operator syntaxes -- prefix, postfix, infix, circumfix -- along with all precedence; in favour of a single operator syntax, increase flexibility?

      Then read How non-member functions improve encapsulation in full. Then note the author.

      Then consider how the ability to call any function as a "method" of any random variable -- regardless of anything -- will play amongst the Duck typing is no typing crowd.

      And I'm far from excited. I'm bored to see this being raked over again; especially upon such scant & broken reasoning.

      There is simply no reason to lose one's cool in order to counter such illogicality.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Who talked about eschewing anything?

        How does adding another way to TIMTOWTDI make the whole thing less flexible?

      > To me, it is completely incomprehensible, why there are such strong opinions put forward.

      Balancing principles like "reads like a human language" and "orthogonal features¹" is not easy.

      Especially if they are confronted with...

      • "avoids too much nesting"
      • "backward compatible" (Perl4)
      • "maintainable implementation"
      • "portable implementation"
      • "multi-paradigm"
      • "glue language"
      • "combines features of older languages"
      • "Huffman coding"
      • ...²
      • "CLI/one-liner friendly "
      • "fast"
      • "extendable"
      • "suitable for project guidelines"
      • "DWIM"
      • "DRY"
      • "self documenting"

      ... it stops being straight forward science and becomes empirical.

      Seeing the big picture is complicated and long discussions become annoying.

      After some time many end just reacting on trigger signals, like

      "METHODS! They want to transform Perl to Java!!!".

      > P.P.S.: Like this (ugly)

      Indeed, not the best example! :)

      But I agree a well designed autoboxing (i.e. w/o the need of a $-sigil) would help a lot here.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

      ¹) small set of basic rules which can be easily learned and consistently recombined.

      ²) "remembering all principles" (from here on some items were added)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://1067053]
Approved by ww
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (17)
As of 2014-04-17 17:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (453 votes), past polls