Is there any code in Firefox (as of 2020) that comes from Netscape Navigator?
retrocomputing.stackexchange.com
retrocomputing.stackexchange.com
This supports the statement that code is read many times more than written. So think about that when trying to be clever.
This can be solved at a language level by making if-else and switch (aka match) expressions. I don't understand why more languages don't do this. It doesn't seem like it would too hard to implement, and C# 8 has shown that it can integrate well an existing C-like language.
Of course some libraries like cheerio require a callback with an available ‘this’ bound into it.
> ({ literalProperty: () => {} }).literalProperty.name
'literalProperty'
> ({ ['computedName']: () => {} }).computedName.name
'computedName'
> const variable = () => {};
> variable.name
'variable'
So if you want to name an arrow function, you can usually assign it to a variable.* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
* https://developer.mozilla.org/id/docs/Web/JavaScript/Referen...
new Error().stack
The following demonstrations take the prior examples and put the stack call into the arrow function bodies and wrap that in an arbitrary function for an additional line in the stack trace output.The first example assigns the arrow function to an object property. And then generates the name of the object's property name. This does nothing to describe the function. Here is a better example:
var stack,a=function(){({ myProperty: () => {stack = new Error().stack;} }).myProperty();};a();stack;
In the browser that outputs: "myProperty@debugger eval code:1:59
a@debugger eval code:1:82
@debugger eval code:1:102
Its a bit more clear in Node's REPL 'Error\n' +
' at Object.myProperty (repl:1:59)\n' +
' at a (repl:1:82)\n' +
' at repl:1:102\n' +
' at Script.runInThisContext (vm.js:120:20)\n' +
' at REPLServer.defaultEval (repl.js:432:29)\n' +
' at bound (domain.js:429:14)\n' +
' at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
' at REPLServer.onLine (repl.js:759:10)\n' +
' at REPLServer.emit (events.js:333:22)\n' +
' at REPLServer.EventEmitter.emit (domain.js:485:12)'
Essentially the stack traces represent a method call as designated by a function whose identity is bound to an object property, but the function itself remains unnamed. The second example is logically identical to the first except for the minor syntax difference of array notation versus a word type variable name.The third example is logically different than the prior two examples:
var stack,a=function(){var myVariable = () => {stack = new Error().stack;};myVariable();};a();stack;
Browser:
"myVariable@debugger eval code:1:51
a@debugger eval code:1:71
@debugger eval code:1:81Node: 'Error\n' + ' at myVariable (repl:1:51)\n' + ' at a (repl:1:71)\n' + ' at repl:1:81\n' + ' at Script.runInThisContext (vm.js:120:20)\n' + ' at REPLServer.defaultEval (repl.js:432:29)\n' + ' at bound (domain.js:429:14)\n' + ' at REPLServer.runBound [as eval] (domain.js:442:12)\n' + ' at REPLServer.onLine (repl.js:759:10)\n' + ' at REPLServer.emit (events.js:333:22)\n' + ' at REPLServer.EventEmitter.emit (domain.js:485:12)'
The output of assigning an arrow function is identical, in both environments, to assigning a regular anonymous function:
var stack,a=function(){var myVariable = function () {stack = new Error().stack;};myVariable();};a();stack;
That is different than assigning to a named function: var stack,a=function(){var myVariable = function myFunctionName() {stack = new Error().stack;};myVariable();};a();stack;
'Error\n' +
' at myFunctionName (repl:1:76)\n' +
' at a (repl:1:96)\n' +
' at repl:1:111\n' +
' at Script.runInThisContext (vm.js:120:20)\n' +
' at REPLServer.defaultEval (repl.js:432:29)\n' +
' at bound (domain.js:429:14)\n' +
' at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
' at REPLServer.onLine (repl.js:759:10)\n' +
' at REPLServer.emit (events.js:333:22)\n' +
' at REPLServer.EventEmitter.emit (domain.js:485:12)'
And both of those are different to anonymous functions not assigned to a variable. Both of the following examples produce the same output: var stack,a=function(){(function () {stack = new Error().stack;}());};a();stack;
var stack,a=function(){() => {stack = new Error().stack;};};a();stack;
'Error\n' +
' at repl:1:46\n' +
' at a (repl:1:65)\n' +
' at repl:1:71\n' +
' at Script.runInThisContext (vm.js:120:20)\n' +
' at REPLServer.defaultEval (repl.js:432:29)\n' +
' at bound (domain.js:429:14)\n' +
' at REPLServer.runBound [as eval] (domain.js:442:12)\n' +
' at REPLServer.onLine (repl.js:759:10)\n' +
' at REPLServer.emit (events.js:333:22)\n' +
' at REPLServer.EventEmitter.emit (domain.js:485:12)'
You can see in the first anonymous function example that an IIFE (immediately invoked function expression) is used. Function's require identity, aside from 3 exceptions, otherwise they throw an error. The three exceptions are arrow functions, IIFE, and function arguments.So much of this discussion is nonsense though, because it doesn't make sense to arbitrarily complicate your code with unnecessary objects merely to provide your anonymous arrow functions with identity. The whole point of arrow functions is to reduce syntax and thereby provide easier to read code, which only the third of those three examples provide.
It is also helpful to understand that a function's name is an identity known to the function, which means it is available to the internal logic of the function as a local reference and not a scoped reference. The identity of a variable name to which a function is assigned will always be a scoped reference, and that distinction also results in different output in stack traces.
Furthermore, none of those examples demonstrates the most important use case, callbacks, or functions as arguments to event handlers. In Node the callbacks become nested very quickly and often times many layers deep. Each use of an arrow function is an anonymous line in the call stack and several layers of anonymous calls is less helpful to read. It's not hopeless because the stack trace provides the location of each call, but you have to dive into the code on each line mentioned to see what is actually happening instead of just reading the function names from a more helpful stack trace.
What I was saying is if you are currently using a named function:
function foo(bar) {
// …
}
you don’t lose the name by making it an arrow function: const foo = bar => {
// …
};
and yes, you can name your callbacks and event handlers like this before passing them to functions. Introducing variables to name values (any values, not just functions) doesn’t really complicate code. Many times, it can be a readability improvement.https://www.artima.com/weblogs/viewpost.jsp?thread=147358
>All Things Pythonic: Language Design Is Not Just Solving Puzzles. By Guido van van Rossum, February 10, 2006.
>Summary:
>An incident on python-dev today made me appreciate (again) that there's more to language design than puzzle-solving. A ramble on the nature of Pythonicity, culminating in a comparison of language design to user interface design.
[...]
http://lambda-the-ultimate.org/node/1298
>Guido: Language Design Is Not Just Solving Puzzles
>And there's the rub: there's no way to make a Rube Goldberg language feature appear simple. Features of a programming language, whether syntactic or semantic, are all part of the language's user interface. And a user interface can handle only so much complexity or it becomes unusable.
>The discussion is about multi-statement lambdas, but I don't want to discuss this specific issue. What's more interesting is the discussion of language as a user interface (an interface to what, you might ask), the underlying assumption that languages have character (e.g., Pythonicity), and the integrated view of semantics and syntax of language constructs when thinking about language usability.
[...]
In the original language design I mean, since non-arrow functions with dynamic "this" only make sense in the context of having been mistakenly baked into the language from day one (or so). If JavaScript started out with only fat arrow functions, and had a simpler way of passing the current object like Python's or CLOS's or Dylan's or ScriptX's explicit "self" parameter, there would have been no confusion or automatic nuclear foot guns or need for two subtly semantically and syntactically different kinds of functions.
Any JavaScript programmer who doesn't clearly understand the difference between non-arrow and arrow functions, and the nuances of dynamically bound "this", and when to use each type of function, is dangerous and libel to write subtly buggy code. Because there should only be one type of function!
There was no reason to design the language and function syntax and semantics in such a mistakenly complex fragile way, that eventually spawned millions of blog posts explaining the nuances and dangers of "this". Because you know that behind every one of those helpful blog posts is a well intentioned programmer who got screwed by "this", and wanted to help other people avoid their mistakes.
I've been programming JavaScript for years, and I STILL get screwed by "this". Whenever something goes inexplicable wrong and I find myself pounding my head up against a cinderblock in frustration because I can't figure it out, I take a step back and search my recent changes for "this", and in most cases, I've just accidentally used a function instead of a fat arrow.
There were plenty of other languages that could have served as examples of the right way to do it, like Smalltalk or Python or Common Lisp CLOS or Dylan, but they were ignored when JavaScript was designed.
It depends. Often you can optimize them out.
Fat arrow functions struck me like one of those half-assed solutions Trump (edit: or Obama) comes up with for a terrible problem of his own creation, a foolish mistake that nobody in their right mind would have ever made in the first place. And then he expects praise for his solution, and nobody remembers he caused the problem it was supposed to solve in the first place.
I agree with the sibling comment by austincheney: JavaScript would have been a much simpler and less bug-prone language if not for "this" being dynamically scoped and magical, which later required nailing fat arrow functions onto the side, that were almost but not quite entirely unlike functions.
Have you ever tried explaining why there are two different kinds of functions in JavaScript to a beginning programmer, and seen their eyes glaze over when you digressed into the nuances of "this", lexical scoping, dynamic scoping, call and apply, closures, and binding functions? You have to understand all that before you truly understand functions in JavaScript, and much of it is irrelevant crap.
Lexical, dynamic, both, or neither? Pick a lane, JavaScript!
>"dynamic this binding is an oft-fired footgun" -Brendan Eich
C++ does it behind the scenes, but it's just a hidden parameter, not a property of the hidden "virtual machine", because C++ doesn't have a virtual machine. But if you look at the C code generated by the CFront C++=>C compiler, you will see that every method has an explicit first "this" parameter whose type is the class it's defined in.
The way "this" is defined in JavaScript unnecessarily exposes the internal implementation details of the first JavaScript interpreter, which all subsequent JavaScript interpreters and compilers then had to be compatible with.
Simply knowing about normal function parameters and lexical binding like in Python is not enough: There is an invisible a VM interpreter thread somewhere that you have to know about, which has a "this" property (or "horrible global object", as Douglas Crockford puts it), and the only way to change it is indirectly through method applications with ".", or by using call and apply. So JavaScript "this" is a magic keyword, not just a normal parameter like all the rest. In the same way JavaScript "arguments" is magic, not just a normal argument like Python or Lisp &rest arguments.
And this needlessly adds to the complexity and surface area of the language, and bakes in unwanted behaviors like dynamic binding, when most of the civilized world agrees that lexical binding is superior, less surprising, and easier to reason about, and dynamic binding should be the exception that you have to go out of your way to use, not the default behavior for the implicit first argument of every method or function.
That sounds like an unnecessarily complicated and possibly wrong way to think about it. `this` acts exactly like a parameter in ES5 strict mode (`x.f()` being `f.call(x)` and `f()` being `f.call(undefined)`), and does not act like dynamic binding.
JavaScript will always suffer from that mistake, no matter how much they try to paper over it with strict mode or TypeScript. It's way too late to remove non-fat-arrow functions from JavaScript, so they will always be a foot gun, whether or not you're using strict mode.
If you define a non-fat-arrow function and mention "this", and then pass it out to somebody you don't know or have any control over or contact with, who calls that function without going out of their way to properly bind it with call or apply, then they will be screwed.
There are arguments to be made that it’s confusing coming from other languages given that it acts nothing like their “this”es, but I’m not sure that “properties of invisible VM interpreter threads” are related at all.
And why did Douglas Crockford say "this" was "horrible", and that ES5/strict mode was "much less wrong than binding the global object, but is still not right"?
And why is "this" always showing up as #1 in the lists of "10 Most Common JavaScript Mistakes"?
https://www.toptal.com/javascript/10-most-common-javascript-...
>Buggy JavaScript Code: The 10 Most Common Mistakes JavaScript Developers Make
>Common Mistake #1: Incorrect references to this
>I once heard a comedian say:
>I’m not really here, because what’s here, besides there, without the ‘t’?
>That joke in many ways characterizes the type of confusion that often exists for developers regarding JavaScript’s this keyword. I mean, is this really this, or is it something else entirely? Or is it undefined?
>As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of “this/that confusion”.
https://javascriptissexy.com/understand-javascripts-this-wit...
>Understand JavaScript’s “this” With Clarity, and Master It
>(Also learn all the scenarios when this is most misunderstood.)
>The this keyword in JavaScript confuses new and seasoned JavaScript developers alike. This article aims to elucidate this in its entirety. By the time we make it through this article, this will be one part of JavaScript we never have to worry about again. We will understand how to use this correctly in every scenario, including the ticklish situations where it usually proves most elusive.
https://dev.to/joelnet/rethinking-javascript-the-complete-el...
>Rethinking JavaScript: The complete elimination and eradication of JavaScript's this.
>If this is so difficult to reason about, why don't we just stop using it? Seriously. Why. don't. we. just. stop. using. it.?
>If you have read How I rediscovered my love for JavaScript after throwing 90% of it in the trash, then you won't be surprised when I say I am throwing this away. this is gone. goodbye. this won't be missed.
>With functional JavaScript, you will almost never see this. I say almost never because even though your code doesn't contain this, you have little control over 3rd party libraries. Popular libraries like React, jQuery, eventemitter2 and many others will force this down your throat.
>Here are some examples of how libraries force us to use this.
[...]
https://softwareengineering.stackexchange.com/questions/3060...
>Why doesn't ES6 have thin-arrow functions?
>See the proposal to add arrow functions:
http://wiki.ecmascript.org/doku.php?id=harmony:arrow_functio...
[That link is broken but this one works: https://tc39wiki.calculist.org/es6/arrow-functions/ ]
>What it says is:
>However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun.
That's right: the original fat arrow proposal championed by Brendan Eich himself literally called "dynamic this binding" an "oft-fired footgun", citing it as the rationale to justify the design of fat arrow functions. That comes directly from the horse's mouth. Do you really disagree with Brendan Eich on that point?
More interesting discussion about this and that:
Douglas Crockford on Fat Arrow Functions in JavaScript (yuiblog.com)
https://news.ycombinator.com/item?id=3780367
What is the meaning of this?
https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-t...
>JavaScript is an amalgam of good parts and bad parts. Its best parts came from Self (prototypes) and Scheme (lexically scoped nested functions). But the interaction of those two very good parts produced some bad parts.
>When a function is called with the function invocation pattern, its this is not bound to the outer function's this as we would hope, but is instead bound to the global object, which is horrible. (ES5/strict binds the inner function's this to undefined, which is much less wrong than binding the global object, but is still not right.) The workarounds for this include the use of bind functions and riddles like
>var that = this;
I could go on. There are literally THOUSANDS of blog posts by people who got screwed by "this", and then posted about it to warn other people not to make the same mistake they did.
It looks like a variable, and it kind of but not really behaves like an implicit first parameter in some circumstances, but that's not really what's going on at all. And that is the danger, and source of misunderstanding and bugs: it looks like something that it's not.
For one thing, you can't assign to "this" like a variable. For another thing, "this" doesn't show up in "arguments" (which is also magic). If you think "this" is not mysterious and just a normal but implicit argument, you don't really understand it.
Which is my point: "this" is such a terribly designed language feature that even experienced JavaScript programmers misunderstand it, and it causes subtle hard to find bugs, even for experienced JavaScript developers. It's not just mysterious, it's dangerous.
https://books.google.nl/books?id=4RChxt67lvwC&pg=PA169&lpg=P...
>JavaScript: The Definitive Guide
>Note that this is a keyword, not a variable or property name. JavaScript syntax does not allow you to assign a value to this.
>Unlike variables, the this keyword does not have a scope, and nested functions do not inherit the this value of their caller. [...]
Here is how "this" is explicitly defined as a keyword in the JavaScript BNF grammer, in this example as the very first option of PrimaryExpression. Definitely not a variable or Identifier. Quite magic. No other "variable" name is defined as a top level PrimaryExpression. "this" is very special.
https://tomcopeland.blogs.com/EcmaScript.html
PrimaryExpression ::= "this"
| ObjectLiteral
| ( "(" Expression ")" )
| Identifier
| ArrayLiteral
| Literal
You can even ask devtools for its opinion: >var this = 1;
VM2547:1 Uncaught SyntaxError: Unexpected token 'this'You’re also misusing terminology by saying `this` is “dynamically scoped” (it does not have dynamic scope[1], that would be terrible) when documents you’re quoting say “dynamically bound”. The difference is important, which is why three people have corrected you on that now.
[1] https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynam...
Explain just how "this" is lexically scoped, what "lexically scoped" means, and then explain why they had to add fat arrow to the language, if "this" is "just like regular parameters", please?
If "this" is lexically scoped, then why can call and apply change it at runtime?
And how do explain this stackexchange discussion, which directly addresses and answers the question? The detailed answer "yes" got five votes and was accepted. The other answer "no" got one vote and was not accepted. What's your answer?
https://softwareengineering.stackexchange.com/questions/3961...
Question> Is `this` in JavaScript an example of dynamic scoping?
Accepted Answer> To be clear, JavaScript does not, in fact, have dynamic scope. It has lexical scope. Plain and simple. But the this mechanism is kind of like dynamic scope.
>The key contrast: lexical scope is write-time, whereas dynamic scope (and this!) are runtime. Lexical scope cares where a function was declared, but dynamic scope cares where a function was called from.
>Finally: this cares how a function was called, which shows how closely related the this mechanism is to the idea of dynamic scoping.
And you ironically wrote:
>(it does not have dynamic scope[1], that would be terrible)
Whatever you call it and however you define dynamic scope, the dynamic way "this" behaves IS terrible, and undeniably causes lots of easy to make, hard to diagnose bugs. That is why Brendan Eich called it a "footgun". That was my point, and that was why they had to add fat arrow to the language.
8.3.2 GetThisEnvironment ( )
The abstract operation GetThisEnvironment finds the Environment Record that currently supplies the binding of the keyword this. GetThisEnvironment performs the following steps:
1. Let lex be the running execution context’s LexicalEnvironment.
2. Repeat
a. Let envRec be lex’s EnvironmentRecord.
b. Let exists be envRec.HasThisBinding().
c. If exists is true, return envRec.
d. Let outer be the value of lex’s outer environment reference.
e. Let lex be outer.
NOTE The loop in step 2 will always terminate because the list of environments always ends with the global environment which has a this binding.Source: http://www.ecma-international.org/ecma-262/6.0/#sec-getthise...
This is pretty unambiguous. The "this" binding is resolved in the lexical scope, not the dynamic scope.
Yes.
> Explain just how "this" is lexically scoped, what "lexically scoped" means, and then explain why they had to add fat arrow to the language, if "this" is "just like regular parameters", please?
`this` is lexically scoped* because the function it belongs to is determined by where it appears in the code.
Fat arrow was added to the language with this difference because it’s useful to have a function without its own `this`.
> If "this" is lexically scoped, then why can call and apply change it at runtime?
It’s always set at call time. Not a matter of scope. (Parameters: also have values determined at call time, also lexically scoped.)
function a() { return this; }
let obj = {a};
obj.a() === obj
> And how do explain this stackexchange discussion, which directly addresses and answers the question? The detailed answer "yes" got five votes and was accepted. The other answer "no" got one vote and was not accepted. What's your answer?The answer is wrong despite its votes. The comment on it by JacquesB is correct: “This is confusing values and variables. this cares cares how a function is called the same way parameters care how a function is called - they get their value at runtime when the function is called. But the scope of all variables (including this) is lexical and not dynamic.”
> Whatever you call it and however you define dynamic scope, the dynamic way "this" behaves IS terrible, and undeniably causes lots of easy to make, hard to diagnose bugs. That is why Brendan Eich called it a "footgun". That was my point, and that was why they had to add fat arrow to the language.
I disagree, but am mostly here to argue against objectively wrong information rather than opinions.
* in contrast to dynamically scoped. In JavaScript it’s also common to use “lexical scope” in contrast to “function scope” to distinguish `let`/`const` vs. `var`. In the JavaScript spec, the lexical thisMode refers to where the (arrow) function appears, not the position of the `this`.
Reality check: Are we even talking about the same language? I'm talking about JavaScript. Which language are you talking about, C++? If you're not talking about JavaScript, then you replied to the wrong comment. Or are you just trolling and gaslighting, because you were offended by the Trump reference? I'll give you the benefit of the doubt that you're also referring to JavaScript, and that you sincerely believe what you say, because you need to change your beliefs.
Please go read any elementary JavaScript tutorial, or any of the thousands of blog posts by people who got screwed by accidentally mis-understanding for a moment and mistakenly thinking that "this" was lexically scoped, then got burnt, but learned from the experience, and wanted to share with everyone else what they learned by shooting themselves with an "oft-fired footgun": "this" is dynamically scoped, and changes meaning at runtime, regardless of the surrounding lexical environment in which it was defined, UNLESS you use fat arrow functions, which were specifically designed to work around that problem.
If "this" behaved like an implicit parameter with lexical scope, then why did they bother adding fat arrow functions to the language as an afterthought, to work around the problem you don't seem to believe exists?
One more time, I will quote the rationale section of Brendan Eich's fat arrow proposal:
https://tc39wiki.calculist.org/es6/arrow-functions/
>"dynamic this binding is an oft-fired footgun" -Brendan Eich, ES6 Arrow Functions Proposal
If you're right, then Brendan Eich, Douglas Crockford, Anders Hejlsberg, many other expert designers and programmers of JavaScript and TypeScript, and a whole lot of other people, are also extremely confused:
https://www.forumone.com/ideas/typescript-application-scale-...
>TypeScript borrows some features from the upcoming ECMAScript 6 specification, too. There is convenience syntax for day-to-day programming tasks, such as the arrow function, borrowed from CoffeeScript. The arrow function, which looks like this: (foo, bar) => baz, is shorthand notation for (function (foo, bar) { return baz; }).bind(this). This automatically captures the current value of “this” in scope, which is more often than not what you want. The proposal even states “dynamic this binding is an oft-fired footgun.”
http://jsnext.blogspot.com/2012/07/arrow-functions.html
>Arrow Functions are lexically bound to the 'this' of where it is declared. In other words, when an Arrow Function is declared, whatever the scope is at that time, that is 'this'. [...] Why add Arrow Functions? Why add this? We already understood what was going on... so why change it? I think that Brendan Eich has provided a great list of reasons ('Rationale' section): [...] However, we don’t want CoffeeScript’s ->, it’s confusing to have two arrows and dynamic this binding is an oft-fired footgun.
What exactly do you believe Brendan Eich meant by "dynamic this binding"? How can "this" be dynamically bound, yet behave "like an implicit parameter with lexical scope" (as you wrongly claim) at the same time?
Is Brendan Eich and everyone else in the JavaScript and TypeScript communities mistaken, and they foolishly added fat arrow functions to JavaScript for no reason, but nobody pointed out that embarrassing mistake until you came along?
If you're right, then you're barking up the wrong tree by arguing with me about it, so by all means, get on Twitter and tell Brendan Eich himself, ASAP! Your argument is with him and everyone else, not me. Maybe it's not too late to turn that ship around, but in my opinion it's already sailed.
But if you're wrong, then you probably have a lot of bugs to fix in your code, and should stay off Twitter.
If you truly believe in your heart of hearts that "this" is lexically scoped, you have definitely proven my and Brendan's point that "this" is a terrible "oft-fired footgun" that causes lots of deep confusion and insidious misunderstanding: just take a step back and look at how sure you are of yourself. Because "this" is certainly more mysterious and dangerous than YOU believe it is.
Dynamic scope means something different. Dynamic scope means that a variable binding from the call site is visible in a called function and down the call stack. This is not how "this" works. The "this" binding at the call site is never visible inside the called function, unless the called function happen to be nested inside the same lexical scope.
"this" is confusing because it gets rebound at every call, even if the function is not called using dot expression. But it is not because of dynamic scoping.
C++ is designed to compile to an implementation of an abstract virtual machine defined by the standard.
https://en.wikipedia.org/wiki/Leaky_abstraction
https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-a...
Don't get what I mean by leaky abstractions? Take non-fat-arrow functions for example. They're more expensive than fat-arrow functions, because they have a "prototype" property. And that's used to IMPLEMENT JavaScript's weird quirky form of object oriented programming, by giving you yet another way to call that function with "new" to create an object using that prototype, in a way that makes it a dangerous mistake to call that function the normal way without "new" (by sorta working on the surface usually without throwing an error, but causing deep subtle hard to diagnose bugs).
That is yet another double barreled footgun, thanks to a leaky abstraction with functions and "new": mistakenly calling a JavaScript class directly instead of using "new", or mistakenly calling "new" on a non-class function or fat arrow function, which doesn't have a prototype and can't be used as a class. Non-fat-arrow functions and "new" are like a footgun whose barrel is bent around aiming at the head of person who's shooting it. Fat-arrow functions don't solve the problem or eliminate the footgun, they merely add another barrel to the gun, aimed directly at your foot, too.
So if you can't directly call or apply a class function that has a prototype like a normal function, then why the hell is it a function anyway, instead just being a class like most other oop languages have, and why the hell does that irrelevant feature of functions having an optional prototype force that overhead on ALL the other functions in the system, whether or not they need it, even if you're using purely functional programming without objects?
That was one of the original rationals for fat arrow functions, as well as papering over the dynamic "this" binding mistake: to get rid of the overhead of the function prototype link, since non-class-constructor functions were so predominantly common. But they didn't bother to fix the obnoxious quirk about overloading functions with behaving like classes, but having to call them differently with "new", instead of simply having classes that were not callable functions, and being able to support multiple constructors with different names and signatures, like so many other object oriented programming languages do (but which JavaScript can't support, since class === function === constructor, there can only be one constructor per class by definition).
Conflating functions and classes and constructors is just insane, a pointless mistake and implementation detail with no upside and many downsides. That's what I call a functionally classic leaky abstraction. ;)
https://news.ycombinator.com/item?id=3780748
>mattbriggs on Mar 31, 2012 | parent | favorite | on: Douglas Crockford on Fat Arrow Functions in JavaSc...
>the this keyword still works exactly the same, just a terse syntax for functions and for function binding to the current scope.
>currently, function(){} is the exact same as the proposed ()->{}, and (function(){}).bind(this) is the exact same as ()=>{}
>starwed on Mar 31, 2012 [-]
>This is not just about syntax. Unless using bind somehow grants the mentioned property that
>>"Fat arrow functions do not have prototype properties, which makes them cheaper to make. They are immutable."
[That was quoting Douglas Crockford: https://yuiblog.com/blog/2012/03/30/what-is-the-meaning-of-t... ]
>mattbriggs on Mar 31, 2012 [-]
>granted, but that sounds more like a micro optimization rather then significantly changing the behavior of the language
Perl originally had the exact same problem of leaky abstractions, only much much worse. The language design was deeply defined by nothing more than the one implementation of the Perl interpreter itself. There was no "abstract virtual machine" design written down. There was only the source code to the one existing implementation of Perl.
You had to understand many trivial details about how that one Perl interpreter just happened to be implemented, in order to truly understand Perl. (Try explaining Perl references without making all kinds of nuanced excuses and implicit references to how the Perl interpreter itself works.)
It took Perl (or whatever the kids are calling it these days) decades and decades to dig its way out of that hole, and by the time they did, it was irrelevant. JavaScript got a lot luckier.
"Please don't use Hacker News for political or ideological battle. That destroys the curiosity this site exists for."
Even if it is true that code is read many times more than it is written, isn't that an argument for writing shorter, more dense code, so there's less of it to read? And an argument for more clever code so it's more interesting to read? If you're going to spend the next six months reading, that doesn't make you want all books to turn into Spot the Dog, does it? To the contrary the more you do something, the better you get at doing it; reading more code is often suggested as a way to make yourself better at programming. In fact, isn't it equally an argument for "if people have to read the code, there aren't enough comments, and/or there wasn't enough code verification"?
Comments are for people to read, code is for computers to execute. The refrain "code is for people to read and only incidentally for machines to execute" is like saying "engines are for people to watch and only incidentally to move vehicles" - it would lead to engines made of perspex, taking up the size of a room so there's plenty of open spaces to stick your head in for a look around, interrupting the combustion cycles for cleaning and washing cycles, moving at 10 rpm so it's not too fast to see...
This sounds like the rationale behind the APLs.
Of course. To fix an issue on a line, you need to know the context it’s used on and what happens with the line before and after. You also know what calls it or under what context.
> did they necessarily read the lines they left alone?
We can’t say for all of them, but they must have read lines that directly interact with it.
http://art.net/~hopkins/Don/unix-haters/x-windows/motif.html
Including some classic comments like:
/* sets the parent window to 0 to fool Motif into not generating a grab */
And: /*
* This is a horrible function which should not be needed.
* use it to put the resize method back the way the XlwMenu
* class initializer put it. Motif screws with this when
* the XlwMenu class gets instantiated.
*/An entire GUI toolkit was written from scratch simply to replace Motif (Gtk).
This should tell you what you need to know.
>MoOLIT (Motif OPEN LOOK Intrinsics Toolkit) is a graphical user interface library and application programming interface (API) created by Unix System Laboratories in an attempt to create a bridge between the two competing look-and-feels for Unix workstations at the time: OPEN LOOK and OSF Motif.
>The library provided common GUI features such as boxes, menus, lists, and buttons, but allowed users to choose which look and feel they wanted at runtime. It was a short-lived project, as the industry was moving towards Motif as the de facto GUI standard, a trend culminating in the COSE initiative in 1993.
Of course if you just wanted a laugh at the name, you could also use the X Anathema Widgets (Xaw) toolkit, but I think MoOLIT was funnier. I cracked up every time I saw some Sun marketing droid in a tie seriously talking about it.
https://en.wikipedia.org/wiki/MoOLIT
https://en.wikipedia.org/wiki/OLIT
https://en.wikipedia.org/wiki/OPEN_LOOK
https://en.wikipedia.org/wiki/Motif_(software)
https://en.wikipedia.org/wiki/X_Toolkit_Intrinsics
https://en.wikipedia.org/wiki/X_Athena_Widgets
>In a talk for USENIX, X pioneer Jim Gettys remarked that although Athena widgets were "ugly", they were often used in the period of X history that he describes as the "GUI wars", as a safe alternative to the competing Motif and Open Look toolkits.
https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule
>"Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp." -Philip Greenspun's Tenth Rule
The X Toolkit ends up needing to do all of these dynamic-scripting-language-like things, like resolving names and paths, binding events to handlers, calculating expressions, and instantiating objects based on resource data. So if it doesn't already start out with a standardized scripting language to use for that, it has to duplicate all that dynamic almost-but-not-quite-entirely-unlike-half-of-Common-Lisp stuff itself.
Case in point: Motif's infamous UIL (because X resource files weren't half-assed enough).
https://www.donhopkins.com/home/catalog/unix-haters/hpox/uil...
And then when you do get around to plugging that toolkit into some other scripting language (the way WINTERP plugged Motif/Xt into XLisp, or GTK/GObject plugs into Python for that matter), now you have two or more fat bloated complex buggy poorly documented incompatible impedance-mismatched half-assed competing layers of middleware and object models tripping over each other's feet and spraying each other with seltzer bottles like the Three Stooges.
https://www.youtube.com/watch?v=VO9RP4QEZKU
https://news.ycombinator.com/item?id=22610342
>Speaking of the plague, does it support UIL? ;)
>Neils Mayer described WINTERP (XLisp + Motif) as: You might think of such functionality as "client-side NeWS without the postscript imaging model".
http://nielsmayer.com/winterp/
>Don Hopkins wrote to a comp.human-factors discussion about "Info on UIL (User Interface Language)" on January 22, 1993:
https://groups.google.com/d/msg/comp.human-factors/R3wfh90HM...
>Here are some classic messages about UIL. Avoid it like the plague.
[...]
NSAPI:
https://en.wikipedia.org/wiki/Netscape_Server_Application_Pr...
NPAPI:
https://en.wikipedia.org/wiki/NPAPI
FWIW, here's some feedback I wrote up and sent to Netscape about the original version of the Netscape plug-in API (NPAPI), when I worked at Kaleida. This was from around 1995, when JavaScript was called LiveScript, before anything like LiveConnect/XPConnect/NPRuntime existed, when Netscape though Java was the solution to all their problems, and before ActiveX of course (but I warned them about Microsoft's use of OLE in the browser), so plug-ins only had very limited if any interaction with LiveScript and DOM.
ScriptX was a multimedia scripting language, a lot like object oriented Lisp or Python with built-in graphics and multimedia libraries. But unfortunately it was not designed to be an extension language library that could plug into another application like Netscape, the way Python does so well. So I made a "ScriptX Plug-Out" that integrated ScriptX running in another process with a Netscape plug-in via Apple Events.
https://donhopkins.com/home/archive/netscape/Netscape-Plugin...
>I hope NetScape can come up with a plug-in interface that is good enough that they can implement their own navigator components with it (like the mail reader, outliner, progressive jpeg viewer, etc). The only way it's going to go anywhere is if they work closely with developers, and use the plug-in interface for non-trivial things themselves. Microsoft already has a VRML plug-in for their navigator, so presumably they have a plug-in interface, and from what I've seen on their web site, it may not be "good enough", but it's probably going to do a lot more that you can do with NetScape right now, since they're exposing a lot of their navigator's functionality through OLE. They seem to understand that there's a much bigger picture, and that the problems aren't trivial. Java isn't going to magically solve all those problems, folks.
I used mod_perl extensively in the summer (May-Aug) of 1996; it was the only way I found to embed perl directly into the server process, at the time.
We had a clunky CGI script that crawled the filesystem on request, no doubt a security hole waiting to happen, but Netscape made it worse. (It's possible that other web servers did, or even still do, but I really hope not.)
Anything that the script sent to standard error, which could reveal things like filesystem paths and other sensitive data, was not only logged, but also fed back to the web client as part of the response.
Luckily, because stderr wasn't buffered, in our case it was fed to the browser before any headers, causing the web client to throw up a server error instead of displaying the error messages themselves.
So yes, maybe some "Netscape" is in there still. Just not Netscape 4, the good one we think about when remembering Navigator.
You will immediately see a lot of NS_ (or ns) prefixed names in the source code. Without knowing about Firefox's history I thought like that Firefox has history with Apple (NeXTSTEP). But no, NS_ are the legacy from Netscape.
It was fun to get to know its history from the source code when I was contributing it :)
[1]: https://dxr.mozilla.org/mozilla-central/source/dom/media/Med...
I used to call the browser Netscapé, which rhymes with Nescafé, back in the 90's when it was the world's leading distributer of Java.
https://en.wikipedia.org/wiki/Nescaf%C3%A9
>Nescafé is a brand of coffee made by Nestlé. It comes in many different forms. The name is a portmanteau of the words "Nestlé" and "café". Nestlé first introduced their flagship coffee brand in Switzerland on 1 April 1938.
The style around naming, spacing, etc was very different, and not always cleaned up, so it was easy to tell what was old.
To this day, I remember the excitement from the buildup to the first open source release of "Mozilla (Netscape 4.something)"... and then downloading the code and seeing this horrible complexity. And suddenly understanding why Netscape was so dysfunctional.
https://news.ycombinator.com/item?id=20266627
>It certainly had a lot of problems and limitations, and OLE/ActiveX/DCOM/DirectX/etc took it way too far, then Mozilla XP/COM cloned it and also took it way too far (and then back again: see "decomification" and "decomtamination"), but it really was a pretty elegant and successful solution to the problems it was designed to address at the time.
https://wiki.mozilla.org/Gecko:DeCOMtamination
http://taras.glek.net/blog/categories/decomtamination/
https://blog.mozilla.org/tglek/category/decomtamination/
https://news.ycombinator.com/item?id=12968830
>Mozilla underwent a process of "DeCOMification", because they went too far with XP/COM, and wanted to dial it way back.
https://bugzilla.mozilla.org/buglist.cgi?query_format=specif...
>Can someone link to a synopsis describing what "COM" is? It's hard to search for. (e.g. microsoft com visual studio)
https://news.ycombinator.com/item?id=12975257
>Glad you asked! One of my favorite topics. ;)
[...]
>And Mozilla came up with XP/COM [14], for implementing components in Mozilla/Firefox/XULRunner/etc, enabling programmers to implement and consume XP/COM components in C++ or JavaScript. Of course it has its own IDL and tooling, and suffers from many of the same problems that COM did.
>Mozilla didn't go nearly as far down the rabbit hole as Microsoft did, and later backtracked in their valiant "deCOMification" aka "deCOMtamination" and "outparamdelling" efforts [15].
An example of outparamdelling:
Is the shame of this the reason Marc A doesn't want to talk about Netscape?
It wouldn't have been "rocket science": Python already existed at the time, with an excellent extension and embedding API, and was well known and widely used that way. TCL was another contender that also had an excellent native code integration API, although it was a much worse language than Python.
But there were politics around TCL, because Sun had hired John Oosterhout, its author, and arrogantly unilaterally announced that they were making TCL the web's official scripting language by administrative fiat, leading to the great "TCL War" kicked off by RMS's infamous but insightful "Why you should not use TCL" posting. Then Sun dropped TCL like a hot potato, and started pushing Java obsessively instead.
https://vanderburg.org/old_pages/Tcl/war/0000.html
https://news.ycombinator.com/item?id=17059077
And of course NetScape also went a long way down the misguided road of Java applets, and worse yet "100% Pure Java TM", by announcing they were going to rewrite the entire browser in Java. In which case, instead of cloning Microsoft COM and using XP/COM as a component extension hub, they would have ended up being stuck with Java's awful "JRI" native code integration API, which was eventually superseded by the also-awful "JNI".
The problem with using Java as an integration hub was that Sun was ideologically opposed to integrating Java with any other languages, because they thought everyone should throw away all their own code and rewrite everything in "100% Pure Java TM" (linguistic supremacy instead of linguistic inclusivity).
To encourage or even allow developers to use some other language than Java would be to admit that Java wasn't perfect for everything and superior to every other language, which Sun couldn't bring themselves to do after launching their "100% Java TM" campaign. So they tried to shame and refused to support anyone who wanted to integrate Java with native code, instead of rewriting everything in Java from scratch, like Netscape tried to do but eventually gave up on.
So Sun downplayed and strangled JRI in the crib, and they also didn't give a shit about its successor JNI either, and let it wither on the vine, because they refused to recognize the importance of using any other language than Java, once they got obsessed with their "100% Pure Java TM" craze.
NetScape suffered from the Java/JRI albatross around their neck for a long time:
https://en.wikipedia.org/wiki/NPAPI#LiveConnect
>The disadvantage of LiveConnect is that it is heavily tied to the version of Java embedded within the Netscape browser. This prevented the browser from using other Java runtimes, and added bloat to the browser download size since it required Java to script plugins. Additionally, LiveConnect is tricky to program: The developer has to define a Java class for the plugin, run it through a specialized Java header compiler and implement the native methods. Handling strings, exceptions and other Java objects from C++ is non-obvious. In addition, LiveConnect uses an earlier and now obsolete application programming interface (API) for invoking native C++ calls from Java, called JRI. The JRI technology has long since been supplanted by JNI.
I wonder why NetScape didn't choose Python in the first place, instead of inventing their own language or using TCL or Java. Lua would have also been a great choice, but it wasn't nearly as far along, mature, widely supported, and popular as Python was at the time. It was probably because they just wanted to invent their own language, and not use something off-the-shelf that was already widely supported and just worked: NIH.
Here's some other stuff I wrote about the development of component technologies and Java during that time:
https://news.ycombinator.com/item?id=19837817
>Wow, a blast from the past! 1996, what a year that was.
>Sun was freaking out about Microsoft, and announced Java Beans as their vaporware "alternative" to ActiveX. JavaScript had just come onto the scene, then Netscape announced they were going to reimplement Navigator in Java, so they dove into the deep end and came up with IFC, which designed by NeXTStep programmers. A bunch of the original Java team left Sun and formed Marima, and developed the Castanet network push distribution system, and the Bongo user interface editor (like HyperCard for Java, calling the Java compiler incrementally to support dynamic script editing).
https://donhopkins.com/home/interval/pluggers/
https://donhopkins.com/home/interval/pluggers/requirements.h...
https://donhopkins.com/home/interval/pluggers/navigator.html
https://donhopkins.com/home/interval/pluggers/java.html
I'd love to hear from somebody who was at Netscape at the time, about what they thought of Python, whether or not they fairly considered it, and why they didn't end up using it instead of rolling their own language from scratch. And also what Netscape's view of the great "TCL War" was from their perspective, and why they chose to collude with Sun's Java Manifest Destiny for so long, but earlier they didn't play along with Sun's announcement that TCL would be the world's official web scripting language. Besides the obvious fact that Java was much better than TCL, yet TCL for all its flaws and limitations at the time was certainly better than initial version of JavaScript (LiveScript), which was awful.
Is there any code in Source that comes from idtech 2?
// Assertion: Now we know the name of the current page
Is this style frowned upon? I've always thought it's a very clear way of communicating. There's a reason many maths papers are written like this. Do my co-workers think my comments are silly? :(First, it just says what the three simple lines of code above did. Comments should rather focus on the "why" to provide information which the code cannot give.
Second, assertions should be code (or somehow machine readable).
e: Edit url to point to rust status in Firefox