Hacker News new | past | comments | ask | show | jobs | submit login
Is there any code in Firefox (as of 2020) that comes from Netscape Navigator? (stackexchange.com)
197 points by aaronbrethorst 67 days ago | hide | past | web | favorite | 98 comments



> In fact, if my calculations are correct, out of 65,745 lines in the original nsprpub, 36,046 are present unchanged in the current version of nsprpub, i.e. 54.8%.

This supports the statement that code is read many times more than written. So think about that when trying to be clever.


Clear is better than clever. Unfortunately there is no agreement on what is clear and what is clever. I think arrow functions in JS are more clever than clear, but I’ve had people tell me that my opinion is mistaken.


There are also people who think that ternary operators and switch statements are too clever. I tend to prefer concise clarity over unnecessary boilerplate and duplication. But that's the issue, opinions differ on what's clear versus clever. Someone who prefers Go will give you a different answer than a Lisper.


> There are also people who think that ternary operators and switch statements are too 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.


the problem with arrow functions is that they do seem syntactically unlike the rest of the language, like they were grafted on, which makes them naturally unclear. However they solve some very real problems with the language that the cleverness outweighs the clearness.


Do you mean the arrow function syntax or the concept of anonymous functions (lambdas) in general? As someone well-versed in Lisp and new to JS I find the arrow syntax quite nice.


I agree. I like an old fashioned loop with an obvious invariant. But some people think functional programming with arrow notion is so much better. Go figure.


Arrow functions don’t have ‘this’ bound in them, which makes them safer.

Of course some libraries like cheerio require a callback with an available ‘this’ bound into it.


The ability to assert the most about what the code cand and cannot do, trumps both, which is why the use of strongly typed (check, even dependently typed) functional languages should be more widespread.


is this because you think having one dynamically scoped variable is clearer than having 0?


I think arrow functions are less clear because they are always anonymous functions. Anonymous functions complicate stack traces and performance profiles.


