http://www.perlmonks.org?node_id=570242

spq has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on a project and am trying to settle on some API details. Currently, it is how users will check a value, such as a response code, set by the invocation of a method on an object, where the value is from a small set of possibilities. Actually checking the response code wouldn't need to be done very often unless testing or debugging. But even calls that die will set a response code, so if the die was captured by eval you could interrogate for more information. Etc. So for example, if the object was $client and you had just invoked method foo on it: $client->foo({some => 'args'}); And you wanted to see the specific response code, what might be the most 'natural' syntax? Here are the possibilities I'm considering:

  1. $client->response_code == OK;
  2. $client->response_is(OK);
  3. $client->response_code == $client->OK;
  4. $client->response_is($client->OK);
  5. $client->response_is('OK');

Initially I had a sub-package that exported all the relevant constants, such as OK. However, I have some other message handling methods that would be useful to most of the packages in the set and would just as well make a simple base class. Options 1 & 2 above both require exporting the constants, which doesn't seem to be compatible with use base qw();. Options 3 & 4 work when the class for $client inherits from the messaging base class (which sets the constants internally), but the use of $client twice looks a bit odd to me. Option 5 would remove the need for constants, but it also looks a bit odd to me to be sending a word as a string to check the status - but that could be just be because I'm used to using the constants.

Fellow Monks, what would you prefer to use? Do you have an idea that might be better? And yes, please feel free to include a link to your personal favorite message passing or exception handling module whose interface you like or that you think I should consider using directly to solve my problem. ;)

Replies are listed 'Best First'.
Re: OOP style question: Checking a value
by Tanktalus (Canon) on Aug 29, 2006 at 21:03 UTC

    Actually, it seems a bit behind the curve already. As in, by the time I'm looking at the response code, I should already know whether we are looking at an error or not. So, checking against OK seems a bit late.

    if (not $client->foo({some=> 'args'})) { my $rc = $client->get_current_error(); # handle the error ... no need to check "OK". }
    Now, as to what the current error might be, I don't know. Most of the time, I keep my functions and methods trivial enough that true/false is sufficient. I know that doesn't work in all cases (DBI springs to mind). That said, I'm not really fond of numbers - they're way too opaque. Figuring out what return code 3618 is is not what I want to do every time I call foo. So I kinda like it when the error is a string that I can just display. For example, if you had a set_current_error method that took a string, set the internal marker to that string, and also took a stack trace and stored that, and then I could query for the error message, or I could query for the stack trace of the error (or one after the other). Both can come in handy. (Carp's longmess may come in handy for creating the stack trace).

    Also, by using strings, you don't need constants anymore. A simple true/false for the method's success, and a string for the error. Seems straightforward to me.

    (Yes, I can see how more information about a failure could be handy, and thus the reason for error objects, but that can be overkill in some projects. I don't know if this is such a project.)

      Arggg - shouldn't have used OK in my OP I guess. Please see my response to the previous reply as well. I certainly agree that 'Figuring out what return code 3618 is' is a pain. Which is why I originally exported constants, such as ERROR, OK, NOT_FOUND, BAD_REQUEST, FORBIDDEN etc. Each method is (well, mostly will-be ;) documented with the possible codes it might set, should you be interested in finding out more details. This allowed things like:

      # load test client $client = new MyModule({CLIENT_ID => 0}) ok($client && $client->response_code == CREATED, 'Loaded test client'); # foo test case 1 my $goodies = $client->foo({some => 'args'}); ok(defined $goodies && $client->response_code == OK, 'Got some kind of goodies from foo');

      That's an example of the current API in a couple tests, checking response codes. Now, normally you would never need to do this in production code; if $client was actually a true value, then the client should have loaded fine and your object should be good to go. Hopefully the $goodies you get back, if any, are the goodies you want. If not, then you might want to go get the error message(s) (such as you would for DBI) or perhaps even determine the specific response code.

      But now I'm participating in wandering off the subject. - lol - Let me try rewording my question. Lets assume that a side-effect of calling methods on an object of class Bar is that it changes the value of one of the objects attributes. The possible values are meaningful for some purpose and not arbitrary, only being selected from a limited, well defined set of possible values. While these values could be anything (numbers, documents, other objects), checking which value it is set to can be accomplished by comparing it to a defined set of English words - mnemonics. In the original version these words were exported from a central repository (that hides any magic away) and could be checked against the current state with == SOME_WORD. However, I want to combine a few things that are related and go together well with these word definitions and make them a class of their own, which my other classes may inherit from. This makes it 'impossible' to export the words as before, and as such alternate syntax's need to be considered.

Re: OOP style question: Checking a value
by jdtoronto (Prior) on Aug 29, 2006 at 20:34 UTC
    spg

    If anything, no 5. 1 & 2 make the OK look far too much like a bareword which is uncomfortable when using strictures. 3 & 4 needlessly repeat the object name, so 5 is the most compact. But why not test for truth and only look at the response when the return value fails?

    if ( $client->response ) { #then do whatever } else { #probe for the bad news here }
    Or as you suggest, you could use an eval, but why?

    jdtoronto

      Sure. But a response code is always set, so in you example above you would be checking $client->foo's result in the if (){}. Otherwise though, I leave how to structure the code checking foo's result and looking at the response code to the users preferences. ;) And I still need to define how they probe for the bad news. ... Oh, perhaps I wasn't clear. There are far more than just pass/fail (OK/ERROR) as possible response codes.

      The primary target for the code in this project is a related mod_perl project. While I've reused the same massaging and response codes for my own error checking and testing (and far more code uses them for those purposes), the response code values are actually the same as used by Apache, and as such can be meaningfully returned to a client (browser) with the correct meaning in the appropriate circumstances.

      So that's one vote for #5. Thanks!

Re: OOP style question: Checking a value
by perrin (Chancellor) on Aug 29, 2006 at 21:20 UTC
    In this case, I'd probably use Exception::Class objects for each possible type of failure, or else one that contains the error code. For example:
    eval { $client->blinky_blinky; }; if (my $err = $@) { if ($err->isa('NotFoundError') { # do something } else { $err->rethrow; } }
    In general, when I want to check for a specific state, I make a method for it rather than expose internal values:
    $client->response->is_ok; $client->response->is_not_found;
    The HTTP::Response class is a good example for this kind of stuff as well.
Re: OOP style question: Checking a value
by diotalevi (Canon) on Aug 29, 2006 at 21:11 UTC

    What of $obj->response_is_ok;?

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: OOP style question: Checking a value
by CountZero (Bishop) on Aug 29, 2006 at 21:23 UTC
    My answer: "6. None of the above".

    As Tanktalus already explained, it feels strange to check for the response code AFTER you have called a method on an object.

    In my book of programming with objects I always like the object on which a method is called to directly return some meaningful code to the caller.

    It is up to the caller to either call the object in a void context (essentially throwing the return value away) or saving the return value and acting upon it later.

    If you need more than a simple "true" or "false" value returned, why not go all the way and have your objects return full blown response-objects? You could make this response object stringify to one of your constants or call other methods on it (logging, stack-traces; full exception handling; ... etc).

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      Because many, if not most, of the methods already return something useful. And as I said in an earlier response, I need to have some of these codes (yes there are more than just true/false) available for a certain specific subset of methods, and so started reusing them for other purposes, since they made sense for some other things, including where a failure state could have different causes that I may want to handle differently. Sure there are other ways of doing it, and suggestions are welcome.

      But even if I ceased reusing these codes there are still a small subset of methods that would required some variation of the style question originally posed.