Skip to content

Reflection Enhancement #675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
danielribeiro opened this issue Sep 9, 2010 · 15 comments
Closed

Reflection Enhancement #675

danielribeiro opened this issue Sep 9, 2010 · 15 comments

Comments

@danielribeiro
Copy link

It would be nice to have class name from objects, created from classes defined by class keyword. This would be possible to retrieve from constructor property, provided the classes were not anonymous functions.

Edit: It would also be very nice to have pythons' locals (akin to Ruby's local_variables) and Ruby's method instrospection mechanisms.

@jashkenas
Copy link
Owner

It would be nice, but Internet Explorer's implementation of named functions breaks scoping and leaks memory.

@danielribeiro
Copy link
Author

Really? Well, using named functions was just one way. Setting the classname as a propety of the class, and giving something classname as a function on the prototype of all classes would probably work on all browsers, while still giving the capability of doing x.getClass().name().

@jashkenas
Copy link
Owner

Using regular JavaScript, you can do:

object instanceof Klass

And also:

object.constructor

... to get a reference to the class.

does that not work for you?

@danielribeiro
Copy link
Author

Consider this example
class Animal
constructor: (@name) ->

    an =  new Animal()
    alert Animal.constructor

On firefox 3.6 and Chrome 5, I get:
function Function() { [native code] }

So, yeah, it doesn't work. Not to mention getting the reference to the class itself (with the name, it would be possible to easily get it from the global scope, but having less nice things make a language less nice).

@jashkenas
Copy link
Owner

I'm not saying that it contains the name of the class -- just that the name of the class is often used to get a handle on it -- and you can get a handle on it directly.

Do you have a real-world piece of JS that depends on the class name, as an example that you can share with us?

@danielribeiro
Copy link
Author

Class names are mostly useful for debugging names. In all oo languages really. Either directly, or indirectly as default toString implementation or stacktrace.

On our project, that is still using JS.Class, and from these posts will still use it even if we move to Coffee-script, we set an atribute for all objects and classes, with the following code:
// Debug Function that creates instance variabel _class with the class name for all
// JS.classes
function createDisplayName(target) {
if (!target) {
target = window
}
for (var name in target) {
try {
var clas = target[name]
if (clas && clas.includes && clas.includes(JS.Kernel) &&
clas.displayName.length == 0) {
clas.define('_class', name)
clas.extend({
displayName: name
})
}
} catch (exception) {
//Yeah, some objects from window can't be accessed
}
}
}

It is important to stress that JS.Class can set displayName of all classes defined within a module with a name. Module in JS are not nearly as convenient to write as in ruby, and we find that displayName alone is too far for firebug, this is why we set the attribute _class on all objects.

This is mostly dev code. But development is not only easier with it, it is possible. Javascript has historically lacked several facilities, but thankfully this is starting to change, not with one project alone, with all of them together.

@jashkenas
Copy link
Owner

Then you'll be glad to hear that modern JavaScript debuggers are starting to use names from variables, and not just named functions. For example, given this CoffeeScript that throws an exception through three classes:

class One
  one: -> (new Two).two()

class Two
  two: -> (new Three).three()

class Three
  three: -> throw new Error('three called')

(new One).one()

Chrome logs this stacktrace:

stacktrace

@danielribeiro
Copy link
Author

That is great news. Which chrome version? If it works even on debug mode (which is really important to notice the actual name of the current object's class name, as the line of code is not enough to determine for methods invoked from subclasses), this whole enhancement can be ignored. At least on such browsers.

@jashkenas
Copy link
Owner

I'm using the stable build of Mac Chrome, if you want to investigate further ... number 6.0.472.55.

@danielribeiro
Copy link
Author

Well, we are on Ubuntu, but it should work the same. About classes, as it stands, we will probably stick to JS.Class. It is extra nice on coffeescript. We also remembered a valid reason for class names on runtime, besides debugging: automatic population of a dsl. For instance, by just creating a class called HBox, we can write ui.hbox(ui.list(1, 2, 3, 4)) instead of new HBox(new List(1, 2, 3, 4)) (it is the same in coffescript and javascript).

Since the dsl is extensible, it is required to have the class name. Since we plan to open source this in the next months, we can't really require people to automatically define the class names. With the callbacks from JS.Class it suffices people to include a module or extend a class, and we walk through all the global namespace looking for its name (lazily, so that we don't do this more than once). Or we do a minor fork of coffeescript to create a JS.Class with the class keyword, and we set the name when we do it. It might not pay off, as we will have to have both ways, as we will support JS clients as well.

Thanks for all info/patience/attention.

@danielribeiro
Copy link
Author

Well, now that we decided to give coffescript classes a go, instead of just using JS.Class', one trouble is clear: debugging the coffescript compiled version is worse, as there is no mark that global attributes are classes. This prevents us from setting their true name, which is horrible when debugging even shallow hierarquies (ok, I know this method is on class A, but i don't know the instances's actual subclass).

We will look into the compiler pre-processor plugins to enable this. Of course, we will already setup the displayName as well, making the iteration process unnecessary.

Edit: Well, the iteration mechanism actually might work. Just looking for functions with a non-empty prototype instead of clas && clas.includes && clas.includes(JS.Kernel). No need to tamper with ClassNode (line 717) on http://github.com/jashkenas/coffee-script/blob/master/src/nodes.coffee#L717

@danielribeiro
Copy link
Author

About named functions having memory leaks, I wonder, if this is true, why prototype still uses them (a quick search on function $A on http://prototypejs.org/assets/2009/8/31/prototype.js will show this)...

@danielribeiro
Copy link
Author

Edited the original to add some more suggestions.

@jashkenas
Copy link
Owner

CoffeeScript classes now have names on the constructor, which can be accessed like:

@constructor.name

or

klass.name

Closing the ticket.

@danielribeiro
Copy link
Author

This is really appreciated! And I suspect not just by me. Thanks.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants