Hash constructor

4 views
Skip to first unread message

Alexander Presber

unread,
Feb 8, 2007, 11:26:19 AM2/8/07
to prototy...@googlegroups.com
Hello everyone,

I have a little trouble porting stuff to from prototype 1.4 to 1.5.
Some has to do with ticket #3592, where the results of filters on
enumerables are discussed. As long as this patch is not accepted I
could just patch the behaviour for myself, overloading Enumerables
reject and findAll methods after loading prototype.js.
This would work, because the Enumerable methods were copied to the
Hash object _when_creating_a_new_Hash_.

Now with 1.5 that cannot be done anymore, because the Enumerable
methods are copied to the Hash _prototype_, from where they are
copied by JS when instatiating a new Hash via the new operator.
So effectively to overwriite Enumerable methods I would have to
reextend Hash.prototype with Enumerable after applying my fixes on
Enumerable (the same goes for Array and Range and future Enumerable
descendants).

Now my question is: What is the advantage of the new Hash
implementation? Why did Class.create not suffice? I can see added
complexity but no real gain, since Enumerable is not really in the
prototype chain of Hash, its methods are just copied to the Hashes
prototype.

Please don't think I want to troll around, I am really appreciating
your work.
I have a lot of code depending on Prototype and there is just so much
broken now.
On the other hand I would not want to miss on features and
improvements by staying on 1.4, you see.

Alex

Andrew Dupont

unread,
Feb 8, 2007, 12:17:21 PM2/8/07
to Prototype: Core

On Feb 8, 6:26 pm, Alexander Presber <aljos...@weisshuhn.de> wrote:
> Now my question is: What is the advantage of the new Hash
> implementation? Why did Class.create not suffice? I can see added
> complexity but no real gain, since Enumerable is not really in the
> prototype chain of Hash, its methods are just copied to the Hashes
> prototype.

The advantage is the reason that prototypes exist in JavaScript in the
first place. Using the previous method (copying methods onto each
instance), if you create 100 you've got to make 100 copies of your
inherited methods. With prototype-based inheritance they all point to
the same copy. It's a big win for memory usage. Read this interview
with Dean Edwards: http://snook.ca/archives/writing/an_interview_wi/

That said, if you need to redefine Enumerable methods I don't think
it's that much of an inconvenience to do:

Enumerable.findAll =
Array.prototype.findAll =
ObjectRange.prototype.findAll =
Hash.prototype.findAll = function() { /* ... */ }

It's certainly not pretty, but you could roll it up into some sort of
function if you're redefining Enumerable methods that often.

More to the point: why override Enumerable methods when you can define
new ones -- "customFindAll" or "_reject" or something like that?
Seems more future-proof and friendlier to other scripts.

Andrew Dupont

unread,
Feb 8, 2007, 12:24:49 PM2/8/07
to Prototype: Core
Apologies -- I didn't fully understand this question until I re-read
#3592.

I agree that we need to apply this patch and will raise some hell
forthwith. In the meantime, the issue is specific to Hash, so can't
you do...

Object.extend(Hash.prototype, {
reject: function() { /* ... */ },
findAll: function() { /* ... */ },
_add: function() { /* ... */ },
_new: function() { /* ... */ }
});

I think this is the best band-aid until this problem gets permanently
fixed.

On Feb 8, 6:26 pm, Alexander Presber <aljos...@weisshuhn.de> wrote:

Alexander Presber

unread,
Feb 8, 2007, 12:44:28 PM2/8/07
to prototy...@googlegroups.com
Am 08.02.2007 um 18:24 schrieb Andrew Dupont:
>
> Apologies -- I didn't fully understand this question until I re-read
> #3592.
>
> I agree that we need to apply this patch and will raise some hell
> forthwith. In the meantime, the issue is specific to Hash, so can't
> you do...
>
> Object.extend(Hash.prototype, {
> reject: function() { /* ... */ },
> findAll: function() { /* ... */ },
> _add: function() { /* ... */ },
> _new: function() { /* ... */ }
> });

Thanks :-)

Here is my (slightly more prototypish) solution for now:

$A([Array, Hash, Range]).each(function(c){Object.extend(
c.prototype, {


reject: function() { /* ... */ },
findAll: function() { /* ... */ }

})});

Cheers, Alex

Alexander Presber

unread,
Feb 8, 2007, 12:59:45 PM2/8/07
to prototy...@googlegroups.com
> With prototype-based inheritance they all point to
> the same copy. It's a big win for memory usage. Read this interview
> with Dean Edwards: http://snook.ca/archives/writing/an_interview_wi/

I see your point. But this is not exactly what happens here.

We do indeed save memory by putting the methods into the Hashes
constructor.
I completely missed that and it is indeed an advantage.

