in reply to Re: Re: Autoboxing: Yes or No?
in thread Autoboxing: Yes or No?

OK, so this may not be a "killer app", but one feature of autoboxing can be really a time-saver: methods on undef

I like chaining methods, and often I am only interested in the result of the whole chain. For example when navigating an XML document: $elt->first_child->text or $doc->root->last_child( 'section')->first_child( 'title')->att( 'num'). If one of the calls fails, than I am happy with undef being returned. I just don't like having to test every single method call. Which is often what I have to do, or the program dies when it tries calling a method on undef.

None of the possible alternatives seems to be as convenient as autoboxing undef, the closest in convenience, but I would guess at a higher performance price, being by returning a pre-defined object instead of undef in case of failure and overloading the boolean-ification of the object.

Replies are listed 'Best First'.
Re: Re: Re: Re: Autoboxing: Yes or No?
by chromatic (Archbishop) on Jan 01, 2004 at 20:52 UTC

    That sounds like a good use of the Null Object pattern.

      I thought about that, and even experimented with it, but if I use a Null Object I cannot write if( $elt->first_child) {...} anymore, I have to explicitely test for $elt->first_child->is_not_null everywhere, which I don't like, or I have to overload the boolean-ification of the objects, but I am not a fan of overloading, mostly for performance reasons.

      I agree that what I ask for is syntactic sugar, but I think it is also quite a natural way to write code, so it might make sense to have this in the language. I like the idea of undef being the null object. Being able to have a false blessed reference would actually be even better, because in this case I would know to which class that flase value belongs.

        mirod wrote: If I use a Null Object I cannot write if( $elt->first_child) {...} anymore.

        Ovid begs to differ :)

        package Null::Object; use overload 'bool' => \&bool; my $self; sub new { $self ||= bless {}, shift } sub AUTOLOAD { $self } sub bool { return; } package main; my $null = Null::Object->new; $null->foo->bar->baz; if ($null) { print "We shouldn't be here!"; } else { print "We are false!"; }

        That might need a bit of tuning, but you get the idea.

        Update: I just noticed that you mentioned overload, so my bit of code is not news to you :) On the other hand, if clean null objects is the only benefit of autoboxing, then I again can't see much of a benefit to them. I might also add that null objects should be the exception rather than the rule, thus the performance impact should be minimal (I hope).

        Cheers,
        Ovid

        New address of my CGI Course.

Re^4: Autoboxing: Yes or No?
by Aristotle (Chancellor) on Jan 01, 2004 at 23:43 UTC

    I think this is a problem best left unaddressed. In general OO the Law of Demeter forbids such deep hierarchy navigation constructs.

    Now, manipulating XML (or other document) structures is a very specific case, and not all the common OO rules necessarily apply. However, I'd argue that this means you should rather be using a language addressed at this specific problem domain. Which in this case does exist and should be obvious: XPath. Indeed, something like this behaves exactly the way you specified:

    # LibXML lingo; XPath expr is off the cuff, untested $doc->findvalue('/section[last()]/title[1]/@num');

    All that said, even methods on undef would not really solve the issue, just sweep it under the rug. Doing this well and cleanly in Perl would require something along the lines of

    $doc->root(sub { $_->last_child( 'section', sub { $_->first_child( 'title', sub { $_->att( 'num') }) }) });

    In summary, you will not be able to solve this satisfactorily and concisely in a language without continuations. Which isn't so bad, because this particular problem is likely better left unsolved.

    Makeshifts last the longest.

      Aristotle wrote: I think this is a problem best left unaddressed. In general OO the Law of Demeter forbids such deep hierarchy navigation constructs.

      I am wondering if I missed what you were trying to say. The Law of Demeter lets us know that this is bad:

      my $company = $sales_rep ->office ->division ->company;

      This enforces a class heirarchy which becomes inflexible since the user's code must now know the class heirarchy (bad!) and this makes changing the heirarchy more difficult. However, there's nothing wrong with this:

      $sales_rep ->set_title($title) ->set_office($office) ->set_something_else($foo);

      In this case, there is no enforcement of a particular class heirarchy and you therefore aren't bound by one. With mirod's example, I think we have the same thing:

      $doc ->root ->last_child('section') ->first_child('title') ->att('num')'

      While these are accessors and not mutators, we still appear to only be dealing with only one class and are less concerned with restructuring things. We have a published interface that only one class needs to maintain, whereas with my first example, we appear to have the various classes needing to know about the published interfaces of other classes and this greatly compounds the problem, thus increasing maintenance costs.

      If I am misunderstanding the situation (or your objection), please let me know.

      Cheers,
      Ovid

      New address of my CGI Course.

        Yes, this is indeed no violation of Demeter's Law. I was arguing that navigating node hierarchies is better left to a language tailored to the problem domain. So we have three conceivable cases where such method call chains appear: one is a design problem, one is better addressed on a different level, and the other (ie returning $self from a mutator - which is really a Perl-only idiom) is not really an issue WRT this discussion.

        Makeshifts last the longest.

      I agree with using XPath... if it's available. It is now available for XML::Twig but that's quite recent. Also in this case I used only accessors, but as pointed by ovid, I could have used setters or other methods.

      And yes, it mostly "sweeps the issue under the rug", the same way Perl itself sweeps under the rug the fact that $ sometimes matches just the end of the string, and sometimes matches a line return and the end of the string. It might not always be the correct thing to do, it is just natural and convenient when you don't have to be too strict.

      I really like ovid's comparison of the null object to the relational NULL BTW: sometimes you don't want the absence of some data to stop you, and you don't want to (and you should not have to) write a special case to handle it.

Re: Re: Re: Re: Autoboxing: Yes or No?
by BUU (Prior) on Jan 01, 2004 at 20:17 UTC
    Could you get around that by just doing eval{ $child->parent->grandparent->bar()} if($@){} And check $@ for 'method on undef' or whatever the exact string is?

      Sure, I could, it would just be ugly. Methods on undef let me write more natural and concise Perl.

Re:x4 Autoboxing
by bsb (Priest) on Jan 02, 2004 at 01:21 UTC
    Another alternative:
    eval { $some->big->chain->of->calls } die $@ if($@ && $@ =~ /\^Can't call method .* on an undefined/)
    Add sugar to your taste

    (Or Perl6's undef but ?something?;)

      BUU had already suggested that, though. mirod countered that he considered it ugly.

      Makeshifts last the longest.

        Yeah, I noticed that afterwards.
        If the error checking is wrapped up in a sub then it's less ugly, but maybe still too ugly for some.