sindresorhus/ponyfill

Ponyfills should *never* use the native API

mathiasbynens opened this issue · 10 comments

How are ponyfills better than polyfills?

[…] This is especially problematic when a polyfill is not fully spec compliant (which in some cases is impossible), as it could cause very hard to debug bugs and inconsistencies.

This is a very good point. However, the ponyfill example that appears below seems to contradict it: it uses the native API when available (Number.isNaN || …), which has exactly the same downside.

Only use the native API in your ponyfill (the Number.isNaN || part) when the spec is stable, to ensure it doesn't have differing behavior depending on the environment.

If consistency is what you’re after, I’d suggest recommending against ever using the native API in ponyfills.

Couldn't this impact the performance quite massively? For instance with the object-assign ponyfill. Not sure though, but I think the ponyfill itself will be much slower then the native method.

I discussed the Number.isNaN || part with Sindre before he released this as it was not present at first. So might be me to blame for that :).

Thanks for opening this issue. I was hoping someone would. I was back and forth on whether to include it or not, but thought I would include it so we could get a discussion on it.

However, the ponyfill example that appears below seems to contradict it: it uses the native API when available (Number.isNaN || …), which has exactly the same downside.

Not entirely. The difference is that it would only influence your code, not all code running.

I agree though, in general you should not do this, but there are some performance sensitive API's where the performance improvement of the native API outweigh the risk, like in the object-assign case.

Not entirely. The difference is that it would only influence your code, not all code running.

Of course, but that’s still “caus[ing] very hard to debug bugs and inconsistencies” as the bug depends on the code path that is taken, which is environment-dependent in this case.

Done. Let me know if the text could be improved: 0ab04b9 Thanks for bringing this up :)

2 late 2 the party, but considerable amount of the current ponyfills do use the native APIs when available. Does this require a major version change for all of them (for potentially being a breaking change)?

@petetnt I don't think it's worth the hassle for users to do a major bump. This is more about new ponyfills.

@sindresorhus fair enough 👍

The new language glosses over the performance implications. I agree with the sentiment, but there is likely a point at which it is reasonable to go the other way (polyfilling a stable API, and native implementations offer significant performance gains).

Maybe the rule should be "don't do it, unless you can demonstrate a significant performance benefit using native". Or some way to communicate that native is an option, but not one that should be chosen lightly.

"don't do it, unless you can demonstrate a significant performance benefit using native"

When consistency with the native implementation cannot be guaranteed, it’s one or the other.

  • If performance is critical, use a polyfill. (A proper polyfill does nothing when a spec-compliant, native implementation is available.)
  • If you want a consistent implementation that works for your code, use a ponyfill (or “shim” as others have been calling it). (A proper ponyfill doesn’t use the native implementation, as per this thread.)

You can’t have your cake and eat it too.

There is a middle-ground. People that need absolute performance could use the native method themselves and fall back to the ponyfill. The ponyfill should never do that though.

I had some text about this that @mathiasbynens convinced me to remove: ab9a673