//= operator alternative

R

Roy Johnson

I apologize for being so late to this party, but I do think I have an
idea worth considering.

//= will be forthcoming in perl6 to handle defaulting undefined values
(vs. merely false ones). In the threads discussing it, there was some
noise made about needing another operator for exists, and maybe a
special alternative to the (ever so rarely used) &&=, etc.

It occurred to me that maybe what ought to be done was to make tests
act as assigners (or yield lvalues, sort of) in certain situations --
in particular, in situations where ||= or &&= is specified, assign to
the argument being tested:

defined($var) ||= 'default';
exists($hash{$key}) &&= 'replacement';

To me, this reads pretty well. From a syntax standpoint, it's very
irregular, but that hasn't stopped Perl in the past.
 
R

Roy Johnson

Having thought about it some more, I got a much better, more
comprehensive idea.

Change the behavior of defined() thus: it provides a context in which
only undefined values are false. Boolean operators return undef rather
than empty string.

Then this would work exactly like you'd expect:
if (defined($a or $b)) { ...

and you could do

defined($v ||= a() || b());

exists() would be exactly like defined(), except that when checking a
hash value, only non-existent keys return false.

It's straightforward, and it addresses a lot of things that people
grouse about. For larger areas, there could be pragmas "use defined"
and "use exists". I don't know how useful/popular those would really
be.

In a hurry tonight, but wanted to get this out there. Please think
about it a little and comment.
 
R

Rafael Garcia-Suarez

Roy said:
Having thought about it some more, I got a much better, more
comprehensive idea.

Change the behavior of defined() thus: it provides a context in which
only undefined values are false. Boolean operators return undef rather
than empty string.

Then this would work exactly like you'd expect:
if (defined($a or $b)) { ...

well, the problem with contexts is that you're going to face
awkward propagation problems like this one :
if (defined(foo()) { ... }
sub foo { $a or $b }
I understand that Perl 6 will have more contexts that Perl 5, so
maybe will it have a defined-boolean context in addition to the regular
boolean one. (I don't think so, though.)
 
R

Rafael Garcia-Suarez

Roy said:
//= will be forthcoming in perl6 to handle defaulting undefined values
(vs. merely false ones). In the threads discussing it, there was some
noise made about needing another operator for exists, and maybe a
special alternative to the (ever so rarely used) &&=, etc.

// and //= will be present in perl 5.10.
It occurred to me that maybe what ought to be done was to make tests
act as assigners (or yield lvalues, sort of) in certain situations --
in particular, in situations where ||= or &&= is specified, assign to
the argument being tested:

defined($var) ||= 'default';
exists($hash{$key}) &&= 'replacement';

To me, this reads pretty well. From a syntax standpoint, it's very
irregular, but that hasn't stopped Perl in the past.

At first sight, I like this syntax. It think it could be implemented in
Perl 5 without too much pain. (Perl 5 language suggestions should be
directed at the perl 5 porters mailing list, by the way.)
 
R

Roy Johnson

well, the problem with contexts is that you're going to face
awkward propagation problems like this one :
if (defined(foo()) { ... }
sub foo { $a or $b }

It's lexical, so there's no propagation problem. You're in normal
perl-truth-context unless you're lexically enclosed in another. foo
evaluates $a and $b in its own context, and returns whatever it
normally returns. The defined() interprets that as true, unless it is
undef. That is exactly how that code would work today. If $a is
normal-perl-false, $b is returned, and is evaluated in defined()
context.

More of how I see it:

In this context, variables are checked for definedness first, and if
defined, then return whatever their value is to the expression. That
is to say, they are not autovivified until assigned to, or passed to
subroutines. Details on that may get sticky. I am not a Perl
technician.

defined() itself will return appropriate truth values for whatever
context it is in. That means you don't want to do:
$v = defined( a() || b() || c());
unless you want a boolean result for the whole expression, but
defined($v = a() || b() || c());
if you want $v to get the first defined value. Compare that with
defaulting for undefined $v:
defined($v ||= a() || b() || c());

// and //= will be present in perl 5.10.

So I have heard. Where do I look to find how they will work? The
reason I consider it the wrong solution is that, according to an old
document,
if ($a // $b)
doesn't mean "if either is defined". To get that, you have to do ($a
// $b // 0), which is distinctly kludgy. What we really want is a way
to provide a different truth context, hence:
if (defined($a || $b))
It reads beautifully to me.

The drawbacks I have thought of are pretty minor. It is possible,
since exists() and defined() both technically take expressions, that
some weirdly-written code would change behavior. The best example I
could think of:
# Find the first false value and tell me whether it is defined
defined( $a && $b && $c && $d )

If block notation were used, it would be new syntax, and that has some
appeal, considering the special nature of the beast. It doesn't behave
like a function, after all.
defined { $v = $a || $b || $c };

One advantage of // is that you can switch context easily:
# Defined or true or defined or true
$v = $a // $b || $c // $d;
The defined() context would buy you nothing here. I don't see that as
a major issue.

The original syntax I proposed:
defined($v) ||= $a;
could be syntatic sugar for
defined($v ||= $a);
but that raises the question of what to do when you have more on the
right than a simple value:
defined($v) ||= $a || $b;
Is that
defined($v ||= $a || $b);
or
defined($v) || ($v = $a || $b);
?

The latter strikes me as correct.

Thanks for your comments.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top