Your get function has expanded to 70 lines in production? I have to ask why. While I don't agree with turning good rules of thumb like, "Functions should not exceed 50 lines" into rigid rules, I don't remember the last time I felt the need to write a function that was 70 lines long.

As for your abstract class issue, you can always make the error sub an anonymous code reference which just *happens* to default to \&Carp::confess but can be set to whatever makes sense in the application. (For a GUI you probably want to write a log, pop up a pop-up window, and then throw an exception internally? I don't have a sense for what makes sense since I have not worked with GUI code for a long time.) If you do that I would make sure that it is everywhere exported from the same place so it can be switched globally as appropriate.

For your code example, when I write code following a general pattern like that, normally I don't want to make that a silent error. It is too each to have a typo in the list of attributes, I have made mistakes like that a million times. But still if I wanted to make that kind of logic clear, I would suggest creating a method called, "has_attrib" and then calling that in your loop. In fact you can now write it as:

foreach my $object (@object_list) { foreach my $attribute_name (grep $object->has_attrib($_), @attribute +_list) { my $value = $object->get($attribute_name); # Do stuff here } }
As for your challenge, don't get impressed too easily. Here is a realistic application off of the top of my head. The application is converting data from one database layout to a very different one. Your objects are instantiated out of queries in the one database and then present views of themselves for the insert into the other. Attributes are fields of tables. The contents must be able to contain any data that would be appropriate for the insert, and that means that you must preserve the difference between NULL (internally represented in Perl as undef) and strings (internally represented in Perl as themselves). Note that while you could use some internal representation of the null value other than the default supported by DBI, doing so would be coding overhead and a possible source of mistakes which you don't want.

Finally the EAGAIN is not meant as a counter-example. It is just the specific example that really got me thinking about the basic issues with error-handling logic. In general error-handling logic is the least tested logic in our code. Yet it is the logic which we most depend on working when things goes wrong. Therefore error-handling policies that make error information available and scatter the handling of errors to user code is practically a guarantee that when things go wrong we will not have handled it well.

But here is the EAGAIN issue explained. A very large number of Unix system calls have a possible error that they can return called, "EGAIN". This error means that something was temporarily unavailable, but if you try the call again in a bit, it will probably succeed. A typical example is that fork can fail this way if the OS has run out of process IDs. It is also used to resolve various race conditions. Etc.

Under normal conditions this error is rare to very rare. User code is supposed to test for it and have appropriate failure/retry logic, but people frequently don't write this logic, or they write it but it is buggy, and it never gets exercised. However the odds of the kinds of races that return this error rise dramatically when the system is under heavy load. Therefore if there is a sudden spike in usage that lasts for a while, processes that have been running for ages may start acting up in a variety of bad ways for no apparent reason.

Anyways I didn't mean to compare EAGAIN to the mechanics of your application. I just wanted to point to it as an example of why I think that error logic that has been moved to user code - no matter how clearly documented - is going to become error-prone.

(PS: The system headers you talked about? Some people definitely complain about that. In fact changing how Perl handles errors that come from system calls are on the top of the list of things that Larry Wall wants to change in Perl 6...)


In reply to Re (tilly) 6: To sub or not to sub, that is the question? by tilly
in thread To sub or not to sub, that is the question? by tachyon

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.