question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Change Object.assign polyfill to NOT walk entire prototype chain and to NOT force ideologies

See original GitHub issue

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Environment: OS: Linux 4.10.0-35-generic #39-Ubuntu SMP Wed Sep 13 07:46:59 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux Node: 8.1.3 npm: 5.3.0

Packages: (wanted => installed) react-native: 0.49.3 => 0.49.3 react: 16.0.0-beta.5 => 16.0.0-beta.5

Target Platform: Android (7)

Steps to Reproduce

(Write your steps here:)

  1. Create an object with keys var a = { test: 'derp' }
  2. Create an object with a as the prototype var b = Object.create(a)
  3. Attempt to assign b to a new object var c = Object.assign({}, b)

Expected Behavior

react-native shouldn’t slowly walk the entire prototype chain or force ideologies

Actual Behavior

react-native DOES slowly walk the entire prototype chain AND force ideologies

Reproducible Demo

https://github.com/facebook/react-native/blob/master/Libraries/polyfills/Object.es6.js

Your Polyfill for Object.assign (Object.es6.js) is completely backwards, slow, and forcing an ideology. You are DELIBERATELY walking and copying the entire prototype chain, which is slow, and often not desired. The SUPER INSANE part? You are telling me how to live my life, and throwing an exception if there IS an enumerable property in the prototype chain. Forcing people to do things YOUR way is the wrong way. Please update the polyfill to 1) NOT walk the entire chain, 2) NOT tell me how to code.

By the way, I ran into this simply inheriting from EventEmitter, which is SUPER COMMON by the way.

I am upset that Facebook has written controlling polyfills forcing ideologies and telling me how to live my life. Please stay off my lawn, stop telling me how to code, and stop doing things the slow way just to tell other people how to do things

// We don't currently support accessors nor proxies. Therefore this
    // copy cannot throw. If we ever supported this then we must handle
    // exceptions and side-effects.
    
    // No SANE person would ever copy an object with `key in obj`
    // please use `Object.keys(obj)` instead, which is much faster,
    // and doesn't involve forced ideologies
    for (var key in nextSource) {
      if (false) { // <--- Add false here... because you don't need to tell me the proper way to code
        var hasOwnProperty = Object.prototype.hasOwnProperty;
        if (!hasOwnProperty.call(nextSource, key)) {
          throw new TypeError(
            'One of the sources for assign has an enumerable key on the ' +
            'prototype chain. Are you trying to assign a prototype property? ' +
            'We don\'t allow it, as this is an edge case that we do not support. ' +
            'This error is a performance optimization and not spec compliant.'
          );
        }
      }
      target[key] = nextSource[key];
    }

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
th317erdcommented, Oct 31, 2017

@TheSavior “Also, since all of our other polyfills appear to have that check already, it doesn’t seem like those concerns would be unique to this file. For that reason, it seems reasonable to add that separately, earlier.” I agree it certainly makes sense to add that change to the polyfill (instanceof Function check), however being as the polyfill is currently not to standard I am concerned with switching between platforms that implement the standard, and platforms where the non-standard polyfill will be used. The deviation of the polyfill will potentially cause the app to crash where the polyfill is used (as it does now).

I will write unit tests when I have some free time, which might not be for a few days

1reaction
TheSaviorcommented, Oct 31, 2017

Please note that I want to help make this satisfy your concerns.

The PR is quite difficult to review and merge confidently, this is true polyfills in general. The following explains why.

I have no context on the initial intent of this code, but I assume that the people who wrote it were smart engineers with more context on the situations it needs to support than I do currently.

The fact that there is a specific warning about the hasOwnProperty checks and that the polyfill is not spec-compliant implies that we started with a spec compliant polyfill and needed to change it to this approach instead. I could also imagine this being an optimization for Prepack, but based on the history of this file not being recent, that likely isn’t the case.

// WARNING: This is an optimized version that fails on hasOwnProperty checks
// and non objects. It's not spec-compliant. It's a perf optimization.
// This is only needed for iOS 8 and current Android JSC.

// We don't currently support accessors nor proxies. Therefore this
// copy cannot throw. If we ever supported this then we must handle
// exceptions and side-effects.

It feels like it would be fairly bad form for us to ignore these warnings without better understanding the situations they were meant to solve. Unfortunately, these warnings were not codeified via tests.

Also unfortunately, I couldn’t trace the history of this file back to where it was added or modified to be able to see if the original authors remember anything about the reasons. The only people I could find related to that history were @mjesun and @davidaurelio. Perhaps they have some context.

In the mean time, while we are trying to get more context before figuring out how to move forward with those changes, I’d be happy to accept a PR that just contains the additional existence check that you added.

if (!(Object.assign instanceof Function)) {

This check exists on the other polyfills and I can’t imagine why we’d want to override an existing Object.assign function.

FWIW, I also have a hard time fully understanding the problems you are trying to address. From you initial post it seems like the main complaint you have is:

shouldn’t slowly walk the entire prototype chain or force ideologies

When trying to deconstruct that complaint and understand the specifics, I can understand the first half being performance related. For “force ideologies”, I’m not exactly sure what you mean by that. Is that specifically about us overriding existing Object.assign functions which would be satisfied by the addition of the existence check above? Or are there other “ideologies” the code is forcing? Can you help understand the specifics of this?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Object.assign() - JavaScript - MDN Web Docs
The Object.assign() method copies all enumerable own properties from one or more source objects to a target object.
Read more >
Object spread vs. Object.assign - javascript - Stack Overflow
assign that doesn't seem to be mentioned in the current answers is that the spread operator will not copy the the source object's...
Read more >
Opinions : Do you use es6 classes : r/javascript - Reddit
Kyle Simpson strongly reasons against using ES6 classes as they simply ''mimic'' prototype inheritance, in favor of object composition.
Read more >
Part 1: Prototypes vs. classes - Cygni
A prototype, on the other hand, is not related to types at all, but is simply an object instance. In fact, this statement...
Read more >
14. New OOP features besides classes - Exploring JS
In contrast to how this classic operation works, Object.assign() only ... This is how you would copy all own properties (not just enumerable...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found