Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re: Being more Assert-ive with Perl

by water (Deacon)
on Sep 18, 2004 at 08:08 UTC ( [id://391964]=note: print w/replies, xml ) Need Help??


in reply to Being more Assert-ive with Perl

This post is more for newcomers, than a response to stvn.

Yes, use assertions. Use boatloads of them.

 "assertions++" x 1000. Assertions rock. You will be surprised at how many bugs they detect.

And if you can (risk, speed, etc), leave them in and turned on in production code (with an appropriate handler, of course). (After all, these are assertions, and thus should NEVER happen, right?)

but...

Unless you're writing time-critical software in perl -- a game, a controller, etc (and one could ask, "errr, why in perl, then?" if that is indeed the case) -- then

  1. The program run time will very likely be dominated by IO, usually disk, db, network, web fetches, etc, and thus the speed difference between  assert (defined $foo, 'defined foo') and  defined $foo || die 'defined foo'; should be irrelevent in real code
  2. Machine time is cheap and Programmer time is expensive -- what is clearest? Which is easiest for others to read?
  3. Making assert a sub makes it Very Easy to change the assert behavior of the whole code base (logging, reponding to errors, correct shutdown in case of Really Bad Errors, etc), whereas the in-line || doesn't give you those options.
Last point aside, IMHO, it really doesn't matter if a shop opts for  assert vs.  ||, as long as the gang uses the idiom consistently. I personally like  assert, because to me is is more clear, and more flexible, but I also prefer Pepsi to Coke -- many of these things are just individual preference.

And as for ensuring an entire code base meets explicit coding standards -- well, this is great use of perl testing. just File::Find::Rule or whatever and  Test::More the whole source tree and apply regexps to every module and program, such that code that doesn't meet standard fails the test and 'breaks the build'.

From what I've read here, stvn is a far more advanced coder than I. This is not a criticism of his post or his method, just a caution to the less-experienced: Premature optimization is the root of all evil .

Don't worry about speed difference until you know your program is running too slowly, then rationally determine what is creating the bottleneck. And I'd bet you lunch that, unless you have contrived code, the bottleneck won't be your assertions. No way.

"assertions++" x 1000; "coding_standards++" x 1000; "'worrying about speed of assert vs. ||' -- ";

Replies are listed 'Best First'.
Re^2: Being more Assert-ive with Perl
by stvn (Monsignor) on Sep 18, 2004 at 15:18 UTC
    water,

    Excellent points, all of them, however I do disagree with a few of them.

    And if you can (risk, speed, etc), leave them in and turned on in production code (with an appropriate handler, of course). (After all, these are assertions, and thus should NEVER happen, right?)

    This I do not disagree with, but instead strongly agree with. After all, if one of your pre-conditons is that you get passed a connected database handle, or a writeable filehandle, would you not want to check that at runtime as well? Assertions and Contracts are not just for debugging, they are ways in which you can make your code more reliable and robust.

    The program run time will very likely be dominated by IO, usually disk, db, network, web fetches, etc, and thus the speed difference between  assert (defined $foo, 'defined foo') and  defined $foo || die 'defined foo'; should be irrelevent in real code

    This is true, assertions will almost never be your bottleneck, but personally I have assertions just about everywhere, which includes methods and functions which need to get called inside tight loops, as well as at time critical portions of code.

    For instance I have a part of a reporting app which spends a lot of time doing a DB query, once I get the results back (up to 30,000+ rows) I need to loop through them all and calculate various values. My query has already taken a long time, so anything more I do, I want it to be fast so that the user doesn't think somethings wrong. I use these fast assertions inside the calcualtion routines and loops to make sure my values are always valid before I start. Doing this has the added benefit of keeping my calculation code simple and fast since it never gets an edge case so it doesnt need to handle them.

    I guess my point is that, yes, IO/Network/DB stuff can take a while and certainly be the likelest bottleneck, but sometimes this means your post-processing code needs to be that much faster.

    Machine time is cheap and Programmer time is expensive -- what is clearest? Which is easiest for others to read?

    Agreed, but IMHO, my way is clearer :)

    You say TOmato, I say TomAto. It's all a matter of style.

    Making assert a sub makes it Very Easy to change the assert behavior of the whole code base (logging, reponding to errors, correct shutdown in case of Really Bad Errors, etc), whereas the in-line || doesn't give you those options

    Not so, a modification of the example above will show that it can be done:

    sub insertQuarter {     my ($coin) = @_;     (defined($coin) && $coin == 25) || errorHandler(You must insert 25 cents");     initializeGame();     startGame(); }
    Where the code for errorHandler can be changed to do just about anything (log, die, warn, etc etc etc). IMO this is just as flexible as an assert subroutine. It is also faster too. Here is some code which benchmarks not only a raw OR against an assert sub, but also benchmakrs using the OR with the errorHandler as well as an example of no-op versions of both errorHandler and assert.

    As you can see from the results, using a basic assert subroutine is about 34% slower than the raw OR. When you add the flexibility of an errorHandler subroutine on the other end of OR, you lose only 1% (which is surely insignifagant), and gain the same flexibility an assert subroutine would have. Even when you turn off assertions and make both the assert and errorHandler routines into no-ops, the assert version is still a 21% slower (which really is useless overhead since much of that is likely just the call to assert).

    Again, I like my assertions to be on at runtime, and I put them everywhere, so for me, these performance gains are a nice thing to have. But even if you don't need to worry about performance, I see little gain in flexibility over using an assert sub.

    This is not a criticism of his post or his method, just a caution to the less-experienced: Premature optimization is the root of all evil .

    Yes, quite true, but would you not want to make sure your always using the sharpest knife in the drawer?

    I do not mean this as a means of premature optimization, but as a style, which IMO, is clear and readable, but also has the added benefit of being faster than many of the other options out there.

    But then again, I hate Pepsi, and I hate Coke,... gimme some Mountain Dew anyday ;-)

    -stvn

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-04-19 05:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found