Questions about reimplementing core classes

I had reason to need a sorted map recently and thought it might be a
useful exercise to write it as a complete drop-in replacement for Hash,
backed by a sorted array. An hour or so later:

http://pastie.caboo.se/62458

A few questions arose while I was writing which I’d like to pose to
y’all:

  1. I’m storing entries as struct objects, the class definition for which
    is stored in a class constant. Good or bad practice? I note that I get a
    constant redefinition warning when I reload the class. I could easily
    enough use a two element array, but thought a struct would be more
    efficient and be more clear.

  2. I’m extending Hash, not because I need to, but so that I could pass
    kind_of? tests if necessary. Good or bad practice?

  3. I had vaguely thought that the default freeze implementation would
    freeze all instance variables, but it does not. Is this a good way to
    implement freeze? (with the exception of the incorrect return value?)

  4. Should I be checking block_given? in delete_if, et. al.? Should I be
    explicitly declaring a &blk argument?

Thanks for any tips.

  • donald

On 5/17/07, Ball, Donald A Jr (Library) [email protected]
wrote:

I had reason to need a sorted map recently and thought it might be a
useful exercise to write it as a complete drop-in replacement for Hash,
backed by a sorted array.

Quick thing - I know Array is implemented in C rather than in Ruby.
This is probably true for Hash as well. There’s two points here:
first, if you were patching Array directly, you could rewrite [] and
it would still drop to the C implementation (if I understand
correctly). Second, the C versions of course will be faster.

enough use a two element array, but thought a struct would be more
efficient and be more clear.

I didn’t spot this in the code, but I’m in a pre-RailsConf packing
frenzy. Off the top of my head I’d say don’t do it - you should be
able to get that information from the stored object itself. Just
because you pop it in a hash doesn’t mean its identity dissolves.

  1. I’m extending Hash, not because I need to, but so that I could pass
    kind_of? tests if necessary. Good or bad practice?

Makes sense to me, although I’d probably want to run it through unit
tests for Hash, assuming those exist - and I’m sure they do, even if
only in the JRuby project - just to make sure it earns the inheritance
(so to speak).

  1. I had vaguely thought that the default freeze implementation would
    freeze all instance variables, but it does not. Is this a good way to
    implement freeze? (with the exception of the incorrect return value?)

I don’t know, I would have expected roughly the same thing.

  1. Should I be checking block_given? in delete_if, et. al.? Should I be
    explicitly declaring a &blk argument?

I hate to admit it but I have no idea what you’re even asking. I did
pp Hash.methods.sort and got neither of those. Are they in Enumerable?
I totally missed that.


Giles B.

I’m running a time management experiment: I’m only checking e-mail
twice per day, at 11am and 5pm. If you need to get in touch quicker
than that, call me on my cell.

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org

Quick thing - I know Array is implemented in C rather than in Ruby.
This is probably true for Hash as well. There’s two points here:
first, if you were patching Array directly, you could rewrite
[] and it would still drop to the C implementation (if I
understand correctly). Second, the C versions of course will
be faster.

I doubt that simply rewriting [] (and []=) would suffice, as Hash and my
SortedHash have entirely different internal data structures, upon which
the rest of the methods would seem to depend. Note I’m almost certain
that the C-based Hash is going to destroy my SortedHash in performance,
even for small collections for which a binary search is likely to be
faster than hash access. This was more of a learning ruby exercise than
anything practical.

packing frenzy. Off the top of my head I’d say don’t do it -
you should be able to get that information from the stored
object itself. Just because you pop it in a hash doesn’t mean
its identity dissolves.

Er, I’m just talking about a data structure in which to put the key and
value objects. I’m curious about the merits of [key, value] v.s.
ENTRY.new(key, value) (v.s., I dunno, putting the Entry struct in a
class variable or a class instance variable).

  1. Should I be checking block_given? in delete_if, et. al.?
    Should I
    be explicitly declaring a &blk argument?

I hate to admit it but I have no idea what you’re even
asking. I did pp Hash.methods.sort and got neither of those.
Are they in Enumerable?
I totally missed that.

Hash.methods.sort wouldn’t list 'em as they’re not class methods,
they’re instance methods. pp {}.methods.sort would list 'em. In any
case, I was going by the documentation here:

http://dev.rubycentral.com/ref/ref_c_hash.html

  • donald

On May 17, 3:40 pm, “Giles B.” [email protected] wrote:

Quick thing - I know Array is implemented in C rather than in Ruby.
This is probably true for Hash as well. There’s two points here:
first, if you were patching Array directly, you could rewrite [] and
it would still drop to the C implementation (if I understand
correctly).

a = [1,2,3]
def a.
“You want element #{bar.inspect}? Too bad!”
end

puts a[2]
#=> You want element 2? Too bad!

p a.class
#=> Array

On 5/17/07, Robert D. [email protected] wrote:

On 5/17/07, Ball, Donald A Jr (Library) [email protected] wrote:

  1. I had vaguely thought that the default freeze implementation would
    freeze all instance variables, but it does not. Is this a good way to
    implement freeze? (with the exception of the incorrect return value?)
    No that is not a good way I am afraid. Please note that one cannot
    freeze instant variables - I have a reason to be picky here, I believe
  • but the objects they are referring to.
    Do you see the implications of a “deep” freeze now? The whole program
    will probably get cold feet :wink: as objects just referenced in our
    object would be frozen.

This analogy remind’s me of ice-9 in Kurt Vonnegut’s “Cat’s Cradle.”


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 17.05.2007 22:08, Ball, Donald A Jr (Library) wrote:

is stored in a class constant. Good or bad practice? I note that I get a

  1. Should I be checking block_given? in delete_if, et. al.? Should I be
    explicitly declaring a &blk argument?

Thanks for any tips.

How about using http://raa.ruby-lang.org/project/ruby-rbtree/ ?
Btw, this is one of two hits for
http://raa.ruby-lang.org/search.rhtml?search=sorted%20hash

:slight_smile:

Kind regards

robert

On 5/17/07, Ball, Donald A Jr (Library) [email protected]
wrote:

implement freeze? (with the exception of the incorrect return value?)
No that is not a good way I am afraid. Please note that one cannot
freeze instant variables - I have a reason to be picky here, I believe

  • but the objects they are referring to.
    Do you see the implications of a “deep” freeze now? The whole program
    will probably get cold feet :wink: as objects just referenced in our
    object would be frozen.

However what you are doing is clever of course, you freeze the objects
you have created as containers for other objects without freezing the
objects the container references, do you see how bad it would be again
if your SortedHash froze all contained objects?

  1. Should I be checking block_given? in delete_if, et. al.? Should I be
    explicitly declaring a &blk argument?
    I prefer to declare &blk, because it is easier to pass it to another
    method needing a block, just compare

def a &blk
b &blk if blk
end
v.s.
def a
b &Proc.new if block_given?
end
However

passing &blk is much slower if memory serves right.

Cheers
Robert

Do you see the implications of a “deep” freeze now? The whole
program will probably get cold feet :wink: as objects just
referenced in our object would be frozen.

Heh heh heh, that hadn’t yet occurred to me, but your point’s well
taken.

However what you are doing is clever of course, you freeze
the objects you have created as containers for other objects
without freezing the objects the container references, do you
see how bad it would be again if your SortedHash froze all
contained objects?

Of course. But what I’m doing is fine, at least as far as it goes, yes,
since I have relatively simple internal data structures? If it were more
complex, it would be better to explicitly check frozen? in each of the
methods which could modify state? (which means i really ought to put in
a super call in my freeze method…)

  • donald