Loyal Opposition to Const, Private, Freeze, Non-Configurable, Non-Writable...
mail.mozilla.org
mail.mozilla.org
On the one hand, I think he has a point that said features of JS.next are cutting against the grain of present-day JS. There are quite a lot of people programming in JS, many of whom may or may not deserve to be called good programmers but who nonetheless can produce functioning web pages, that would have to switch to a very different coding model to work with JS using these new features.
On the other hand, it's difficult to program your code when you know than any of your invariants can be accidentally stomped on by any other code that happens to run on the same page. It's also difficult to write libraries when everything's guts are exposed, even with red tape. Raymond Chen over at MSFT has an entire blog that could be titled "How Implementation Details Become De Facto Interfaces Due to Insufficient Encapsulation."
I think my final thought on the matter, is that when you think about it, it's really quite silly that we only have one language for front-end web development. It is, in fact, unacceptably silly. Like, seriously guys, what the hell? This is totally crazy. If you want to do server work, or non-web client applications, or embedded, or whatever else, you have a full array of programming languages. These run the gamut from ball-gag-and-leather-straitjacket static languages to walk-into-anyone's-house-and-drink-their-milk dynamic languages, from concise expressive languages to low-level bit-fiddly-ones, from parens to curly braces to significant whitespace to perl.
On the web we have JavaScript. Not that it's a bad language, it has its warts (what doesn't?) but it's actually a cute little language. But I don't have the option of using a language with static guarantees. Or deterministic memory management. Or asynchrony. Or macros. None of these are strictly better, they're all just personal preferences, but the point is, you don't have the choice.
That lack of choice is probably what's driving these against-the-grain additions to JS.next. They're adding more features to JavaScript so that it can cover some of the bases that it currently doesn't, and all the different directions it's being pulled in are understandably causing some stress. I think it's the wrong solution, but it's also the one with the easiest transition path. The ideal solution, is that we could use different languages from different paradigms, but how the hell do you crowbar them into existing browsers?
So uh... do I have conclusion? I dunno, language evolution is hard, let's go shopping.
function A {
var secret = 0; // <---------- private variable
this.method = function() {
alert(secret);
};
this.increment = function() {
secret++;
};
}
a = new A();
a.increment();
a.method(); <-------- prints 1
The main problem is just the inefficiency of declaring methods inside constructors.Edit: Hence, the keyword.
At the very extreme end of total dynamism, you get facility to implement whatever kinds of guarantees you want as libraries. Sad that in a language without meta programming features, the power is indeed reduced, but nevertheless extreme dynamism can be powerful enough to implement the guarantees that you need.
For example, if JS gets a facility to "run this code when an unknown method of this object gets called" and "-ditto- when an unknown field gets set or read", you can implement a public API for an object using a proxy object. You'll also be able to enforce member naming conventions if you want to. If you're doing the wrapper only for checking, you can keep the wrapper during development and leave it out when you deploy the code. You get a lot of flexibility.
Furthermore, if JS lets you install hooks like python decorators, you can implement guarantee mechanisms in JS as a library similar to what decorators get used for. Again, if it gets you better performance, you can strip decorators from deployed code during the minification phase.
So indeed, why not shoot for extreme dynamism in JS?
"const" does not add anything new to a variable.
If you don't want to change the value of a variable ...
don't change the value of the variable.
I've got a better idea: how about we mark the variable in some way and get the compiler to remember this for us. Then, when we come back to the code in 6 months, we won't make mistakes.I have a decade of experience in "dynamically" typed languages, and I prefer modern statically typed languages in almost all situations. Now it turns out you can have both: see Racket and Typed Racket for instance.
Sometimes I might want to use a library in a way its author didn't previously intend, so I might then want to modify a variable even if it's marked as const. It makes sense in a dynamic language to have a way to bypass the checks (like Ruby's "send" to access a private method). But that isn't an argument for discarding checks altogether.
The trouble with true private/protected variables is that you never really know how your code is going to get used and which parts of your library people may want to mess with. In that case, you can either play around with things you aren't really supposed to touch, or if that's not possible because everything's encapsulated, being in a hurry, you'll just fork the code and turn private methods into public ones. Both approaches suck, and the problem exists regardless of whether your language supports `private` and `const` keywords or not.
Until you have a user subclass your class and accidentally stomp over one of your private names, causing your class to mysteriously fail. I've been bitten by this before, and it'd be nice for JS to offer a solution.
Library consumers, on the other hand, will reap the most benefit from the proposed constraints.
`private` is important metadata for a library consumer. Documentation generators can ignore private members, and private tags serve as roadsigns that the member can be ignored if one is only interested in the API. `private` is a very powerful filter.
The same can be said for `const`: indicating a value shouldn't change eliminates one more thing one needs to hold in their head as they explore a lib's boundaries.
I don't care at all about the performance benefits; I care about communication. `private` and `const` are nearly-free, expressive documentation.
I actually like Ruby's "red tape" approach; it offers library consumers helpful metadata while still allowing flexibility. Maybe the best solution is for library developers to rigorously use the _private and CONST naming conventions, and reserve `private`, `const`, and `freeze` for security-sensitive code. Wouldn't that offer the most flexibility?
There's been such a big movement towards more strictness, more Java-like features and frameworks, while the more interesting development today seems to be moving away from that, towards more concise, flexible, and expressive languages like Ruby and Python, more FP ideas, and the rise of server-side Javascript.
I started programming professionally in Perl, where you were handed a loaded gun and learned the hard way not to shoot yourself in the foot. I appreciate the discipline that demands, making you think hard about what you're doing.
I really hope the Javascript community doesn't start to compromise its dynamic nature and lose one of the things that made it great. There are areas where syntax could certainly be improved/made more concise, but keep the dynamism and flexibility all the way (and add more!). Good on Jeremy for fighting for that.
I’m all for taking things away, but I personally want more in exchange. For example, if you’re going to give me immutable or const declarations, give me lazy evaluation as part of the bargain.
So I’m not opposed to taking things away, I am just optimistic that we can provide a lot more value than ‘constraints’ in exchange. And if we aren’t going to provide more value, I think we’re setting our sights too low.
It feels like we're circling around a local maximum and nobody is trying to make a really big leap when thinking about JS.next. We're getting the warmed-over leavings of middle-of-the-road language ideas.
If you really want constraints that are tailored for a team environment, make them programmable and put const and private in the standard lib. Then let Alice write something that prevents Bob from putting text in a SQL query or opening up an XSS vector in raw HTML. Or let Carol write something that ensures that all code makng certain writes to the database have an authorization check baked in.
The ideas behind powerful contracts / type systems have been around for a long time: provide properties that are checked such that you can rely on them.
It seems an interesting and difficult problem to try to add a general enough contract system to javascript, which would support things like const and private and "account balance is always positive". But I think that if done well, it would be the single defining feature which would draw me into using a language. Man, would that be awesome.
I agree on circling a local maximum, but some of this is just JS catching up to Ruby and Python. Syntactic affordances for usability that desugar to only lightly extended kernel semantics.
The big ticket items are modules, proxies, weak maps, binary data, and the like.
When I liken JS to x86, I'm not comparing it to assembly so much as to a ubiquitous target for compilation. JS is even stickier and longer-lived than x86 -- witness ARM's rise on mobile while the web evolves mostly-compatibly, including JS content and the JS language.
Contracts and macros are on the Harmony agenda, further out.
However JavaScript performance still leaves much to be desired - http://stackoverflow.com/questions/6216888/is-nodejs-faster-....
I want JavaScript to close the gap without sacrificing dynamism. And it won't - these feature are entirely optional and they free the implementors to make assumptions which allow further optimization.
"Pay for what you use"
To be totally honest I don't see myself writing plain JavaScript much longer, I'm closing in on 7 years now. At work I use quite a bit of CoffeeScript and very likely in the near future I'll leverage ClojureScript.
An example of this would be Cython for Python, which lets you get to C speed within 1 to 5% slow down due to interfacing with Python, and it has you write in a Pythonic dialect of C/C++.
Because that's a terrible, stop-gap optimization strategy. You can't JIT over the FFI boundary without some heroic API, and distributing compiled/compilable code is quite a hassle.
I think the author missed the point of private, because it does add something new. Specifically, it adds the ability to know that the property is not being altered outside the class without reading the entire code base.
Jeremy is right on. Keep JavaScript open. Add red tape if you must, but don't ACTUALLY lock it down. The openness (and lack of package management) are killer features.
We are lucky that JavaScript is the language in the browser; it could easily have been Visual Basic (shudder).
Also, he doesn't go over the most useful aspect of static OO, which is interfaces. Being able to force an incoming argument to have attached methods often makes code much simpler, because you don't have to deal with the possibility of someone passing different arguments into your function.
Arguments like this usually degenerate into shouting messages, so I would like to conclude that even though I am a huge fan of static typing, I don't think it's for javascript. You can always add a static type checker on top of a non-static langauge, so people like me will be happy. It might be more difficult to go the other way around.
[Also: if you have used jQuery, you've used a monad. They aren't scary!]
EDIT: Example: "in particular, how a monad must be capable of "wrapping" (their terminology) arbitrary datatypes, not just one particular datatype"
Yet it was very clear the author was talking about wrapping arbitrary types and IO String was a single example. And it goes on...
It seems to me that the restrictions he's talking about adding to the language are akin to making JS closer to Java, not closer to Haskell. Those similar restrictions - in Java - make extending an existing library much more difficult since you can't do things like add methods to an existing class/object; that method has to exist elsewhere & take the object you're extending as a parameter. This isn't an issue in Haskell since functions don't exist on an object, but are defined outside the types & operate on them.
Sure, you can't change the methods of a class has at run time. Who cares? Like I said you can just create an object wrapper, sometimes called a decorator if you are into design patterns, that has all of the methods of the original object plus a few more (or even a few less, doesn't matter). This gives you all of the functions of the original object plus more, just like modifying a class at runtime does. Possible in Java, possible in Haskell, possible even in JavaScript.
The only difference is that you have to explicitly call into the wrapper classes. You can't expect objects that you instantiate from outside your library to have these methods.
But again, who cares. If you want to use the cool new library functions, use them. Otherwise don't.
Specific example: if we are talking about jquery, you can't expect document.GetElementById('foo') to have special jquery functions. But you can expect $('#foo') to have them, which is the same thing so you really have nothing to complain about.
None of the proposed object-lockdown would prevent anything. You could use decorators, you could use an adapter, hell you could rewrite or fork the useful library and take out the object-locks. But all of those introduce the very overhead that JS benefits from avoiding. I mean compare the size of "Javascript Pattern" to the GOF book. What's more, languages like Java are written with a sensitivity toward design patterning, Haskell has robust types/interfaces. Javascript just has a big empty box, prototypes and closures. (This is an exaggeration but if you declaim it loudly enough you will get a chuckle.)
Private variables may be accessible outside of classes in Ruby -- but they already aren't in JS. And JS has extremely strong encapsulation through scoping and closures, so arguments against encapsulation based on the "language grain" fall a little flat for me. If an explicit private keyword enables optimization of existing functionality, then why not have one?
If you say so.
Once we start introducing these data structures we will have to figure out actual memory storing (16bit? 32bit? 64bit?) which obviously introduces another layer of complexity to "standardizing".
In my experience, no compiler is sufficiently intelligent to outsource this to. And if you have to review the code anyway (and you do), enforcing coding conventions is the least of your problems.
Being able to freeze an object to prevent anything modifying it would be useful for preventing 3rd party scripts you include on your site from deleting or modifying your code's behavior.
This was in addition to all of the script pulled in from ad networks, inline crap that was shoehorned in by a newspapers' own developers, all of our in-house stuff, various frameworks with the usual add-on libraries, analytics, maps....imagine if you will 16 meg page weights on a site with minimal graphics.
Needless to say this rolling clusterfuck of 3rd party javascript meant that at least twice a week a site would go haywire when some random code snippet from an ad network stomped all over one or more critical variables for the commenting system, or analytics would run off into the bushes for no readily discernable reason, you get the idea.
The Solution: aggressively namespace all of the mission-critical scripts we controlled and go heavy on encapsulation. Sure, this lead to god object code smells, but it cut way down on javascript-related site outages.
"const" does not add anything new to a variable. If you don't want to change the value of a variable ... don't change the value of the variable.
"freeze" does not add anything new to an object. If you don't want to change the shape of an object ... don't change the shape of the object. "
Now, having started to dabble a little in Rails and Node--and hence getting exposure to Ruby and JS--I do have respect for a lot of the interesting things you can do in those languages.
That said, I've also got a experience dealing with libraries and software engineering on various sized projects, and I'm sensing a pattern here.
It seems like good practices (encapsulation, static typing, etc.) are being ignored because they get in the way of "free programming". Now, is this actually an accepted attitude in the web development world, or are these people actively promoting terrible design practices?
I understand that programming routines for web pages and the like is not the same as for thick-client applications, but is the use of your library by other people through an interface or namespace collisions really not a large concern?
Bollocks. If javascript wasn't the language of browsers, nobody would use it. Its got nothing to do with javascripts awesomeness. Indeed, that it took so long for the community (or in this case Mozilla and Google) to finally say "fuck it, this is the shitbag we're stuck with so at least lets make it faster", just tells me how much they wanted something else to be the standard.
The only argument for NodeJs etc is that programmers can code the same language on client and server. Was there some "foresight" that made javascript the language of browsers? No.
That said, why fuck with it? There are ways to encapsulate fields and methods in javascript. There are also ways to get around it. Just as there are ways to get around private and const in C++.
If private and const really float your boat use GWT.