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.) | [reply] [d/l] |
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. | [reply] [d/l] [select] |
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
| [reply] [d/l] |
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!
| [reply] [d/l] |
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. | [reply] [d/l] [select] |
| [reply] [d/l] |
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
| [reply] |
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.
| [reply] |