Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

Re: What operator should perl5porters use for safe dereferencing? (&-> and ->?)

by tye (Sage)
on Jun 01, 2012 at 05:52 UTC ( #973680=note: print w/replies, xml ) Need Help??

in reply to What operator should perl5porters use for safe dereferencing?

I find ~> not visually distinct enough (otherwise, it might be my first choice). [Update: Alternately, in some fonts it doesn't even look like an arrow and so reads more like "approximately greater than". The combination of the two possible presentations makes it a particularly bad choice, IMHO.]

The name "safe de-ref" means more to me than what is being proposed here. What is being proposed is merely the more specific "undef-safe de-ref". As such, the closest representation of what it does is the &&-> choice (a syntax which I'm pretty sure I've seen in some other language, though I don't recall which).

However, it isn't actually &&-> so I'd vote for &-> because it is that much less ugly and is mnemonic for "slightly different from &&->". In case some don't quite follow... If we had an operator that was to "&&" as the new "//" is to "||", then that operator would be the ideal one to paste in front of "->" to get this new "undef-safe de-ref" operator. But we don't. Now, "&&->" naturally implies "de-ref if true" which is only slightly different from "de-ref if defined". So "&->" is about as close as we can get to "de-ref if defined" by virtue of being "slightly different from 'de-ref if true'". But we do have "&" so you could interpret "&->" as "bit-wise 'and' then de-ref" but that just makes no sense.

So my choice would be for "&->". But part of my reason for that choice (despite it being somewhat ugly) is because I would also like to have something worthy of being called "safe de-ref".

I'd like to also have "->?" added to Perl 5. Since "safe de-ref" is too vague, we should call "->?" the "de-ref if possible" operator.

So $obj->?blurg(@args); would be roughly equivalent to $obj->blurg(@args) if $obj->?can("blurg"); (note how I had to use "->?" in order to safely call can() on something that might be neither an object nor a class).

But my hopes for "->?" are even better realized if, in the process of extending Perl 5's de-ref operators, we also add the long-ago-proposed de-ref operators of "->@" and "->%". Because "is this a hash reference?" is a complete mess in Perl 5.

It started with ref which had the poor design of not thinking blessed hash refs are hash refs. Then we added ->isa("HASH") which was more accurate in several ways but rather sucked because you can't safely call ->isa(...) on some random scalar. Then chromatic's fetish for forcing everybody else to do things his way so he wouldn't have to make a minor improvement to his used-only-in-testing module got pushed as a moral stance against making isa actually convenient as well as useful so that problem just gets worse. So I've resorted to things like eval { $ref->{''} } but that gets unacceptably complicated because you might have a version of Perl that issues warnings (not suppressed by eval) when you do something that it thinks might be an attempt to use the deprecated "pseudo-hash" feature.

So $ref->?% or even defined $ref->?% would be a nice replacement for all of the prior "is a HASH?" techniques. It'd even work for blessed references to scalars that overload hash de-ref'ing.

And even if we don't get ->%, I'd still be happy to have $ref->?isa("HASH") which I don't believe would violate chromatic's edicts about how I should be allowed to use isa() (but would require overload to properly either fudge @ISA or override isa() when an object overloads a data de-ref operation if we want ->?isa to be completely accurate).

And, of course, you could do things like:

$opt = $ref->?{optName} // $ref->?[optNumb()] // ref->?();

for when you don't really care which succeeded or why and you just want the result (or undef).

Thanks much to Tanktalus for helping me with these ideas.

Update: I'd also be happy with just implementing ->? (but my guess is that many will want "de-ref if defined" w/o having to also silently ignore the extra "de-ref isn't possible" cases). But I'd be quite sad if ->? were used to implement just "de-ref if defined".

- tye        

Replies are listed 'Best First'.
Re^2: What operator should perl5porters use for safe dereferencing? (->)
by tye (Sage) on Jun 01, 2012 at 06:54 UTC

    I also strongly support the "make plain -> to be undef-safe" position. I've long found it frankly a design bug that using means that $undef->{key} will either 1) silently create a hash or 2) die (depending on often-subtle issues of context).

    My preference would be more like: Let me pick how de-ref'ing an undef behaves from 1) silent, 2) warn, or 3) die. Then, depending on my choice, $undef->{key} would pick (depending on context) between these paired choices of behaviors:

    1. a) silently auto-vivify or b) silently return undef
    2. a) auto-vivify with a warning or b) return undef with a warning
    3. a) die or b) die

    But, as a transition, it would be great if a future version of Perl 5 had default behaviors of:

    1. w/o 'use strict': a) silently auto-vivify or b) silently return undef
    2. w/ 'use strict': a) silently auto-vivify or b) return undef with a warning

    (for extra clarity, 2b would be the only change.)

    I almost always 'use strict;' and I almost always want $x = 'y'; $x->{z} to be fatal. But I very often don't want this to die:

    sub routine { my( $arg, $opt ) = @_; blarg( $arg ) if $opt->{blargTheArg}; ... }

    So I've gotten in the habit of writing ( $opt || {} )->{blarg} (after too many cases of code making it into Production before it ran into a case that resulted in $opt being undef).

    So, it will be less work to form a habit of $opt&->{blarg} (or $opt->?{blarg}), but I'd much rather be able to declare that undef-> triggers a warning (in either context) and to have that be the default behavior in the context where the current behavior really just doesn't make a lot of sense.

    On a side note, yes, I am aware of the autovivify module. I've long wanted that capability but I have no plans of using that module because the amount and complexity of XS code contained in it seems like a very inappropriate way to implement this feature (except as an experiment / proof of concept before it can be accepted into the 'core' -- which is what I consider this module) and has too high a risk of bizarre failures for the benefit provided, in my experience. I expect that one day the too-much and too-complex XS code of autovivify.xs will be completely replaced by some quite simple 'if' statements that examine 'hint bits' being sprinkled into a few places in Perl's own de-ref-implementing code and then I'll have a 'no autovivify;' that I can feel safe using.

    Even better will be if the way that I declare 'de-ref'ing undef in an lvalue context generates a warning' at least can also declare the same (or similar) behavior for rvalue contexts.

    - tye        

      I don't think I'd have a big issue with this applying to hash and array refs. but ignoring method calls on undef by default is a big No-no for me. I'd definitely vote for it being a completely separate pragma then.

      Ordinary morality is for ordinary people. -- Aleister Crowley

        Oh, yes. I agree with that.

        - tye        

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://973680]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (10)
As of 2019-06-20 11:47 GMT
Find Nodes?
    Voting Booth?
    Is there a future for codeless software?

    Results (89 votes). Check out past polls.