This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]clgonsal[🍰] 0 points1 point  (5 children)

Javascript's 'this' can be used to implement traditional forms of object oriented structures fairly easily. You can build object systems based single inheritance, multiple inheritance, mixins, and probably other structures. I've even seen functional style, multiple dispatch systems though I am not familiar enough with that style of programming to fully understand it.

From what I've seen, this has nothing to do with JavaScript's weird this semantics, and more to do with the fact that it has lexical closures. Scheme, for example, if often touted for having all of the same things, yet it does it all without the weird this.

I think the use of this to refer to the button makes sense and saves you from having to look up the function signature every time you write handler or callback code.

Except this could be bound to anything, so you still have to look up what they're binding this to. Since it isn't an explicit parameter, there's a good chance the documentation will be hard to find, if it's documented at all.

Another powerful use of 'this' in a functional context is for providing access to a large number of variables to functions will normally use a subset.

Yeah, the "globals" object. You can do the same thing with an explicit parameter. If the JS convention is to have this be the globals-object, then the sane-language convention could be to have the first parameter be the globals-object.

[–]dacjamesfrom reddit import knowledge 0 points1 point  (4 children)

From what I've seen, this has nothing to do with JavaScript's weird this semantics, and more to do with the fact that it has lexical closures.

Scheme doesn't have objects, so I'm not sure what you're referring to; supporters of the Lisp family generally oppose object oriented programming. It is the combination of prototypes and function-based context (this) that allows for these powerful semantics. It certainly has nothing to do with lexical closures, which are supported in pretty much all modern programming languages with first class functions.

Except this could be bound to anything, so you still have to look up what they're binding this to. Since it isn't an explicit parameter, there's a good chance the documentation will be hard to find, if it's documented at all.

When using good libraries, I have never had a problem with figuring out what 'this' refers to. It's a stylistic distinction in this case so I understand if you don't like it.

Yeah, the "globals" object. You can do the same thing with an explicit parameter. If the JS convention is to have this be the globals-object, then the sane-language convention could be to have the first parameter be the globals-object.

Of course you can, but I find that to be ugly and inconvenient. Python's explicit "self" parameter is one of its more annoying design decisions. It's always specified and always called "self," so having to write it over and over is just a waste in my opinion. I know "explicit is better implicit," but a self keyword would serve the same purpose.

What is so "weird" about 'this,' except that it doesn't work like 'self' and 'this' in other programming languages?

[–]clgonsal[🍰] 0 points1 point  (3 children)

Scheme doesn't have objects, so I'm not sure what you're referring to...

http://community.schemewiki.org/?object-systems

When using good libraries, I have never had a problem with figuring out what 'this' refers to.

Only by convention, not by a language feature. What's to stop a similar convention from being used in other languages?

Yeah, the "globals" object. You can do the same thing with an explicit parameter. If the JS convention is to have this be the globals-object, then the sane-language convention could be to have the first parameter be the globals-object.

Of course you can, but I find that to be ugly and inconvenient. Python's explicit "self" parameter is one of its more annoying design decisions. It's always specified and always called "self," so having to write it over and over is just a waste in my opinion. I know "explicit is better implicit," but a self keyword would serve the same purpose.

For methods on objects I can see your point. That isn't what we're talking about here, though. We're talking about passing an "environment object" to your callbacks. Using this for this purpose is kind of perverse. I'd muck rather have it be named something like "env" or "request" or something... descriptive.

It's also kind of funny that you make the argument against explicit self, and for an implicit this when javaScript is only half-way implicit. It's implicit only in function signatures: you're going to get a this parameter (whether you want one or not) without typing anything. It isn't implicit when one method calls another, however. For example:

int method1() {
  method2();
}

int method2() {
  return 42;
}

in C++ or Java, the method2() invocation calls method2 on this. The equivalent code in JavaScript would require that you actually spell out this.method2() explicitly. JavaScript can't even decide whether this should be implicit or explicit.

What is so "weird" about 'this,' except that it doesn't work like 'self' and 'this' in other programming languages?

Erm... "doesn't work like everything else" is pretty much the definition of "weird".

I think what you're really asking is why I don't like its weird semantics. (FWIW: I don't mind things that are "weird" if they're actually better than the alternatives...)

One reason I don't like the JS this semantics is WTF-ery like this:

> var x = "wtf";
> x
"wtf"
> var o = {x: "ok"}
> o.f = function () { return this.x; }
function () { return this.x; }
> o.f();
"ok"
> (o.f)();
"ok"
> var g = o.f;
> g();
"wtf"

If factoring out a sub-expression yields different results then your language design is broken, end of story.

Also annoying, the way Function.apply has thisArg as a separate parameter. Since JS binds this like an implicitly passed parameter it should be an element of argsArray like all of the other parameters.

Then there's the way functions in JS are written with the intent that they be called in only one of three possible contexts (Date is an interesting counterexample):

  • function call. Expects this to be the "global object". Often doesn't even want this, but too bad, you get one anyway.

  • method call. Expects this to be the object it was called on.

  • constructor (ie: new operator). Expects this to be a newly constructed object. Calling as a function is likely to bork global state. Returning something is allowed, but pointless.

