in reply to Re^3: Split tab-separated file into separate files, based on column name (open on demand)
in thread Split tab-separated file into separate files, based on column name

So it got me curious, and I did a quick-and-dirty test implementation of scalar > file() and fstream() << scalar. But I get the "useless use of ... in void context" warnings.

So my tangential question: Is there a way to "export" the no warnings 'void' from inside the streaming package, rather than requiring it in ::main? It would be best if it could just turn off the warnings for the streaming objects, but leave the warnings on for non-overloaded uses of comparison and bitshift. I tried putting the no-warnings inside the overloaded functions, to try to keep the scope limited, but that's not the right place to prevent the warning. (Yes, I understand this isn't necessarily good practice, or "nice" to the external user. This is just for my own curiosity, and not something I'd put in practical code.)

#!/usr/bin/perl -l use warnings; use strict; # [id://11121105] # as suggested, have file() return an object which overloads > and >>, + so you can overwrite and append # "value" > file('to_overwrite'); "value" >> file('to_append'); # or have fstream() return an object which overloads just <<, for a ve +ry c+_+-eseque # fstream("path") << 120 << " in hexadecimal is " << ctrl::hex << 12 +0; END { print "="x10 }; { package fout; use autodie; use overload '>' => \&overwrite, '""' => sub { \${$_[0]} }, ; sub file($) { print __PACKAGE__, "::file($_[0])"; return bless \$_[0], __PACKAGE__; } sub overwrite { # 'value' > file($f) ==> overwrite(\$f, 'value', 1) my ($self, $value, $swap) = @_; if($swap) { open my $fh, '>', $$self; print {$fh} $value; } else { warn "not sure how to clobber scalar: `file($$self) > $val +ue`"; } return $self; } } *file = \&fout::file; #no warnings 'void'; #file('zzz') > "value"; #fout::overwrite(file('xxx'), 'manual', 1); # this wrote the file corr +ectly #'blah > file(yyy)' > file('yyy'); # will this? #print __PACKAGE__, "::"; { package fstream; use autodie; use overload '<<' => \&append, ; sub fstream($) { print __PACKAGE__, "::fstream($_[0])"; return bless \$_[0], __PACKAGE__; } sub fclobber($) { print __PACKAGE__, "::clobber($_[0])"; open my $fh, '>', $_[0]; return bless \$_[0], __PACKAGE__; } sub append { my ($self, $value, $swap) = @_; if(!$swap) { open my $fh, '>>', $$self; print {$fh} $value; } else { warn "not sure how to clobber scalar: `$value << file($$se +lf)`"; } return $self; } } *fstream = \&fstream::fstream; *fclobber = \&fstream::fclobber; 'value' << fstream('szsz'); fstream('sss') << "first"; fstream('sss') << "second" << "third"; fclobber('clb') << 'one' << 'and another';
  • Comment on Re^4: Split tab-separated file into separate files, based on column name (tangent = open on demand => stream-like)
  • Select or Download Code

Replies are listed 'Best First'.
Re^5: Split tab-separated file into separate files, based on column name (tangent = open on demand => stream-like)
by LanX (Saint) on Aug 26, 2020 at 18:06 UTC
    That's another good example why overloading is doomed to fail if the operator isn't semantically compatible.

    Regarding your question:

    Either you can try to manipulate the __WARN__ handler in %SIG

    Or you can try exporting warnings inside import() like demonstrated in Modern::Perl

    (And I agree about the productive code part. ;)

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

    Updates

    Rephrased and linked

      I'm not much of a fan of operator overloading anyway. But I thought it was a nice thought experiment, and again, maybe acceptable for oneliners.

      I still tried to cheat the system and go around the "useless use [...] in voix context" by using <<= instead of << because $magic << "Value"; returns $magic itself so $magic <<= "Value"; works fine.
      Except it failed when trying to turn this: $magic << "Value" << "Other value"; into $magic <<= "Value" <<= "Other value";, because << is a left associative operator and <<= is a right associative one. Meanig you've just turned ($magic << "Value") << "Other"; into $magic <<= ("Value" <<= "Other");. Whoops.

      So yes, the lesson is don't add new semantic to operators kid (yup, I'm looking at you C++).

        Operator overloading is great, I'm not against it per se.

        But it's a two-edged sword which should be handled with care.

        Overloading an operator because it looks like another syntax is not a good idea ( here >> )

        A good example for overloading are set operations, because the logic is "compatible".

        • X * Y intersection
        • X + Y join
        • X - Y difference
        • - X complement
        I could also attempt to use the logical && family but short circuiting could sabotage it.

        Bitwise ~ | & ^ etc. might be another option tho ... and the analogy between sets and bit vectors might help.

        update

        Found Set::Scalar which has a good set of overloaded operators.

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