Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

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

by tye (Cardinal)
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        


Comment on Re: What operator should perl5porters use for safe dereferencing? (&-> and ->?)
Select or Download Code
Re^2: What operator should perl5porters use for safe dereferencing? (->)
by tye (Cardinal) 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 strict.pm 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?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (19)
As of 2015-07-01 15:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (6 votes), past polls