Distributive-Network / PythonMonkey

A Mozilla SpiderMonkey JavaScript engine embedded into the Python VM, using the Python engine to provide the JS host environment.
https://pythonmonkey.io
Other
618 stars 33 forks source link

Add `.new` Method to JavaScript Clases #171

Open wiwichips opened 9 months ago

wiwichips commented 9 months ago

Describe your feature request here.

Class.new

Feature Request: add a new static method to classes exposed to Python to instantiate JavaScript classes. Code example:

import pythonmonkey as pm
JsDateClass = pm.Date

myDate = JsDateClass.new(0) # in JS this would look like: myDate = new JsDateClass(0);

Relevant Context

Unlike JavaScript, Python doesn't use the new keyword (or anything like it) for instantiating classes. For example:

class SomeClass:
    pass
obj = SomeClass()

However, JavaScript "classes" may require the new keyword to properly setup the object. ES6 classes will throw an error if not instantiated with new.

So we needed to provide a way for Python to instantiate JavaScript classes and chose to add a new function to the PythonMonkey api which returns a function wrapper for the constructor function which can be used to instantiate the class as if it were called with new. See the relevant ticket here: https://github.com/Distributive-Network/PythonMonkey/issues/144

This topic was debated in the TC39 forums here: https://es.discourse.group/t/function-prototype-new/1772 ; however, the community does not appear to be very unified on this subject. @WebReflection suggested adding Class.new to the JS spec

Pyodide uses Class.new to solve this, refer to the Pyodide documentation here: https://pyodide.org/en/stable/usage/api/python-api/ffi.html#pyodide.ffi.JsProxy.new

Code example

import pythonmonkey as pm

myDate = pm.Date.new(0)
WebReflection commented 9 months ago

FWIWI MicroPython in WASM also supports this syntax and it's great to see alignment around this tiny, yet huge, detail.

Thank You!

wesgarland commented 9 months ago

@WebReflection Do you have any insight as to the implementation details in other platforms? A couple of ways to do this pop in my mind right away:

  1. add non-enumerable Function.prototype.new in JS-land
  2. intercept property access to new on JSFunction * from Python

I'm sort of leaning toward #1 due to simplicity, but it would have observable side effects in JS.

wiwichips commented 9 months ago

Hi @zanxueyan, sorry to hear you're having issues. Let's discuss this in the other thread: https://github.com/Distributive-Network/PythonMonkey/issues/170