They can’t be named in the same standalone way that non-arrow function expressions can, but they do acquire names in some positions that get used in stack traces and profiles.

  > ({ 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.



Your parent specifically talked about giving it a name in thte stack frame. And assigning an anonymous function to a constant/object and using it through that assignment will cause the stack trace to show a name.


The only way to arbitrarily generate a JavaScript stack trace without an error, in both modern browsers and Node, is the following code sample. In order to prove the output of a stack trace you need logic that actually produces a stack trace.

   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:81

Node: '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.


This seems like a very verbose retread.

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.


Guido wrote a fascinating article about why Python lambdas are expressions and not functions, so if you want multiple statements, you have to def a function and refer to it by name.

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.

[...]


There is cognitive load associated with remembering a simple function that is only used once, versus seeing it is usage. Arrow functions can be effectively self documenting.


What's hard to document is why there is any need for non-arrow functions.

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.


> Anonymous functions complicate stack traces and performance profiles.

It depends. Often you can optimize them out.


Doesn't that just complicate things even more?


It always struck me about JavaScript, that if you were going to choose one variable and one variable only to be dynamically scoped (for whatever strange reason), "this" would be the absolute worst one to choose that you possibly could, an automatic nuclear foot-gun that would trip you up every time. If you ever wanted a function to lexically close over a variable, but could choose only one, "this" would be it!

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!


‘this’ is not in any sense dynamically scoped. It's just a function parameter, assigned implicitly based on the context of the call.


If that's a fact, then please tweet to Brendan Eich that he was wrong when he referred to "dynamic this binding" as the rationale for adding fat arrow functions to JavaScript in his fat arrow proposal, and take your argument up with him, not me:

>"dynamic this binding is an oft-fired footgun" -Brendan Eich

https://tc39wiki.calculist.org/es6/arrow-functions/


I wrote dynamic binding, that's not the same as dynamic scope.


Do you mean you wouldn’t have named it “this”? Because if `this` weren’t set by the means of calling in ES5 and earlier, it would have no point at all.


It doesn't matter what it's named. It matters how it's passed. Python, Common Lisp CLOS, ScriptX, even NeWS's object oriented PostScript, all pass "self" as a first explicit parameter.

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.


> 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, and the only way to change it is indirectly through method applications with ".", or by using call and apply. So "this" is not just a normal parameter like all the rest.

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.


And ES5 strict mode was retroactively designed in 2008, in a way that had to maintain backwards compatibility with the mistakes of 1997, 11 years earlier. By then the mistake was already irreversibly baked deeply into the language.

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.


I don’t think it’s a mistake. I think it’s a sensible design choice (after strict mode disconnected it from the actual misfeature that is primitive wrappers).

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.


If "this" wasn't a mistake and a loaded footgun, then why did Brendan Eich himself literally say that "dynamic this binding is an oft-fired footgun" in the "Rationale" section of his original fat "Arrow Functions" proposal?

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 has nothing to do with dynamic binding. "this" has lexical scope just like regular parameters. I agree 'this' is confusing, but you are making it sound more mysterious than it is. It is just some syntactic sugar around an implicit first parameter.


Nope. "this" is formally defined as a keyword in the JavaScript syntax, not a variable, not a property name, not an identifier, and not syntactic sugar, since there is no source level transformation you can make that behaves the same (like with C++, the way CFront translated "this" into an actual first parameter). JavaScript's "this" is magic, that's why it has to be a keyword, not a variable.

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'


When people say it behaves like an implicit first parameter, they’re not claiming it literally is a parameter/variable. Of course it’s a keyword. Of course you can’t assign to it. You’re writing long rebuttals to made up arguments.

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...


So do you agree with goto8 when he says ""this" has lexical scope just like regular parameters" and "Nevertheless, scope wise it behaves like an implicit parameter with lexical scope"?

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.


Unfortunately, people voting on StackOverflow are not always correct. If you want the correct answer without guessing, you can check the ECMAScript spec itself:

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.


> So do you agree with [goto11 that] ""this" has lexical scope just like regular parameters" and "Nevertheless, scope wise it behaves like an implicit parameter with lexical 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`.


Nevertheless, scope wise it behaves like an implicit parameter with lexical scope. It just muddies the issue to talk about dynamic scope.


Dude or dudess, "this" absolutely does not behave in any way like it is lexically scoped, in any sense of the term.

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.


Regular JavaScript functions work as if there is an implicit "this" parameter (which gets the value from the left-hand side of the call expression rather than the argument list). Fat-arrow function on the other hand does not change "this", which means the "this" binding inside a fat-arrow function is the one from the containing scope. But in both cases the scope of the "this" binding is lexical.

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++ doesn't have a virtual machine

C++ is designed to compile to an implementation of an abstract virtual machine defined by the standard.


C++ certainly doesn't have a concrete virtual machine in the way JavaScript does, and C++'s abstract virtual machine certainly doesn't expose as many irrelevant implementation details of that virtual machine as JavaScript does. JavaScript's abstractions are much leakier than C++'s.

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.


I've written large js projects without using 'this'. Crisis averted, world saved.


"Eschew flamebait. Don't introduce flamewar topics unless you have something genuinely new to say. Avoid unrelated controversies and generic tangents."

"Please don't use Hacker News for political or ideological battle. That destroys the curiosity this site exists for."


[flagged]


I was not referring to what you said about JavaScript, but rather your inclusion of a unrelated, unnecessary and highly polarizing political tangent.


I'm sorry, I didn't think it was controversial that Trump did that kind of stuff, and it made a perfect metaphor. But even if you disagree about Trump, I think you can still understand the metaphor about JavaScript fat arrow functions. Can you think of a better metaphor?

Edit: I added "(or Obama)" for people who are offended by me pointing out what everyone knows about Trump.


> Can you think of a better metaphor?

One that doesn’t involve politics?


Programming language design IS politics. Especially JavaScript. How do you think it got its name?


Not that kind of politics.


Many of us are trying to escape "Trump Derangement Syndrome" which has become infectious almost everywhere else.


I play a mind game in which the smartest code is the one that looks dumbest and is easiest to understand (of course while still working best).


How do you know anyone has ever read that code? Surely they read the lines they changed - that's where the problems were - did they necessarily read the lines they left alone?

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...


> 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?

This sounds like the rationale behind the APLs.


> How do you know anyone has ever read that code? Surely they read the lines they changed - that's where the problems were

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.


I saved some choice examples of code from the awful X-Windows version of Netscape Navigator, on my Motif Angst Page:

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.
     */


As Motif expertise is now an obsolete skill, I don't think this ages well. Short version: in some places, they don't like how the library works. In others, they are working around library bugs. In all cases, they seem severely pissed off about it, which is probably a bigger issue than Motif.


Most of the anti-Motif comments are by jwz.


I've generally liked his technical rants and writings. These don't really land with me though. Maybe he was frustrated with some deadlines or something.


There is a reason that anybody who dealt with it called it Mogrief.

An entire GUI toolkit was written from scratch simply to replace Motif (Gtk).

This should tell you what you need to know.


It was more to it than Motif being painful, though. Motif was not open, and the open reimplementation (LessTif) was buggy.


Another buggy painful non-open reimplementation of Motif, which arguably had the silliest name of any user interface toolkit in the entire universe, was Sun's and AT&T's (Unix System Laboratories) "MoOLIT", the Motif Open Look Intrinsics Toolkit, that let you switch back and forth between those two different competing looks and feels (both of which sucked in their own ways), and which was based on "OLIT", then Open Look Intrinsics Toolkit, which itself was based on the horrible X Toolkit Intrinsics (Xt), which was the root of all evil.

>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.


I am a tad too young to have encountered it, I was picking up X programming in the wave where motif was heading out. I remember Xt/Xaw which I believe had some commonalities with Motif. Then the first version of gtk I played with was 1.x.


The genius of TCL/Tk, and the reason I believe Tk was so incredibly successful despite the flaws and shortcomings of TCL, is that toolkits like Motif, based on the X Toolkit Intrinsics, that aren't written AROUND an existing extension language, end up getting fucked by Greenspun's Tenth Rule:

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.

[...]


Motif was kind of a running joke back in the early 90s (check the Usenet archive for posts and jokes), just like how JavaScript is today - Everyone was using it, it was in a state of continued development (with a feature creeping tendency), and like other technologies, it has its own limitations. Unsurprisingly, it received a huge number of complaints, its popularity was partially responsible for that. Just like how early Unix had a reputation of unreliability, or how many people complain about JavaScript or web frameworks today. Are they technical milestones? Yes. Is it normal for people to complain about it? Also yes.


Server side, so not in Firefox, but I personally got a lot of mileage out of NSAPI. For the company I worked at, at the time, it was the only way to do something better than old-school, fork a process per request, CGI. We had persistent socket processes handling web requests, in parallel, WAY before things like mod_perl or FastCGI. As I remember, it was there around 1995 or so. Many thanks to any former Netscapers. For comparison mod_perl was 1999 or so. FastCGI was really beta and unknown (as I remember) in late 96.


NSAPI, the server based Netscape Server Application Programming Interface, is not to be confused with NPAPI, the browser based Netscape Plug-in Application Programming Interface. (I only say that because I just confused them, then realized my mistake.)

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.


> For comparison mod_perl was 1999 or so

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.

See also http://apache.perl.org/about/history.html


Ahh. Okay. My memory was off then. Sounds like mod_perl co-existed with NSAPI.


I have far less fond memories of Netscape Web Server.

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.


Maybe my memory, but that feels more like your problem than theirs. NSAPI was fairly well documented, to the point where stderr was your problem to fix, and documented that way.


Not NSAPI, CGI.


It's worth noting that it was Netscape Navigator 6 that this was all based on. As in, the ground-up rewrite of the entire product that ultimately killed the company. You know, the one that was so different to its predecessor that it couldn't render Netscape.com.

So yes, maybe some "Netscape" is in there still. Just not Netscape 4, the good one we think about when remembering Navigator.


Netscape 4 was utter rubbish. There is a reason it was rewritten: it had lost the browser war, because it couldn’t be updated quickly enough to keep up with IE’s rate of adoption of new standard features.


That "stack grows upwards" conditional is a giveaway of ancient code. The only architecture I know still using that regularly is PA-RISC, and it's very rare for people to care about it today.


Searchfox is super handy for spelunking through the Mozilla codebase. For example: https://searchfox.org/mozilla-central/search?q=Netscape+Comm...


Contributed Firefox a little bit two years ago. Here is the file I contributed: [1]

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...


Apple uses a lot of historical legacy NS prefixes too, but in their case it stands for NeXT Step! ;)

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.


Lots of Microsoft Edge (pre chromium) code that stretched back to at least IE4 (along with comments with TODOs for long departed employees)

The style around naming, spacing, etc was very different, and not always cleaned up, so it was easy to tell what was old.


Is Firefox still using using that horrible COM-workalike from Netscape/Mozilla (XPCOM)? This was the thing that immediately turned me off from this codebase back in the late 90s.

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.


There is actually a technical term of art (two actually) for the process of removing XP/COM interfaces from Mozilla: "decomification" and "decomtamination", and another related term "outparamdelling".

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:

https://bugzilla.mozilla.org/show_bug.cgi?id=455943


It took them so much time. I can't even begin to imagine how money it cost them to fix this. 10 years * 500 full times at SV salaries, or something like that? That is one expensive bad architectural decision. Maybe $0.5-1 billion, in the end? Not counting missed opportunities during that whole decade.

Is the shame of this the reason Marc A doesn't want to talk about Netscape?


With 2020 hindsight (literally: it's now the year 2020! ;), I think Netscape should have just gone all-in on JavaScript, forgotten about XP/COM and its ilk, and made JavaScript itself the hub for extension and component integration, by giving it an excellent robust native code integration and extension API like Python has, and plugging things into JavaScript directly, instead of plugging things directly into the web browser itself with XPCOM or NPAPI or ActiveX, and thumb-tacking JavaScript onto the side as an afterthought, like a second-class red-headed bastard stepchild.

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.


Brendan Eich wanted to do Scheme, but then edict came from above that "it has to look like Java" https://thenewstack.io/brendan-eich-on-creating-javascript-i...


Makes me wonder, is there a tool like grammarly [1] for source code? One that checks for large chunks of copied code from other open source projects?

[1] https://www.grammarly.com/plagiarism-checker


I interned at a company called Palamida that did this around 2006. They were eventually acquired by Flexera. One of their competitors was Black Duck Software which was acquired by Synopsys.



Guys from AdaCore working on a new Ada parsing and semantic manipulation library had a small try, fun read : https://blog.adacore.com/a-usable-copy-paste-detector-in-few...


Is there any code in WebKit that comes from khtml?

Is there any code in Source that comes from idtech 2?


For a small personal project [0], it was 14 lines after three years continued in a company.

[0] http://beza1e1.tuxen.de/tipiwiki.html


This was a good read. Question from a naive programmer: the writer mentions 'cute comments' in the codebase, like

    // 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? :(


Comments is a mostly subjective topic. In this case, I have two arguments against the comment.

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).


A lot of the code in libnss (security code) looks quite similar to code that was written in the mid 90s. I don't have archives, but browsing multiple files there is a lot of familiarity there.


Of course, lots of Firefox is Rust now. (edit: I'm saying "lots", not "most")


I don't think this is true? I think Mozilla is interested in using Rust for new code where that makes sense, but the vast majority of Firefox as shipped today is still C++


They're working on porting it. See Oxidation Project: https://wiki.mozilla.org/Oxidation#Rust_Components

e: Edit url to point to rust status in Firefox


Only in specific cases. See the “Recommendations” section in that document.


Nice tangent. Is this why it's market share is falling?


Firefox market share + Firefox Rust usage is mostly stable.




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

Search: