http://www.perlmonks.org?node_id=1212611

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

Hi

I'm experimenting with some operator overloading and I'm getting bitten by the diamond operator. A numeric "less-then" < in list context is parsed as the start of a diamond glob <>

DB<9> sub bla { bless [@_], "Test" } DB<10> package Test; use overload "<" => sub { warn "works" }; DB<11> bla() < bla works at (eval 18) ... DB<12> bla < bla Unterminated <> operator at (eval 20) ...

I'm aware that I could give bla an empty prototype in line 9 or call it with an empty list (like in line 11), or embrace it in brackets, but I need it to swallow a list of args in other parts.

I'm not very confident there is a way but the almighty monastery is always able to surprise me... ;-)

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
Wikisyntax for the Monastery

update

for those wondering, other operators "work"

DB<13> package Test; use overload ">" => sub { warn "works" }; DB<14> bla > bla works at (eval 21)

Replies are listed 'Best First'.
Re: Disabling the interpretation of diamond <> operator in package?
by haj (Curate) on Apr 10, 2018 at 17:26 UTC

    I'm afraid you can't do this in your Perl program.

    It's about context... and happens in the depths of Perl's toke.c. After the name of a subroutine, '<' might be the start of the sub's parameter list, either some diamond or a heredoc. Unfortunately, the code handling these does not have a fallback to "ok, let's try an operator instead" if it's neither. A '>', on the other hand, does not have any ability to produce a parameter list, and is only tested as an operator.

    All the workarounds seen here - bla(), (bla), &bla, sub bla() - move Perl into a context where only operators are permitted, and I can't come up with anything else.

    BTW: Overloading doesn't play any role here. It only affects code which has been successfully parsed.

      Thanks for checking the parser's code! haj++

      > BTW: Overloading doesn't play any role here. It only affects code which has been successfully parsed.

      Yeah I'm aware of this, but wanted to give some context (no pun intended ;-)

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

Re: Disabling the interpretation of diamond <> operator in package?
by jimpudar (Pilgrim) on Apr 10, 2018 at 00:20 UTC

    Hi LanX,

    Try it like this:

    DB<13> &bla < bla works at ...

    I am not 100% clear on why this works, I would appreciate it if someone else might be able to explain it to us :D

    Best,

    Jim

      Indeed thanks! :)

      see perlsub for the explanation:

      &NAME;       # Makes current @_ visible to called subroutine.

      It's a syntax to pass parameters through, so it can't accept new arguments.

      DB<27> sub tst { [@_] } DB<28> sub outer { &tst } DB<29> x outer(1,2,3) 0 ARRAY(0x2f700e8) 0 1 1 2 2 3 DB<30> x &tst 1,2,3 Number found where operator expected at

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

      update

      for clarification, while interesting, this doesn't answer my question and side effects are too weird...

Re: Disabling the interpretation of diamond <> operator in package?
by choroba (Archbishop) on Apr 10, 2018 at 08:34 UTC
      Thanks! :)

      That's what I meant with "or embrace it in brackets" and it's my preferred workaround at the moment...

      But I'd prefer to disable <> locally...

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

Re: Disabling the interpretation of diamond <> operator in package?
by shmem (Chancellor) on Apr 10, 2018 at 13:13 UTC

    IO::All comes to mind as a module which implemented overloading of "<" and whose technique might work for you. Didn't dig into that though, sorry for laziness.

    update: couldnt resist... scratch that:

    perl -MIO::All -E 'sub bo {"blorf"} sub ba {"bar"} ba < bo' Unterminated <> operator at -e line 1.

    Nope.

    To make that work - I fear (just guessing!) - you'll have to go all the way back to perly.c and modify that, fighting with the magic of "<>".

    update2: this is bug smell to me.

    update3: it looks like in the expression

    foo < bar

    the foo thingy must resolve to something that doesn't consume what follows it on the right, overloading in effect or not, to be parsed as you want it to be parsed:

    $ perl -E 'say < 2' Unterminated <> operator at -e line 1. $ perl -E 'say() < 2' $ perl -E '(say) < 2' $ perl -E 'say scalar(say) < 2' 1 $ perl -E 'sub foo(){1} say foo < 2' 1

    So, no. Using the LHS of < as a function which does or does not take arguments isn't possible, I guess.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'