I Want My Objective-C

The other day, as they idea of the defined-dereference operator (~> is the favorite at the moment), I proposed the idea of implementing a pragma that changed what Perl does when it's faced with a dereference of, or a message sent to, undef. Right now, of course, it dies.

This bit me hard this evening as we put up some new code; I have a Mason template that calls a series of methods to get a particular piece of status information to be shown to the user. I had bullet proofed it, or so I thought.
my $foothing = $current_object->foo;
if (defined $foothing) {
    my @barthings = $foothing->bars();
    if (defined $barthing[-1]) {
        my $answer = $barthing->baz->status;
    }
}
Yep, $barthing->baz came back undef, and an error page instead of my actual page.

Now, in the Objective-C world, nil, the Objective-C equivalent of undef has a special property: it accepts any message, and returns nil. So a lot of the boilerplate code (Get an object. Did I get it? Call a method. Did I get another object? Call a method. Did I...and so on) goes away - you don't need it at all. In the case of my code, if I had Objective-C-like undef-as-nil:

no failing 'deref';
$answer = ($current_object->foo->bars)[-1]->baz->status // "not there";
Much less code, and I don't have to remember to check each step, unless I specifically want to do something if a given step is undef. If I do, I can use defined-or to set the value I want instead.

So now I have an excuse to work on this pragma - I actually do need it for work!

5 Comments

At first sight, this makes me a bit uneasy, but I'd be interested to see how it pans out in practice (IOW it's not fundamentally a bad idea). The best I can do to describe my concerns is point at smart match. Generally speaking, Larry has chosen to put ambiguity into Perl values instead of operators. Operators are commonly specific to how they need to look at a given scalar value (eq vs. ==, etc). Smart match is flawed precisely because it tries to DWIM both on the value and the operator side of things.

The ~> (or whatever syntax) proposal continues down the road of making the programmer state explicitly what behaviour he wants using the operator syntax instead of the nature of the value. Admittedly, it's not the same thing as float vs. int vs. char* content in the scalar since your proposed change in behaviour only affects a single, very specific type of value. Maybe my concerns are unfounded. It's more of a gut feeling.

Either way: Stealing from other languages: Good. Stealing clever ideas (but not too clever): Very good. I'd be really interested in such a (lexical) pragma -- even though I would not use it for a long time to come.

Thanks for this post!

I don't think a lexical pragma would be any help for the fairly common situation of:

my $aunts_name = $me->father->sister~>name;

That is, I only want the safe dereference to apply in the case of my father not having a sister. I want the case where $me->father returns undef to be treated as a real error.

Except perhaps in very small scopes, I can't imagine using a safe deref lexical pragma very often. A safe deref operator which can be used on just specific dereferences seems a much better idea.

You can try https://metacpan.org/module/Patterns::UndefObject

or https://metacpan.org/module/Scalar::Andand

or use something like that :

my $aunts_name;
{ $aunts_name = ($me->father->sister // next)->name }

Max.

or https://metacpan.org/module/Scalar::Andand

If you really like it, I'd happily part from it. It's a proof of concept that to my surprise some people may actually be using in their code.

If you want to implement that no failing 'deref' pragma, it probably wouldn't be too hard to adapt something like this (or Leon's Scalar::Andand which appears to use the same autobox approach):

perl -e'use strict; use warnings; package UndefHandler; our $AUTOLOAD; sub AUTOLOAD { (my $method = $AUTOLOAD) =~ s/^.*:://; warn "->$method called on undef value"; () } use autobox UNDEF => q{UndefHandler}; my $x; $x->something->like->this;'

Not something I'd usually leave on in production but have occasionally found it useful when there are a lot of cases and I want to go through and fix them all rather than a find/fix/repeat iteration process.

Leave a comment

About Joe McMahon

user-pic Still blogging about Perl; co-posting at pemungkah.com.