But Dean Ewards is promoting true javascript inheritance, which means
not copying Enumerables methods into our constructor, but
putting Enumerable into our prototype chain. This saves even more
memory (no copying of any methods to extended classes, leave alone
instances) and leaves Enumerable "open", which means we can still
override Enumerables methods and add new ones, even on instantiated
objects.

Now that seems to be on the list of things to do as most people here
probably know. See here

http://encytemedia.com/blog/articles/2006/05/23/prototype-inheritance-
madness and here:
http://sam.conio.net/articles/better-inheritance-for-prototype

But for now it is probably safe to state that the new inheritance
scheme for Enumerable
solves some problems (memory footprint) while creating others
(backwards compatibility, "openness"), at least for some people.

Probably the tradeoff is a positive one for most people, sadly not
including me at this time :-(.

How is the state of affairs in introducing Dean Edwards Base
inheritance to prototype? There are some tickets on inheritance, but
one especially for that?

Cheers, Alex


Mislav Marohnić

unread,
Feb 8, 2007, 2:58:19 PM2/8/07
to prototy...@googlegroups.com
On 2/8/07, Alexander Presber <aljo...@weisshuhn.de> wrote:

How is the state of affairs in introducing Dean Edwards Base
inheritance to prototype? There are some tickets on inheritance, but
one especially for that?

I tried to introduce Base to Prototype once. It was when my level of JavaScript knowledge was so high I thought I can handle it all.

My first task was to "decompile" Base into Prototypish code in order actually *understand* it. I'm ashamed to say that I failed at that first step, thus realizing I have much to work until I reach the "Edwards" level. Hence my involvement with Prototype.

Months later I'm still kinda reluctant to face Base source again. But, I'm building my strength up to it.

-m

Michael Schuerig

unread,
Feb 8, 2007, 9:10:15 PM2/8/07
to prototy...@googlegroups.com

Dean has explained the use of Base on his blog
http://dean.edwards.name/weblog/2006/03/base

The code accompanying "Pro JavaScript Techniques" by John Resig has a
slightly commented version of Base.js (Chapter 3)
http://www.apress.com/book/supplementDownload.html?bID=10163&sID=4026

For something entirely different, Alex Arnell has an inheritance
implementation that (purportedly) plays well with Prototype
http://twologic.com/projects/inheritance/

In case anyone was interested...
Michael

--
Michael Schuerig
mailto:mic...@schuerig.de
http://www.schuerig.de/michael/

Andrew Dupont

unread,
Feb 10, 2007, 1:20:18 PM2/10/07
to Prototype: Core

On Feb 8, 7:59 pm, Alexander Presber <aljos...@weisshuhn.de> wrote:
> > With prototype-based inheritance they all point to
> > the same copy. It's a big win for memory usage. Read this interview
> > with Dean Edwards:http://snook.ca/archives/writing/an_interview_wi/
>
> I see your point. But this is not exactly what happens here.
>
> We do indeed save memory by putting the methods into the Hashes
> constructor.
> I completely missed that and it is indeed an advantage.
>
> But Dean Ewards is promoting true javascript inheritance, which means
> not copying Enumerables methods into our constructor, but
> putting Enumerable into our prototype chain. This saves even more
> memory (no copying of any methods to extended classes, leave alone
> instances) and leaves Enumerable "open", which means we can still
> override Enumerables methods and add new ones, even on instantiated
> objects.

Yes, what you're describing would be ideal, but play around with it
for just a few minutes in FireBug and you'll realize it can't be done.
There's no way to slip an arbitrary object into the prototype chain of
a builtin, so the only alternative is to copy Enumerable over to
Array.prototype via Object.extend.

Now, custom objects like Hash are a different matter. But I think
it's better to be consistent. If redefining Enumerable.reject updated
Hash.prototype.reject and ObjectRange.prototype.reject but not
Array.prototype.reject, then that'd be confusing. Also, the principle
of least surprise dictates that we adhere to Ruby conventions whenever
possible. In Ruby, Enumerable is a mixin, not a class. Better, then,
to use Object.extend (which functions like a mixin) than to have
objects inherit from Enumerable.

> How is the state of affairs in introducing Dean Edwards Base
> inheritance to prototype? There are some tickets on inheritance, but
> one especially for that?

It's a stated goal for 2.0; I'd love to get it into the codebase even
sooner. I think it'd take until 2.0 to rewrite the existing classes
(Ajax.*, for instance) to follow a proper inheritance model, but that
doesn't mean we have to wait until 2.0 to introduce something Base-
like. Ultimately it's up to Sam, though.

Cheers,
Andrew

Reply all
Reply to author
Forward
0 new messages