Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> due to the fact that functions in JS are first-class

I don't agree with that. There are plenty of languages with first-class functions that don't have this kind of confusion. There's nothing about a function being a value and being able to pass functions around that necessitates the awkwardness of JavaScript's 'this'.

What does necessitate it is the lack of separation between functions and objects. The fact that a function can also have its own properties is, to my mind, a mistake in the design of the language. And it's a decision that those other languages with first-class functions and no 'this' problem didn't make. If objects and functions are distinct concepts in the language, it's trivial to make 'this' be dead simple and allow programmers to have a simpler mental model.



You're correct that other languages have first-class functions which are capable of handling context without the implicit-this style like JS. Rust, for instance, uses `self`-as-first-parameter style.

However, `this` has nothing to do with functions being objects, besides the fact that the prototype object is a member to the constructor function.


What model, exactly?

In perl/c[++]/#/java, you have to carry object around with a method (or use functors), otherwise you’ll call it with wrong arguments. In python methods are bound implicitly in a class, but explicitly in assignment (iirc). In Lua you’re explicit with obj:mtd() instead of obj.fun(). In js, obj.mtd() is eqv. to obj:mtd() in that sense, but you can bind() to anything.

Which model is preferable? ‘this’ is natural complexity, and under ‘use strict’ it behaves just okay. It is programmers who don’t care to grasp it.

Saying that as a natural js hater.


> In python methods are bound implicitly in a class, but explicitly in assignment (iirc).

Oh, it's quite a bit more involved than that :)

I'm going to ignore Python 2 and the C API here.

In Python functions are descriptors. This means they have (mostly) a __get__ function which returns a closure passing self or cls or nothing (corresponding to a regular method, a class method and a static method; @classmethod and @staticmethod change the implementation of __get__, but of course they don't, because everything is a special case in CPython; note that "regular methods" are "regular functions" — all functions behave like methods if you treat them like one). If you write

   class Class:
       def foo(self, x): print(x)
then foo is a regular old function. The magic is in the dot operator (quite literally): instance.foo is a different operator from Class.foo, and instance.foo is not Class.foo (one is a bound method the other is a plain function). The former invokes the descriptor protocol to the effect of, roughly, type(instance).__dict['foo']__.__get__(type(instance), instance), which returns a closure calling the "real foo" (Class.foo) with instance as the first argument. Similarly @classmethod has the effect of __get__ returning a different closure, which passes type(instance) as the first argument instead.

Python. It's complicated®.


Yeah, one most complex way to do it. I just tested my assertion for the sake of truth and it seems correct:

  class Foo:
      def bar(self, x):
          print 'bar', x
  
  def f(x): print 'f', x
  
  foo = Foo()
  foo.baz = f

  print(foo.bar)  # <bound method Foo.bar of <__main__.Foo object>>
  print(foo.baz)  # <function f>
  foo.bar(5)      # bar 5
  foo.baz(6)      # f 6
Now who wants to say that 'js this' is quirky and complicated?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: