On 7/16/04 6:38 PM, David Wheeler wrote: > I'm always open to suggestions, esp. since I'm still trying to decide > how to solve this problem in my own applications.
Well, I think I've already given all of my advice, but I'll try to wrap it all up in one post. First, IME, the vast majority of my "get" methods don't allow any arguments. I often can't even think of a reason why they would. If I want to return something different, it's usually done by deriving another value from what is returned by the original accessor. For example, imagine a names() method that gets a list of names. If I only want the names that are "special" in some way, I'm not inclined to add a "special => 1" argument to the name() accessor. Instead, I'd add a new method named special_names(). Or if I want to be more arbitrary: names_filtered(filter => ...) or whatever. In the rare case that I use arguments in an accessor, I still use the same method name to get and set. I distinguish the cases with the simple rule mentioned earlier. If there is one argument, set. Otherwise, get (possibly with modifications as indicated by the arguments, if any). If I ever needed to "set" with multiple arguments in such a method, I'd just require them to be packed up into a single ref arg. And even that isn't always necessary if you know something about the range of valid values for the "set" case. Here's a real-world example. I have a method-maker variant that makes "date" get/set methods. If passed a single argument, it is validated parsed by my simple date parser (which I would love to replace by DateTime->parse(...) ;) and stored internally as a DateTime object. If passed no args, it returns the DateTime object. It also takes a handful of named args in the "get" case. Sometimes I want the date formatted in a "non-default" way. (Actually, this was before DateTime objects stringified at all, IIRC, but regardless...) In that case, I do something like this: $obj->start_date(format => '%B %d %Y at %T') The format arg just gets passed to DateTime's strftime() method, of course. Similarly, if I wanted a truncated clone to be returned, I call: $obj->start_date(truncate => 'day') You get the idea. Why not make separate methods as advised earlier? Well, mostly because every one of my DB-backed objects has at least two dates (create/mod) and usually more. I've already got one get/set method for every column in a DB record. If I had to make separate methods for every potential variant of every date method, the number of methods would explode. (Separate set/get methods would double the number as well.) It's also convenient to be able to pass format and truncate args to any date method without having to accurately predict beforehand which dates I'm likely to want to format or truncate, and without making separate truncate and format methods for all of them "just in case." Finally, why not simply use functions to modify the return values like this? format_date($obj->start_date, '%B %d %Y at %T') truncate_date($obj->start_date) I guess it comes down to a style choice. I prefer the more o-o style to the functional style. I Also don't like having to import symbols all over, and certainly don't want to fully-qualify everything. In reality, functions are doing the work behind the scenes anyway (my own parse_date() and format_date() library functions), but I only have to import them in one place: the method-maker class (and actually I fully-qualify them there because I'm a miser ;) As for this: $obj->start_date(format => '%B %d %Y at %T') being nothing more than syntactic sugar for this: $obj->start_date->strftime('%B %d %Y at %T') the first one gives me a bit more flexibility if, say, I decide to add new format specifiers. As it turns out, that's just what I did, and I didn't end up with a mix of "old style" $obj->start_date->strftime(...) calls and "new style" $obj->start_date(format => ...) calls when I did it. Similar arguments apply to the preference of: $obj->start_date(truncate => 'day') over this: $obj->start_date->clone->truncate(to => 'day') --- But honestly, 99.9% of my get/set methods don't take any args in the "get" case. I really, really like the cleanliness of using the same method name for both. The only thing that bothers me at all is the runtime overhead of arg checking, but as I mentioned before, even that will go away when efficient multimethod dispatch arrives in Perl 6. In the "date" get/set case in Perl 6, I'd have 3 methods with the same name but three different signatures: "no args", "named args", and "a single string arg") Sorry if I can't recall the Perl 6 signature syntax off the top of my head... ;) -John