Some object-oriented languages require you to put "self.", or equivalent, in front of all methods and/or member accesses.
This makes ExtractMethods painful, while encouraging warts such as ForeignMethods and Static Methods. These are controversial. Besides, if these were the only problems with explicit self, I think the enhanced readability (see below) will weigh more.
Languages guilty of requiring self-dot prefixes on methods only:
At least in PythonLanguage, where used to be only three scopes (global, module, and method/function), I think the explicit markup for calling self's methods is a big pro. One seldom puts anything except class and function definitions in the global / module namespaces, so actually we only have one namespace, the local namespace. This improves readability a lot.
Furthermore, I'm still surprised how few people realise that you don't have to call it "self": "s" is just as good if you use it consistently.
These are statically typed languages. That's how they get by without SelfDotSyndrome. Their compilers have a lot more information available to them at compile time, which they use to resolve members and methods.
The SelfLanguage is like this too, even though it's dynamically typed. It can do this because it does away with the difference between member access and method invocation - when you send a message to an object, that message can invoke either a data slot or a method slot.
Self is an interesting case. It uses its scoping rules to resolve method and member access (which, as is pointed out above, always look like method invocations), and the parent scope of a method is always the object to which it is attached. This isn't so in Python, which traditionally has only method scope and global scope. Perl's scoping rules are too weird to even contemplate, and so-called "members" in Perl aren't even variables and are thus not part of any scope. Someone please fill in details on Ruby's scoping and how it contributes to Ruby's SelfDotSyndrome.
It should be just .member. Except the '.' is harder to see than Ruby's '@'. And that should only be when you need a local variable with the same name as the instance variable (useful in setter/initialization methods for readability)--otherwise, scoping should be implicit.
This stuff about static vs. dynamic and scoping rules is kind of pointless. I suppose I'm trying to understand why these languages use this particular design.
EeLanguage uses SoftTyping, so type information is not necessarily available. It is an interesting case because its avoidance of SelfDotSyndrome is purely a consequence of LexicalScoping: a method is just a function definition that captures the state of the object as part of the lexical context.
Explicit self is not all bad. Having self explicit makes creating wrappers a lot easier.
What sort of wrapper?
One way to modify an object's behavior is to surrounding it with a "wrapper" object. The wrapper object receives messages, responds to the ones it wants to, and passes the rest to the "wrappee" object.
aRedButton wraps aButton aRedButton receives #size message, and passes it to aButton aRedButton receives #color message, and returns "red"But what if #size depends on #color? When the wrappee (aButton) sends a message to self, such as self.color, you want self to be the wrapper (aRedButton), to continue catching desired messages. Easy in Python, hard in Smalltalk.
Wrappers are used a lot in the VisualWorks GUI classes. Used too much, in some peoples' opinion.
Maybe I'm becoming a Ruby zombie, but I like the way Ruby does it -- no differentiation for methods, but the @ prefix for instance variables. (And @@ for class variables, too.) As I wrote over in RubyLanguage, I've used this to help me figure out where a class is coupled, which can give you quick guidance during refactoring. -- francis
But that's TheProblemWithSigils. People think they like them, even though they could simulate them.
Well, not exactly. Most languages won't let you start a symbol name with a non alphanumeric character like "@". You can assign your own house style -- "All instance variables need to start with the letters 'cv_'" or whatever -- but the ampersand's a little more concise, and if you don't have the symbol overload you have with Perl it can actually make things easier.
Because CeePlusPlus does not require self, there is a danger of namespaces getting confused:
static int table[] = {1,2,3};// global var int SomeClass::memfunc(int x) { return table[x] * datamember.size() }Here a member function of SomeClass is accessing a table which is in global space (though local to the source file). Now, suppose somebody adds a member 'table' to SomeClass, or one of its public bases. Now, the 'table' refers to a class member, not the global! This risk, I think, is one of the reasons for practices like starting all member names with 'm_' (which is basically forcing SelfDotSyndrome on oneself, cluttering up not only the code but the class definition). Another fix is to use
return ::table[x];// Reverse SelfDotSyndrome!!but are you going to put these :: in front of all globals? In practice, this problem rarely pops up, maybe because globals are rare, and most programmers start global names in uppercase and member names in lower case. But it could take a while to track down when it does pop up, since the true cause is so unexpected. Clearly, the reason for addition of the 'table' member may be completely unrelated to the 'memfunc' method (which could be in a derived class!); the programmer would not expect a change in the function of memfunc() due to this change. FWIW, there is a similar gotcha in Pascal, related to 'with XX do' (or however it's phrased).
Would somebody care to supply a realistic example that demonstrates how "self" (or "self." or "$self->") interferes with refactoring? I've refactored in Smalltalk, C++, and Perl, and I don't resonate with the problem that SelfDotSyndrome alludes to. But then perhaps I missed something. -- DaveSmith
I actually don't think that the "eases refactoring" reason is particularly true. Here's the only kind of example I can think of:
area | width. height | width: right - left. height: bottom - top. width * heightrefactors to:
width right - left height bottom - top area width * heightNot a particularly good example (does anybody have a better one?), but I do think that the SelfLanguage's lack of SelfDotSyndrome helped very slightly, in a couple of ways:
-- AdamSpitz
When you start out with functions and later realize that it would be better to use classes, the explicit "self" complicates refactoring. You have to insert "self" as the first parameter of each function that becomes a method, and you have to make sure that each class attribute "x" is replaced by "self.x".
Here's a (very simplistic) example: I have a constant and define functions for adding to and removing from the constant.
a = 0 def add(b): return a + b def sub(b): return a - bLater, I'd like to wrap this functionality into a class:
class C: def __init__(self, a): self.a = a def add(self, b): return self.a + b def sub(self, b): return self.a - bI use this kind of refactoring quite often.
-- AlbertBrandl
In JavaLanguage, I use the convention of prefixing instance attributes with an underscore:
public class C { private int _a; public C( int a ) { _a = a; } public add( int b ) { _a += b; } }In PythonLanguage, I use the underscore instead of the word "self":
class C: def __init__( _, a ): _.a = a def add( _, b ): _.a += bThat's a personal preference, of course, and not the standard pythonic way of doing things. But people who find "self" a bit distracting when written out might find it helpful, hopefully.
On the other hand, people experienced with SML/NJ, Haskell, EeLanguage or ErlangLanguage are going to have a hard time figuring out why you keep referring to the "never mind" variable...
In the PythonInterpreter?, the global '_' stores the last value returned:
>>> 'foo' 'foo' >>> _ + 'bar' 'foobar'
The habitual use of read & write accessors in Smalltalk resolves the SelfDotSyndrome in a way that makes refactoring simple. If instance variable access only in a getter/setter, then we have (using Point and Rectangle)
left ^self origin x right ^self corner x top ^self origin y bottom ^self corner y width ^self right - self left height ^self bottom - self top area ^self width * self heightIn order to
width ^width height ^height
(define (Circle:area ) (mul (:radius (self)) (:radius (self)) 3.141592))