Hi Robert and Josh,
On 22/12/11 00:49, Robert K. wrote:
having to go find the class. I find that need occasionally. Or sometimes
convenient on first sight but on second sight it may just be
obfuscation.
Kind regards
robert
I’ve run into this kind of thing before, and it does impact me
regularly. Having said that, I know my C++ background (which allows
this) biases me somewhat on the issue.
I tend to steer away from “Foo.bar” style calls inside class Foo for the
following reason- it complicates refactoring. If you determine that a
class would benefit from being split (perhaps because another class has
common functionality and you want it to share a common base), then you
have to selectively rename all of the calls you have made to point to
the correct class. Sure, it’s not hard, and doesn’t take too long, but
when you’re refactoring something for the sake of something else you
have developed, not having to deal with additional chores to make it
work makes it less likely that you’ll stuff something up in the process.
A similar problem arises with renaming the class, but admittedly the
solution tends to be far easier.
For that reason, I’d instead use “class.bar” calls, if it were possible,
which it is not, which brings us to “self.class.bar”. I do this as you
can’t always tell ahead of time when you’ll need to refactor something
to pull out a base class, and so I’ll assume that (almost) all of the
classes I work on could be subject to such changes later in its
lifetime. If you could tell beforehand, you would have designed it that
way in the first place. Now, if you have a class method that is used
both inside and out, but mostly inside (and regularly), it’s a pain to
have to write “self.class.bar” each time you want to call “bar”.
Incidentally, for “bar”, I have a specific method in mind for something
I have been working on (ie. a real-world problem), that makes the most
sense as a class method, since it works entirely off the arguments and
carries no state. The call in question has very specific structured
input requirements, and is called extremely frequently inside the class,
and occasionally outside.
In my case, I ended up solving it by adding an “abar” method that just
called “self.class.bar”, although using it that way does feel a bit
silly, and makes the code less readable (an observer might ask what the
difference between “bar” and “abar” is, for example).
Anyway, I just thought I’d share my particular experience. It’s not hard
to work around, but there are definitely good reasons to want to make it
work that way. It falls under the area of a “quirk” for me, but that is
of course just my personal experience based on my personal experience.
That has the added advantage that
you make the call explicit in instance methods which use it and it is
immediately clear that this method does not manipulate instance
state.
There are definitely cases where this could be advantageous, but there
are also cases where this is not necessary or desirable. In general, I
would personally say that if a particular mechanism is sometimes
beneficial, but sometimes not, it is better to leave it up to the person
writing the code to emphasise the mechanism where it is appropriate, and
de-emphasise where it is not. For example, sometimes it is beneficial to
be specific about the particular class of an object (or its
capabilities), but would that justify requiring every method call to be
prefixed by the class name, every time? I would say not. There are times
where being specific about it would be beneficial, but in the remaining
cases it would clutter up the code unnecessarily.
I think in the situation I outlined above, and possibly also in Josh’s
case, it falls in the realm of clutter. This does not, of course, take
away from the fact that in some situations it would be important, or
absolutely essential, to explicitly convey that the instance state will
not be manipulated. I know that I have certainly run into this case as
well- I won’t bother with a personal anecdote as I suspect you also
already know of many cases where it is extremely beneficial already.
I guess what I am saying is that if something is sometimes beneficial,
and sometimes detrimental, that enforcing it is not always the best
idea, but providing an optional means to make it explicit is beneficial.
I do not believe that is a good idea in general to either force a
mechanism that is only sometimes useful, or argue that as the mechanism
is sometimes important, that having a means to conveniently avoid the
mechanism when it is detrimental is not justified. There are of course
always all sorts of tradeoffs when designing a language- perhaps the
particular feature Josh and I would find beneficial is not readily
possible for some technical reason.
All IMHO.
Garth
PS. Wow, that message was a bit longer than I had planned.