ClojureScript

Printing an Object with a null prototype throws an error

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Completed
  • Affects Version/s: 1.9.293
  • Fix Version/s: 1.9.854
  • Component/s: None
  • Labels:
    None
  • Approval:
    Accepted

Description

ClojureScript doesn't handle printing objects with a null prototype:

(prn (.create js/Object nil)) ;;throws Uncaught TypeError: Cannot read property 'cljs$lang$ctorStr' of undefined
(str (.create js/Object nil)) ;;throws Uncaught TypeError: Cannot convert object to primitive value

For the first case, it looks like pr-writer-impl's last case needs a separate check for a nil object constructor. I've not yet investigated the second case.

Activity

Hide
David Nolen added a comment -

Is this a common JS pattern?

Show
David Nolen added a comment - Is this a common JS pattern?
Hide
Jonathan Boston added a comment -

I assume it isn't since I only recently ran into it. But PDFjs uses it regularly, which is where the problem came to light.

It appears to be used for objects that are strictly for wrapping other data. Perhaps it's a performance optimization?

I'm away from a computer for the next few days, but can provide links/more info then as necessary.

Show
Jonathan Boston added a comment - I assume it isn't since I only recently ran into it. But PDFjs uses it regularly, which is where the problem came to light. It appears to be used for objects that are strictly for wrapping other data. Perhaps it's a performance optimization? I'm away from a computer for the next few days, but can provide links/more info then as necessary.
Hide
David Nolen added a comment -

I'm happy to see a fix for the first case and I'd like hear more information about the second one.

Show
David Nolen added a comment - I'm happy to see a fix for the first case and I'd like hear more information about the second one.
Hide
Jonathan Boston added a comment -

So the second case is interesting and I'm not sure of the fix implications. The following plain javascript highlights the problem:

Object.create(null) + "";
"" + Object.create(null);
[Object.create(null)].join(""); //str implementation uses this

//all three calls give the following error
Uncaught TypeError: Cannot convert object to primitive value

The str implementation passes the value through to array.join, so we'd need to check for null prototypes for every str call.

Adding an extra conditional to printing out to the console seems harmless enough, but adding an extra conditional for every str call seems like it might not be worth it.

I'm happy to do a fix for whatever you suggest.

Show
Jonathan Boston added a comment - So the second case is interesting and I'm not sure of the fix implications. The following plain javascript highlights the problem:
Object.create(null) + "";
"" + Object.create(null);
[Object.create(null)].join(""); //str implementation uses this

//all three calls give the following error
Uncaught TypeError: Cannot convert object to primitive value
The str implementation passes the value through to array.join, so we'd need to check for null prototypes for every str call. Adding an extra conditional to printing out to the console seems harmless enough, but adding an extra conditional for every str call seems like it might not be worth it. I'm happy to do a fix for whatever you suggest.
Hide
Kurt Harriger added a comment -

I just ran into this issue on a project that uses the prosemirror editor.
I finding this issue I managed to tracked it down to this line in their source:
https://github.com/ProseMirror/prosemirror-model/blob/5a81c740526e8a6a726fe8468a5b9244e5605ec6/src/schema.js#L13

Apparently some javascript developers use this pattern to avoid hasOwnProperty:
http://adripofjavascript.com/blog/drips/creating-objects-without-prototypes.html

Show
Kurt Harriger added a comment - I just ran into this issue on a project that uses the prosemirror editor. I finding this issue I managed to tracked it down to this line in their source: https://github.com/ProseMirror/prosemirror-model/blob/5a81c740526e8a6a726fe8468a5b9244e5605ec6/src/schema.js#L13 Apparently some javascript developers use this pattern to avoid hasOwnProperty: http://adripofjavascript.com/blog/drips/creating-objects-without-prototypes.html
Hide
Kurt Harriger added a comment -

in addition to prn and str may also need to update js->clj:

cljs.user> (def b (doall (js->clj (.create js/Object nil))))
org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object. (rhino.clj#41)

Show
Kurt Harriger added a comment - in addition to prn and str may also need to update js->clj: cljs.user> (def b (doall (js->clj (.create js/Object nil)))) org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object. (rhino.clj#41)
Hide
David Nolen added a comment -

Kurt please file a different issue for js->clj. Thanks.

Show
David Nolen added a comment - Kurt please file a different issue for js->clj. Thanks.
Hide
David Nolen added a comment -

I looked into this and I have a patch coming. I think we can handle the pr-str, prn, etc. cases but I don't think we need to handle str. str assumes .toString works, but this won't work in JS either.

var x = Object.create(null);
x.toString() // error
x + "" // error
Show
David Nolen added a comment - I looked into this and I have a patch coming. I think we can handle the pr-str, prn, etc. cases but I don't think we need to handle str. str assumes .toString works, but this won't work in JS either.
var x = Object.create(null);
x.toString() // error
x + "" // error

People

Vote (0)
Watch (4)

Dates

  • Created:
    Updated:
    Resolved: