I'm trying to mix native JS getters and setters with Class.create,
with little success so far. Here's what I tried:
=====8<=====
var MyClass = {};
MyClass.__defineGetter__('test', function() {
alert('inside getter');
return 'foo';
});
MyClass.__defineSetter__('test', function(new_value) {
alert('inside setter');
return new_value;
});
MyClass = Class.create(MyClass);
var foo = new MyClass();
foo.test; // should alert 'inside getter'
foo.test = 'bar'; // should alert 'inside setter'
=====>8=====
Evaluating this code with prototype 1.6.0.2 I only get the 'inside
getter' message alerted, but not the setter one, so getters resist
Class.create but not setters. Is there something wrong I'm doing or
are setters just not supported in prototype?
I'll note that I'm working against Safari on iPhone only so I'm not
worried about compatibility issues while using JS getters and setters.
Thanks for your help,
Antoine
On Jul 2, 2008, at 16:28 , darrin wrote:
> Interesting, first time I've seen this. The alert is actually coming
> out of Class.create call. What about this....
>
> var MyClass = Class.create({
> initialize: function() {
> this.__defineGetter__('test', function() {
> alert('inside getter');
> return 'foo';
> });
>
> this.__defineSetter__('test', function(new_value) {
> alert('inside setter');
> return new_value;
> });
> }
> });
That works fine indeed. Do you have any idea why that is while the
previous snippet did not work?
The reason I ask is because I personally dislike the programming style
where properties are defined inline the object passed as the parameter
to Class.create(), and I prefer to have separate "MyClass.aFunction =
function ()" calls. Do you think there is a way to get getters and
setters to work in this style?
Thanks a lot for your help,
Antoine
On Jul 2, 2008, at 17:01 , Ryan Gahl wrote:
> It probably has something to do with the fact that you are defining
> the getter/setter statically on the class itself, where in the
> second example, you are actually defining them at the instance
> level, which is what you want.
I don't intend to have them defined on the class itself. I define them
on MyClass indeed, but when I do "MyClass = Class.create(MyClass)", I
think that should have copied class members onto the MyClass
prototype, isn't that right?
I guess the issue there is that these special __defineGetter__ and
__defineSetter__ members are not recognized by Class.create() and thus
aren't copied onto the prototype.
Antoine
> Why would Class.create() copy static class members to the prototype?
> That doesn't make any sense. That completely rules out the
> possibility that the developer, you know, wanted them to remain
> static...
As far as I know, that's how Class.create works. See http://prototypejs.org/learn/class-inheritance
and more particularly the Defining class methods section: "There is
no special support for class methods in Prototype 1.6.0. Simply define
them on your existing classes". Then the example shows how class
methods need to be defined _after_ the Class.create() call.
Antoine
> Nowhere on that page does it say that static class methods are
> copied to the prototype.
I think there are only ever static class methods passed in
Class.create(). When you do this:
Class.create({
initialize: function() {
// some code here
}
});
you are passing Class.create an anonymous object with a single static
method defined on it. That object could not be used to create a class
with the "new" construct, it has no constructor to speak of. That's
the whole premise of Class.create as I understand it, you pass it an
anonymous object which really is just a class definition.
The style I use to create classes with Class.create is to actually
name that anonymous object, define what will be instance methods as
static methods on it, pass that object to Class.create() and update
the object with what is returned. So what I wrote above is rewritten
that way and is equivalent as I understand it.
MyClass = {};
MyClass.initialize = function () {
// some code here
};
MyClass = Class.create(MyClass);
> If, for whatever reason, it actually IS supposed to work that way,
> it's a major flaw, and should be fixed immediately. But like I said,
> it wouldn't make any sense if it worked like that, and so it doesn't.
I think it's a pretty elegant design and it's actually the reason I
chose Prototype as a base framework, because I really liked how it
lets one define classes.
> So, with that - just do what darrin suggests (which is the best way
> to ensure your instance methods are truly instance only methods)...
> or attach them directly to the prototype object after Class.create()
> is called.
I think I'll just have a special method called in .initialize that
will map the getters and setters automatically. I was just hoping that
Prototype might already have a way to deal with JS getters and setters
outside of the constructor.
Antoine
On Jul 2, 2008, at 18:36 , kangax wrote:
>> Prototype doesn't provide any special facility for defining "static"
> members (as majority defines it). All it takes is to declare them as
> members of "class" function.
>
> var Foo = Class.create({ ... })
> Foo.blah = 'my static property';
Yeah, that's what I do and it works just fine.
>>> So, with that - just do what darrin suggests (which is the best way
>>> to ensure your instance methods are truly instance only methods)...
>>> or attach them directly to the prototype object after Class.create()
>>> is called.
>>
>> I think I'll just have a special method called in .initialize that
>> will map the getters and setters automatically. I was just hoping
>> that
>> Prototype might already have a way to deal with JS getters and
>> setters
>> outside of the constructor.
>>
>
> You could do that, though "fat" constructors is usually not a good
> idea. It would also cripple performance if constructor is called
> frequently.
I think it might be worth asking for JS getters and setters to be
handled directly by Class.create(). I'll try to add support for them
in Class.create() and submit a patch...
Antoine
There are no "static" or "instance" methods on js objects really : )
I understand what you mean, but it just sounds confusing.
You could do that, though "fat" constructors is usually not a good
idea. It would also cripple performance if constructor is called
frequently.
It's obviously a matter of priorities. For me, performance is usually
one of the key factors. Simulating "private" properties (in a highly
dynamic language) does not compensate for the decreased speed.
Doesn't really matter how we call it : )
Having bunch of logic in constructor is not a good design (in my
experience)
I would appreciate if my reasonings weren't claimed to
be "FUD" : )
:Dan
Bending language (and clogging performance) to meet inept programmers
expectations doesn't seem like a wise thing to do.
It's gotten a bit testy, but I just wanted to say that I, for one,
have appreciated the discussion thus far ;-)
Constantly repeating how I'm "plain wrong" and
making up assumptions about my reasonings, my experience and skills is
not something I would expect of you.
The truth is that there are no silver bullets (that you seem so
desperately convince me to follow).
There are also no "wrong" or "right". There are patterns that work in
one environment and don't work in others.
Ryan, no need to get offensive
Kangax's point might be moot for simple constructors, but that doesn't
make it "plain wrong". Suppose you have a constructor with 100
methods and you want 100 instances, is it better to define each and
every method on each and every instance, or put them on the
constuctor's prototype? More simply, would you consider it OK to
create 10,000 function objects when 100 will do the job?
If you are unequivocally right, then Prototype.js should stick with
the strategy employed for IE of adding methods to every DOM element it
encounters as there would be no point in extending HTMLElement
instead.
Much of the argument in this thread comes from the fact that
javascript doesn't have classes, or instance variables, or static
members: but there are various ways of emulating them. What you are
really arguing about are implementation preferences.
Concepts of good, bad, right and wrong are purely subjective
Why are you calling
shared instance members (where member is property/method) "static"?
Why are you calling
shared instance members (where member is property/method) "static"?
Sorry, that's not what I meant to say. If you read my blog post (http://www.someelement.com/2007/03/multiple-inheritance-with-prototypejs.html) - I explain what I mean by "prototype-static".
Ok, let's look at your example:// constructor
function Person(name) {
this.name = name;
Person.count++;
};
// static property (defined directly on a constructor)
Person.count = 0;
// shared instance method
Person.prototype.say = function(message) {
return this.name + ' says: ' + message;
}
(btw, you forgot a semicolon there - and yes I'm pedantic when it comes to missing semicolons :))
So... what I mean by "prototype static" is the fact that after that last line it is now possible to call "Person.prototype.say("blah")" statically (i.e. without having an instance) -- and of course get an error. What I mean by "instance only" members, is any member that is ONLY visible from instances, period. And of course true private variables and methods is another thing I was talking about.
meh... nevermind :)