dkubb / adamantium

Create immutable objects
MIT License
373 stars 13 forks source link

Cache built-in query methods of immutable object #25

Open dkubb opened 10 years ago

dkubb commented 10 years ago

This branch memoizes the #hash, #to_s and #inspect methods automatically since they are based on the instance state, and cannot change since the instance state is immutable.

[Fix #9]

mbj commented 10 years ago

@dkubb I think the intent of this change is okay. But I fear we run into ordering issues with equalizer, concord, anima includes. Can we guard against overriding the memoized #hash, #inspect etc?

dkubb commented 10 years ago

@mbj I wonder if a method_added hook could be used to warn when a memoized method is being overridden in the same class/module it's defined within? Or it could just re-memoize the method.

One downside to warning is if someone defines their own #hash (or #inspect or #to_s) then they'll get tons of warnings which are meaningless.

elskwid commented 10 years ago

@mbj, @dkubb - now that these gems are being combined in interesting ways seems to be a good time to talk about the ordering and needed methods. Ideally they don't need to be done in any order, right? The ordering gets increasingly complicated as we add more and more gems. It's ironic to be worried about overridden methods given some recent rants about ActiveSupport. I wish I had more to add to actually help. Mostly just echoing the concern and offering to help if I can.

mbj commented 10 years ago

@dkubb IMHO: I'd be okay to issue a warning. If someone dislikes these warnings he can define their own #hash and friends, than import Adamantium or dont use this library. I'd generally favor doing what fulfills my needs, and than focus on imaginary users. Avoiding doing decisions and creating to much options just limits effectiveness of the lib and development speed: "Library authors should provide solutions, not more options.".

My typical code looks like this:

class Foo
  include Adamantium, Concord.new(:bar, :baz)
end

Module#include applies includes in reverse order, concord uses equalizer to set up #hash and friends. So adamantium with auto memoization of #hash and friends would fit my style perfectly.

dkubb commented 10 years ago

@mbj what about using method_added to memoize #to_s, #to_hash and #inspect when they are added?

mbj commented 10 years ago

@dkubb Yeah. This will allow equalizer and similar libs to work without ANY knowlege about adamantium +1. I think this is the way to go.

mbj commented 10 years ago

@dkubb Maybe you should NOT memoize #hash and friends by default. Only if a method missing was detected!

dkubb commented 10 years ago

@mbj method_missing won't kick in because they'll inherit those methods from Object.

mbj commented 10 years ago

@dkubb I meant method_added. Sorry obviousely NOT method missing ;)

orend commented 10 years ago

This PR needs to be rebased; bundle install fails because of old gem dependencies.

dkubb commented 10 years ago

@orend I rebased this against master so it should be usable.

dkubb commented 10 years ago

My latest commit adds a #method_added hook that will memoize a method when it is added.

However, it loses the ability to memoize the built-in #to_s and #inspect methods. I couldn't make them both work because you can't re-memoize a method twice in the same class.

What I think may need to happen is a change in memoize itself where you can memoize a specific method only once, but if the method is overridden you can memoize it again. Once this change is done, then the built-in #to_s and #inspect methods can be automatically memoized again.