Is there an advantage to an explicit "self" instead of the implicit "this"?

Asked

Viewed 568 times

16

Unlike most [most popular] object-oriented languages, which use a keyword to refer to the object that is "target" of a method call (commonly called this), the Python language requires every method to have an additional parameter (the first, and by convention usually called self) to represent this object. This seems to me a case of code Boilerplate, that you have to write always but that doesn’t add much...

(Note: this is a particular case of the use of "pronouns" in code, something possible in the Lisp language and used extensively in Perl)

Is there any concrete reason for not use one this implicit [in the design of a general purpose language or DSL]? Any use case where the explicit parameter allows/facilitates something that would be unfeasible if it were implicit?

Remarks:

  • Even in Python, if you get a reference to a method of an object it comes as a bound method, and you call him by omitting the first argument:

    class Foo(object):
        def bar(self, a, b):
            return self.x + a + b
    
    foo = Foo()
    bar = foo.bar
    bar(10, 20) # 10 é "a" e 20 é "b"; o "self" já está atribuído para você
    

    ...the use of a special function to "reassign" the same to a different object:

    foo2 = Foo()
    bar.__func__(foo2, 10, 20)
    
  • Nothing prevents a "normal" function from being transformed into a method by an operation similar to currying:

    def encadear(a, b):
        a.proximo = b
    
    class Foo(object):
        append   = lambda self, b: encadear(self, b)
        appendTo = lambda self, a: encadear(a, self)
    

    (through a more user-friendly syntax, of course... and in that case, prohibit the use of this in functions declared outside the context of an object would be desirable - unlike what happens with Javascript for example)

  • ...or that a method is transformed into a normal function by a reverse operation:

    var foo = {
        bar:function(a, b) {
            return this.x + a + b;
        }
    };
    
    var bar = foo.bar;
    var foo2 = { x:10 };
    bar.call(foo2, 20, 30); // O método original mantém o this explícito,
                            // mas ainda podemos atribuí-lo explicitamente
    

Therefore, I see no reason to explain the self, just unnecessary code... Is there a strong argument in favor, perhaps coming from the author(s) (s) of the Python language(s)? (or other language that uses similar strategy)

3 answers

6


One of the advantages of using explicit self is that you simplify the language:

  • With explicit self the scope of self will be a lexical scope equal to that of all other variables. No need to create a separate scope rule only for self.

  • With explicit self, methods and functions are the same thing. With implicit self, functions and methods behave differently.

  • With explicit self, it is easier to know how to call the method of an object with the self of another object (just pass another value in the first parameter). In languages with the most magical self it is necessary to call the function in a special way: in Javascript you have to use call, in Python you will have to take care not to create a bound method, etc.

An example that I think is worth adding to the discussion is the Lua language. There objects are sort of hash Tables and methods are simply Dae properties an object that happens to be a function (similar to Javascript). Unlike Javascript, there is no magic to set the self: by convention, you must call the method by passing the object itself as the first parameter.

local my_obj = {}
my_obj.x
my_obj.my_method = function(self)
  print(self.x)
end

my_obj.my_method(my_obj)

The drawback of the self-explanatory is the verbosity of this convention but it may be simpler to solve it with a little syntactic sugar than by changing the basic rules of language. For example, in Lua exoste some syntactic acoustics involving the ::

-- Esse código vai ser desassucarado pra algo parecido
-- com o exemplo anterior

local my_obj = {}
my_obj.x = 17
function my_obj:my_method()
  -- Aqui o `:` insere um parâmetro self no começo da lista de parâmetros
  return self.x
end

-- Aqui o `:` passa o objeto como primeiro parâmetro na chamada
-- da função.
my_obj:mymethod()
  • It’s a great example, I don’t know the language Lua but for what it showed here it is more "sane" than Python and Javascript. This syntactic sugar you mentioned is quite similar to making a currying in the first argument. It only seems to me that when using the :, the lexical scope of self becomes so problematic when the this implicit, no? Think of a closure where both the function Outer as to inner use this syntactic sugar (if this is supported by Lua of course): in that case there will be capture of the name self in internal, that neither the problem of var that = this in Javascript.

  • @mgibsonbr: The : is just a syntactic sugar (abbreviation) that is completely equivalent to if you had written a parameter called self at hand. http://www.lua.org/manual/5.2/pt/manual.html#3.4.10

  • Hehe I understand! What I’m saying is that its use makes it so amenable to a capture as to a self implicit (i.e. equivalent to if you had written a parameter called self on hand in both internal and external functions). But I agree that there is advantage in this case: the programmer always has the option of not use syntactic sugar whenever it causes problems...

  • @mgibsonbr: The inside function will not declare a self parameter so shadowing will not occur. Unlike Javascript, the self statement only occurs if you write it explicitly (with an explicit parameter or with :).

5

In my opinion the greatest advantage of the explicit self is to enable "closures" without pranks and without special treatment. Face avoids that problem where every Javascript beginner falls:

Objeto.prototype.metodo = function ()
{
    var self = this;
    setTimeout(function () {
        this.bla(); // errado, this será window
        self.bla(); // correto
    }, 250);
}

In Python the equivalent would be more or less:

class Objeto:
 def metodo(self):
  def closure():
   self.bla()
  glib.timeout_add(250, closure)

There is no ambiguity with the explicit 'self', while an implicit 'self' could be quite confusing in case there is more nesting of methods.

  • I see what you mean... by self explicit makes it easy to avoid Erasure name - just give a different name inside the closure - while an implicit would have conflict at all times. That’s a good point.

  • Correction: easy to avoid capture of the name.

4

Surely it would be possible that the self is an implicit parameter, such as this of other languages, but I believe this is because one of Python’s philosophies is to make things explicit.

Within a Python class, the difference between a method with and one without the self is roughly the same between a normal method and a static method in languages such as C++ and Java. In C++ and Java this is an implicit parameter in normal methods, and you have to mark the method as static if you want a static method. In Python this is completely wide open.

This also requires you to qualify access to class attributes. In C++ and Java, if you see a variable in the middle of a method you don’t know if it is a class member or not. You can qualify with this to make this explicit, but it is optional. In Python this is always explicit by design.

  • In short... the advantage of the explicit "self" is that it is explicit!

  • "You can qualify with the this to make this explicit, but it is optional" in Java and C++ yes, but in Javascript no... It is possible to have both: this implicit and this.membro must be explicit. Regarding the use of static, is a good argument, although even in Python you can’t create a static method without the decorator @staticmethod (or @classmethod, but then you also need a first parameter self or cls). If you try to call an "instance" method via Classe.metodo without passing as first argument an instance of the class, gives error (which is a good thing incidentally).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.