Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Your use of assertions in Perl ?

by ady (Deacon)
on Sep 05, 2008 at 16:04 UTC ( #709323=perlmeditation: print w/replies, xml ) Need Help??

As you know, an assertion is a statement evaluating to a boolean (ie. true/false) value; Assertion predicates are typically used to check the state of code blocks at entry (precondition), during execution (invariants) and at exit (postcondition), thus verifying runtime compliance with a specified design contract (pre/post) and with assumptions of program state (invariants) for the implementation of an algorithm.

Typically an assertion failure will throw an exception with an error message and a context/stack trace, thus facilitating debugging and error fixing. In Perl we have several mechanisms for implementing assertions, ranging from the simple and general <predicate> or die "Can't ...: $!"; over the eval { <predicate>; }; die $@ if $@; to the use of specialized Smart comments (require, assert, ensure, insist etc.), Test predicates (ok, is, isnt, like, unlike, cmp_ok, can_ok etc.), -- and a range of other CPAN Assert modules.

Programming with assertions for debug scaffolding and unit testing has long been considered a Good Thing for ensuring compliance of program runtime behaviour viz application design and specs; (-- for an interesting historical record, see: Tony Hoare Assertions: a personal perspective).

This is basically how i have been using assertions in my own programming in the past, -- though not as rigoristic as promoted by the Design by contract methodology.Now I'm interested in hearing to what extent and with what means you fellow monks are using assertions in your Perl programming?

My renewed interest in the use of assertions was sparked by a recent article in DDJ CodeTalk, where Walter Bright raised the question of using 'resilient' assertions in high reliability production code, -- rightly questioned, I think, by the commenters of the article, -- but food for thought.Any comments on this approach, based on your own experiences?

Best regards
Allan Dystrup

In the above Assertions... reference Tony Hoare writes :

The primary role of an assertion today is as a test oracle, defining the circumstances under which a program under test is considered to fail. ... many teams leave the assertions in ship code to generate an exception when false; to continue execution in such an unexpected and untested circumstance would run a grave risk of crash. So instead, the handler for the exception makes a recovery that is sensible to the customer in the environment of use.

That nicely wraps up (I think) the discussion of what i've called 'resilient' assertions in production code (cf. DDJ CodeTalk); What's perhaps more interesting in Hoare's paper is his aim of using assertions to express program intention/semantics thus allowing automatic verification/proof. As he writes :

...the axiomatic method has been explicitly used to guide the design of languages like Euclid and Eiffel 20, 21. These languages were prepared to accept the restrictions on the generality of expression that are necessary to make the axioms consistent with efficient program execution.
...there are now strong signs that the actual quality of the language is beginning to matter. ...One day, I expect the new programming language designer will learn how to use assertional methods as a design tool, to evaluate and refine the objectively evaluated quality of familiar language features, as well as averting the risks involved in the introduction of new features.

I was wondering which (if any) effect this kind of conderation has (had) on the development of Perl6, -- taking into account the special nature of dynamic languages and the explicit design goal of flexibility/TimToadyNess of Perl ?

Replies are listed 'Best First'.
Re: Your use of assertions in Perl ?
by moritz (Cardinal) on Sep 05, 2008 at 16:18 UTC
    Before I started with perl I had a small intermezzo with Eiffel. In that fine programming language "design by contract" is one of the design philosophies. The "contracts" are assertions as described by ady, with the nice addition that assertions on methods are actually inherited.

    So I miss assertions in perl a bit, but I am too lazy (and too concerned with not introducing dependencies) to use some dedicated modules for it.

    My current usage of assertions is mostly limited to

    use Carp qw(confess); ... confess "assertion description" unless $condition

    It's a bit sad that Devel::Cover "punishes" the usage of assertions by default if you find no way to trigger it (and unless you tell Devel::Cover to ignore that line, which could also do).

    So to me it seems that all the tools are in place, but either aren't easy accessible, or (more likely) I'm too lazy to use them properly.

Re: Your use of assertions in Perl ?
by dragonchild (Archbishop) on Sep 06, 2008 at 02:40 UTC
    This is how Catalyst's chained dispatch works (q.v. Catalyst::DispatchType::Chained). I always thought it was just sane.

    As for assertions, I read a blog post recently where the author asserted that sane code generally had less else-clauses than otherwise. I've been looking at my code in that light and the code I find to be better has that property. I have a lot of unless-blocks of the form:

    sub foo { my $self = shift; my %args = @_; # Lots of these unless ( ... ) { return; } # Do the real thing }
    Same thing, right?

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Your use of assertions in Perl ?
by Tanktalus (Canon) on Sep 08, 2008 at 14:51 UTC

    I only use assertion-like code in places where they're really really really needed. What an assertion says is that the developer of the function / method / package / object is smarter than any user of the function / method / package / object could ever be, and Knows What's Best (TM). Sometimes, that's true. Sometimes, however, it's not.

    One developer on my team, many years ago, put assertions in his code all over the place to make sure we only did things His Way. When I started to try to use his code, I quickly ran into artificial limitations that if he had just left well alone, would work just fine. Things like passing in a lexical file handle that was pointing to a scalar wouldn't work (he checked that the handle was a GLOB!). After removing more than 70% of his assertions, the code continued to work fine, and started doing things he didn't even imagine as possible. But that's just because perl DWIMs very well.

    So you may be thinking, "But, I know that, so I won't have a problem!" But the point is that you may know more about perl than this guy, but, like him, you may not know what it is that you don't know. He didn't know about lexical filehandles (he had been taught perl by a team that basically still used perl 4 syntax on perl 5.005). What is it that YOU don't know?

    Even core modules aren't immune to this. In There be dragons (or, perl5.8's open stringref breaks...), I pointed out a problem with File::Copy. It isn't an assertion, but it IS code that makes an assumption about its input that just isn't necessarily valid. And when I copied (no pun intended) F::C's code and merely omitted the useless stat call, it worked fine.

    Basically, in my experience, assertions are merely the writing down of assumptions, and not always the assumption that the author thinks they're assuming. And this goes ten times more for DWIMmery like Perl than for Java or C++ where polymorphism is more explicit.

      I can't agree more.

      There have been so many times where I have been stuck sitting there knowing that what I want to do will work, but not being allowed to do it.

      For a concrete example: a monitoring program which sends alerts when your server's disk starts to get full at $work. I want just a "warning" at 100% full, not a "critical", since the disk in question is very low priority and I don't want the system to cry "Wolf!" The obvious solution is to set the critical level to 101% full, and therefore it will never trigger, leaving 100% for the warning.
      Naturally somebody went and made the GUI only allow 0-100% to be entered, and also require something in the critical field. Yet, if you snoop around in the database and poke 101 into the correct cell, it all works perfectly as intended. Unfortunately you can't do workarounds like that and still expect corporate support for it.

      ...Anyways... I would just like to say to all the assertive coders:
      Please do not assert that the input is within an expected range.
      Instead, assert to protect against things which will make your function fail.

      Note that this is the opposite of taint checking; instead of only allowing known-good data from untrusted users, your users are now the authors useing your module. They are fully trusted (and can edit your code if they really want to), so you want to maintain the maximum flexibility while providing some convenient notification when they're about to burn themselves.

      The distinction here is the difference between a guard rail on the highway and the padded rubber room your power users will require after trying to use your code. :)

      PS: this, of course, only applies to modules that do not interact with untrusted users. If taint checking is a good idea for your module, then highly restrictive assertions are probably a good idea too.

