Damian Conway wrote:
> One might argue that it would be more useful to return a result object whose
> boolean value is the success or failure, whose numeric and string values are
> the number of files *un*changed, and whose list value is the list of those
> *un*changed files.
>
> Then you could write:
>
>      unless chmod 0o664, @files  ->  $failed {
>         warn "Couldn't change the following $failed file(s): $failed[]";
>      }
>
> See below for a partial Perl 5 implementation.
>
> BTW, I think that *many* of Perl 6's list-taking builtins could conform to the
> same (or to a very similar) general interface.

The biggest problem that I have with this is that you devalue the
sigils: it becomes the accepted norm that $failed is nearly as likely
to contain a list-like object as a scalar-like object.

How important is it that perl 6 maintains the notion that $foo and
@foo are entirely different things?  If it isn't that important, the
above could be rewritten as

     unless chmod 0o664, @files  ->  $failed {
        warn "Couldn't change the following $failed file(s): @failed";
     }

...with the choice of sigil determining whether the object gets
treated as a scalar or as a list.

Also, there's the matter of "unneccessary paperwork": if the only
thing that I use the return value for is a boolean test, then all of
the effort involved in loading the filenames into a list was wasted
effort.  Is there a way that the "lazy evaluation" concept could be
extended to function return values?  Something like:

> Partial Perl 5 implementation:
>
>      sub chmod {
>          my ($mode, @files) = @_;
>
>          $mode = _normalize_mode($mode);
>
>          my @failed;
>          FILE:
>          for my $file (@files) {
>              next FILE if chmod $mode, $file;
>              push @failed, $file;
>          }
>
>          use Contextual::Return;

# at this point, have the sub temporarily suspend operation.

>          return
>             BOOL   { [EMAIL PROTECTED]  }
>             SCALAR { [EMAIL PROTECTED] }
>             LIST   { @failed   }
>      }
>
>      sub _normalize_mode {
>          return shift @_;     # Extra smarts needed here ;-)
>      }
>
>      unless (my $failed = &chmod(0664, qw(test1 test2 test5))) {
>          warn "Failed to chmod $failed file(s): @$failed";
>      }

...$failed is evaluated in boolean context; so the chmod sub resumes
operation, determines the boolean value, and suspends operation again,
because neither LIST nor SCALAR has been evaluated.

...when $failed is evaluated in scalar context, the chmod sub resumes
operation, determines the scalar value, and suspends operation again,
because LIST still hasn't been evaluated.

...when $failed is evaluated in list context, the chmod sub resumes
operation, determines the list value, and closes out, because all
three of BOOL, SCALAR, and LIST have now been evaluated.

Meanwhile,

  die unless chmod(0664, qw(test1 test2 test5));

...the anonymous return value is evaluated in boolean context; so
chmod resumes operation, determines the boolean value, and suspends
operation again.

...the anonymous return value goes out of scope, so the suspended
chmod sub gets discarded along with it.

Or have some compiler optimization which checks the contexts that the
return value gets used in, and only returns values for those contexts.

--
Jonathan "Dataweaver" Lang

Reply via email to