On Mar 15, 2009, at 23:30 , Brendan Eich wrote:

But here is the uneval/toSource equivalent, inline, using the same notation (single quotes around string results, although all results are string results, in a one-line comment starting //-> after the repr call):

Thank you. Added it here http://gist.github.com/81118 for easy comparison (and syntax coloring :P).

Also, removed the single quotes on the Python examples[1] and cleaned up the Ruby examples[2] to use p(obj) instead of obj.inspect.

Since undefined was added as a global property after ES1, when there was too much risk of a web page defining a same-named global, it's read/write and deletable, so uneval(undefined) produces '(void 0)'.

Note also that unlike toString, the function toSource results squish code onto one line. This can get ugly, but it was considered convenient for short functions. Perhaps it was a mistake to do this, though.

Sharp variables handle cycles and join points but they are overkill for an inspect-like utility, and they require aggressive memoization to avoid divergence calling non-idempotent getters or otherwise dealing with object graphs that modify themselves (via SpiderMonkey's internal metaprogramming hooks) as they are crawled to find the join points.

Comments welcome.

From an end-user's perspective, the main difference between SpiderMonkey's uneval and Python's repr or Ruby's Object#inspect [3] is that the former looks like a meta-programming tool while both Python's and Ruby's implementation are just debugging helpers.

I would argue that fulfilling both needs with the same API is not a good thing. For debugging, the most useful representation of an object is often domain- or even context-specific and that is not necessarily it's source code.

I have little knowledge of Python's repr implementation but can explain briefly how ruby's Object#inspect [4] works.

In Ruby, every object (and in Ruby, nil is an object too) has an inspect method, which is either defined in the object's class or inherited from Object#inspect. When not overridden Object#inspect delegates to the object's to_s [5] method.

Object#to_s returns the object‘s class and an encoding of the object's id and is overridden for most common types (String, Number, Array, etc.).

Printing the object's debug representation to the program's standard output is then as simple as calling Kernel#p [6] with the object passed as it's first argument:

    p(123) # or p 123, brackets are optional
    > 123

Since inspect is an instance method, it allows classes to define their own debugging representation. Thus:

    class Foo
      def inspect
        return 'I am an instance of Foo'
      end
    end

    p(Foo.new)
    > I am an instance of Foo

Here's a pseudo-implementation in ES 3 (please bear with the obvious issues such as breaking for...in loops, etc.). Obviously, naming the EcmaScript counterpart of Ruby's Object#inspect Object.prototype.inspect wouldn't fit with the rest of the EcmaScript API, I would suggest something like Object.prototype.toDebugString().

    Object.prototype.toDebugString = function() {
      return this.toString();
    };

    function p(obj) {
      if (typeof obj === 'undefined') {
        return 'undefined';
      }
      if (obj === null) {
        return 'null';
      }
      return obj.toDebugString();
    }

A program could then specify custom debugging representations like so:

    function Foo() {}
    Foo.prototype.toDebugString = function() {
      return 'I am an instance of Foo';
    }

    p(new Foo());
    //-> I am an instance of Foo

Native objects would need to define their own prototype.toDebugString methods.

We've been using something similar in Prototype for a long time to great effect (although we do not extend Object.prototype).

In summary:

- uneval and toDebugString serve two different purposes and should be treated separately, and - Object.prototype.toDebugString could be roughly mapped to Ruby's Object#inspect implementation.

This would allow for easy customization of debugging output (which answers concerns expressed about domain-specificity of serialization) and avoids complex implementation and specification issues related to returning an "evaluatable" source representation.

Best,

Tobie

--

[1] Python example: http://gist.github.com/78424
[2] Ruby example: http://gist.github.com/78355
[3] in Ruby, the notation Foo#bar means the instance method 'bar' of class 'Foo'.
[4] Object#inspect doc: http://www.ruby-doc.org/core/classes/Object.html#M000358
[5] Object#to_s doc: http://www.ruby-doc.org/core/classes/Object.html#M000357
[6] Kernel#p doc: http://www.ruby-doc.org/core/classes/Kernel.html#M006002

_______________________________________________
Es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to