Ok, yet another meditation that would be better fit for p6l, but I like to see it discussed here and possibly reported there by someone who's actively following the list or dismissed altogether.

I was reviewing the stuff I have inadvertently accumulated in my temp dir and I found a tiny script, most probably originating from some discussion here, that featured the following lines of code:

my $fileno=fileno $fh; print defined $fileno ? $fileno : 'undef';

Thinking of how often one does this kind of things, he/she can't appreciate more the introduction of the C<//> operator, which will soon be in 5 official realms too: not only would it allow to write the second line as

print $fileno // 'undef';

but it would remove the need to create an ad hoc temporary variable for the sole purpose of not having to run the same code, i.e. fileno $fh twice. (In other examples one may need it anyway, and this particular one is somewhat artificial, but it exposes the point and many real world situations are precisely like this.) Thus the whole two lines may be rephrased like:

print fileno($fh) // 'undef';

Clearer, ain't it?

Now, the point is that the original snippet is just a particular case of more general situation in which one has a construct like

print func($thing) ? $thing : 'undef';

where func() is not necessarily a single function or sub but possibly a complex expression involving $thing: granted, by far the most common situation is with defined, but there are other ones and in this case, here's my humble proposal - a shortcutting ternary operator that will accept on the lhs an item, and on the right code and another item; will pass the lh term to the code and it will return either the lht or the rht depending on whether the code returns a true or false value respectively. I have no idea as for the symbol, but perhaps C<|||> would do, reasoning on the base that:

Thus one may have e.g.

say %foo<thing> ||| { /foo/ and .foo('bar') }, 'defoolt';

If all this is possible and does make sense, then probably a C<&&&> should be introduced for symmetry and consistency. I don't see a particular need for low precedency equivalents nor can imagine how could they be called, but I'm open to any suggestion and comment.

I suppose that if this doesn't meet wide popular consent, someone may suggest me that I could write the code to do so myself, in Perl 6: however while I know very well that operators are nothing more than subs in it and one can easily create new ones, I'm not really sure that one can create shortcutting ones as well. Perhaps in terms of macros, ain't it?

Replies are listed 'Best First'.
Re: [Perl 6] Generalized shortcutting C<||>?
by ikegami (Patriarch) on Jul 26, 2007 at 03:12 UTC
    map { some_condition ? $_ : some_default } some_expression;

    is much clearer to me than

    some_expression ||| { some_condition }, some_default

    The syntax and operand order is confusingly dissimilar to the exiting ternary operator.

    some_condition ? some_expression : some_default
      map { some_condition ? $_ : some_default } some_expression;

      Very good argument!

      The syntax and operand order is confusingly dissimilar to the exiting ternary operator.

      Pointless argument: why should it be similar to it? And how is that confusing? It's nonconfusingly similar to C<||> and C<//>. OTOH, while I cherish your map solution, which probably is actually the best one in 5's realms, if you look at it as a whole, it is confusingly dissimilar from those operators, with the value being inspected on the extreme right and the default buried in the block, not to talk of an "unnecessary" C<? $_ :. The right comparison if I get it right should be between:

      map { some_condition ?? $_ !! some_default }, some_expression; # and some_expression ||| { some_condition }, some_default;
        In Perl5, this is roughly what you want as a function, in terms of argument ordering and short-circuiting.
        sub cop { local $_ = shift; my ($cond, $default) = @_; $cond->() ? $_ : $default->(); } for my $test (2..4) { print "$test: ", cop($test, sub {$_ == 3}, sub { 'This is a default' + }), "\n"; }
        I suspect Perl6 would make it more appetizing.

        Caution: Contents may have been coded under pressure.
Re: [Perl 6] Generalized shortcutting C<||>?
by Roy Johnson (Monsignor) on Jul 25, 2007 at 20:16 UTC
    I think what you're suggesting is handled (verbosely, but generally) by given.

    Caution: Contents may have been coded under pressure.
      I think what you're suggesting is handled (verbosely, but generally) by given.

      Well, the whole point here is of having an agile syntax, and I don't see how given could be used easily to achieve that. Care to give an example anyway?

        I didn't state my point well. What you appear to be suggesting is a special case of what given does: topicalize something so you can both test and reuse it. I understand the usefulness of defined-or, and I understand the usefulness of given, but I don't see the need for something in-between.

        I say this notwithstanding that some time ago I mused on a similar (not identical) notion. It didn't generate much excitement, either.

        I haven't gotten much into Perl6, myself, so I can't even translate your example into a given construct, not that it would be excitingly terse if I did. Can you write a function that would do what you want?


        Caution: Contents may have been coded under pressure.
Re: [Perl 6] Generalized shortcutting C<||>?
by ysth (Canon) on Jul 26, 2007 at 06:27 UTC
    (grep( func($_), $thing ), 'default')[0]
      (grep( func($_), $thing ), 'default')[0]

      While I wholeheartedly cherish this as a creation of human mind, you know that kind of comments would it raise in production code, don't you? (It's very obvious, but as with most obvious things, I wouldn't have thought of it...)

        I was trying to be subtle. That's exactly the objection I was expecting, and it applies equally to the suggested operator, IMO.
Re: [Perl 6] Generalized shortcutting C<||>?
by Roy Johnson (Monsignor) on Sep 17, 2007 at 18:32 UTC
    Much belatedly, I came up with this function that I think you will find appealing.
    sub cond (&$$) { (my $check, local $_, my $default) = @_; $check->() ? $_ : $default; }
    Call it thus:
    print cond { fileno($_} } $fh, 'undef';
    It's the sort of trivial function that might be at home in List::MoreUtils.

    Caution: Contents may have been coded under pressure.
      Much belatedly, I came up with this function that I think you will find appealing.

      But of course! Except that as you can easily understand, I wanted something more "builtin" and more disguised as an operator, with the condition in the middle. I understand perfectly well that the general consensus does not seem to agree with my own desire so I will refrain from insisting. Most probably(*) in Perl 6 the corresponding function could be coded as a macro with the same syntax as the one I devised, so perhaps it will be interesting to test it "on the field" one day.

      (*) I'm not sure because Synopsis 6 specifies the syntax to define infix, prefix, postfix, circumfix and postcircumfix custom operators. But there does not seem to be any means to specify more generic ones, e.g. ternary ones. This may well be the subject of another thread.

Re: [Perl 6] Generalized shortcutting C<||>?
by Jenda (Abbot) on Jul 28, 2007 at 18:10 UTC

    Assuming the func() is something complex, possibly involving $thing several times, you'll have to name $thing somehow, no matter what the syntax. Most likely $_, right? So why don't you do just that?

    print foo($_) ? $_ : 'undef' for fileno $fh;
    You can't get it much shorter without getting it way too confusing. I understand you want to get rid of the ": $_" bit, but I don't think you can nor should do that.