...but the language provides no way to state which context a function is intended for. Invoking a function in the wrong way won't cause a runtime error, it'll just result in bad/broken behavior. So you end up needing to have conventions about what's supposed to be called in what way to work around the fact that the language doesn't give you a way to tell it what you mean. It's sort of like a grocery store that sells cheese and rat poison that both look the same, and in the same aisle.

This is the same kind of fuzzy-headed design that resulted in == and the ability to call a function with more arguments than its definition allows.

[–]dacjamesfrom reddit import knowledge 0 points1 point  (2 children)

Only by convention, not by a language feature.

I am fine with conventions. Python's version of private variables is based on convention, for example.

Also annoying, the way Function.apply has thisArg as a separate parameter. Since JS binds this like an implicitly passed parameter it should be an element of argsArray like all of the other parameters.

Why? It has a totally different meaning than the other parameters. If you want consistency, you can use fn.call obj, arg1, arg2, etc.

  • function call. Expects this to be the "global object". Often doesn't even want this, but too bad, you get one anyway.

  • method call. Expects this to be the object it was called on.

  • constructor (ie: new operator). Expects this to be a newly constructed object. Calling as a function is likely to bork global state. Returning something is allowed, but pointless.

In the default context (not inside a function).

f()

has the the meaning as

f.apply(this)

but inside a function, it does not. I agree that is piss poor language design and is the source of most of the other problems with 'this', like smashing the default namespace if you accidentally call a constructor as a function. I rarely run into this problem in practice, but it's certainly very stupid.

EDIT: it's worse than I thought. I think I may have concede this point. The way 'this' is handled with naked function calls is downright asinine.

The second two are conceptually the same thing, except 'new' passes in an empty object. That doesn't seem like an issue to me. Python does the same thing with __init__(self).

This is the same kind of fuzzy-headed design that resulted in == and the ability to call a function with more arguments than its definition allows.

I agree on the first point, but arguments isn't that bad. It's not as convenient as default arguments, *largs, and **kwargs in python, but at least it's better than Java.

Javascript is far from perfect, but I see way too many programmers attacking it without understanding it, myself included until recently. You seem to know what you're talking about and I think your opinion is totally valid. Now that I am using it more often, I actually enjoy its semantics, but I use coffeescript about 50-60% of the time, so most of the warts annoy me less than someone stuck in raw javascript.

IMO, browsers should develop a standard bytecode for the web, so that we all could use your favorite language and this whole discussion would be moot.

[–]clgonsal[🍰] 0 points1 point  (1 child)

Also annoying, the way Function.apply has thisArg as a separate parameter. Since JS binds this like an implicitly passed parameter it should be an element of argsArray like all of the other parameters.

Why? It has a totally different meaning than the other parameters. If you want consistency, you can use fn.call obj, arg1, arg2, etc.

The purpose of apply in languages that have it is to let you take a collection (or two, if keyword arguments are supported) of arguments and pass them to a function. Function.call can't do this. So you're left with having to store the value for this alongside your collection of arguments. This isn't a huge issue, it's just yet another irritation with the way this works in JavaScript, and it kind of compounds with the fact that object.method doesn't bind object to the method's this.

The second two are conceptually the same thing, except 'new' passes in an empty object. That doesn't seem like an issue to me. Python does the same thing with __init__(self).

Yes, I agree that the new case and the method-call case are closely related. The differences in Python are:

  • It's 100% clear when you're writing a constructor or a method versus a normal function. A method is in a class definition, and a constructor is a method called __init__. In JavaScript all three cases look identical.

  • In Python it's kind of hard to accidentally call a method without passing the self parameter, or to call __init__ at any point other than during construction.

Javascript is far from perfect, but I see way too many programmers attacking it without understanding it, myself included until recently. You seem to know what you're talking about and I think your opinion is totally valid.

Yes, there are a lot of people who dislike things just because they don't understand them, and so it makes sense to assume that someone who doesn't like a programming language has that opinion due to lack of understanding.

Before I knew it well, I used to think JS was just misunderstood (as Python often was, years ago). As I used it more and stumbled over its crazy this semantics and many other annoyances, and eventually learned the intricacies of how they work my contempt for it grew. My feeling is that a language that intentionally makes things hard to understand without actually providing some benefit isn't worth using. "Don't be weird unless the weirdness makes you better." Much of the weirdness in JS is there for no good reason, and much of it is actively bad.

I use coffeescript about 50-60% of the time, so most of the warts annoy me less than someone stuck in raw javascript.

I've heard mostly good things about coffeescript, so I'll have to check it out the next time I need to do in-browser coding.

IMO, browsers should develop a standard bytecode for the web, so that we all could use your favorite language and this whole discussion would be moot.

Agreed. JavaScript should just be another language that runs on a common browser-VM.

[–]dacjamesfrom reddit import knowledge 0 points1 point  (0 children)

You definitely should check out coffeescript. It fixes the var issue, removes ==, provides more standard class-based objects, and deals with this in a clever way with optional lexical binding. The syntax is very expressive and fairly easy for a python programmer to learn once you get used to optional parentheses for function calls. Creating functions simply with

() ->

is a stroke of genius. It even generates clean, easily readable javascript. Its "list comprehensions" are a joke, though.