Re: Your use of assertions in Perl ?
by aufflick (Deacon) on Sep 06, 2008 at 03:59 UTC
    Interesting timing - I have just started exploring Eiffel :)

    In Perl, my most common idiom is:

    die "error string" unless condition;

    I haven't really given it much thought, but now I see there are a number of very interesting assert modules on CPAN which require my investigation.

Re: Your use of assertions in Perl ?
by wol (Hermit) on Sep 09, 2008 at 15:04 UTC
    This isn't a perl specific point, but coders need to be able to distinguish between situations where they should die/assert/explode/etc, and situations where they need to be able to handle the bogus input.

    Imagine you're writing a web browser. It connects to some server accross the web, downloads some content and tries to parse it as HTML, images, flash, sound... There's quite a lot of code, so it's useful to add assertions in many functions.

    However, you can't add an assertion like this without it failing (pointlessly) on many many sites:

    if (m{<body>}) { die "Mismatched tags!" unless m{</body>}; }

    In general, only assert over items that you (or someone in your team) is in control of. Never assert about items that you can't control, such as content from the www or a user - you'll just have to find some way of coping with errors in that.

    Oh, and remember that you'll need to be able to tell the difference, and that there shouldn't be a gap between the things that are asserted and the things that are handled...

      Never assert about items that you can't control, such as content from the www or a user - you'll just have to find some way of coping with errors in that.

      I'd modify that to, "Never assert about items that neither you or your intended users can control." An assertion is a perfectly valid way to inform a user, "stop mangling your input data", though you are right of course in that it is nothing more than a source of frustration if the point of the code is for users to run it on someone else's arbitrary and potentially mangled input data.

      As a corollary, however, I'd add that it's nice if your error message tells the user as much as possible about what was wrong and how to fix it.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://709323]
Approved by psini
Front-paged by psini
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (3)
As of 2022-08-13 11:54 GMT
Find Nodes?
    Voting Booth?

    No recent polls found