memoist
memoist copied to clipboard
&block is omited when method memoized
def foo(&block)
@block = block
end
memoize :foo
foo { :bar }
@block # => nil
There should be either exception or no memoization in this case
@JelF what's your actual use case?
By default memoist will treat this like any method with arguments, and try and memoize it based on the value of the block
object
But I'm not sure what a real use of this is, and therefore don't know what the correct behaviour should be.
@matthewrudy i tried to memoize #fetch, delegated to some hash, and got unexpected KeyError in specs
expect(subject.fetch(Foo::Bar) { {} }).to eq({}) # => KeyError
By default memoist will treat this like any method with arguments, and try and memoize it based on the value of the block object
As far as i see, method defined in lib/memoist.rb does not accept &blocks (they are not catched by *args). So this is wrong, memoize just ignores any &blocks
@JelF you're correct, sorry.
But again, what's the real use case, something like this?
class Store
def fetch(key)
get(key) || set(key, yield)
end
end
something like this?
@matthewrudy http://ruby-doc.org/core-2.2.0/Hash.html#method-i-fetch, lol
also, there is no way to cache by block value (if it is not nil), so semantics should be as i've written in top post:
There should be either exception or no memoization in this case
@JelF so you're literally trying to memoize Hash#fetch
?
Again, what are you trying to achieve? you might be better just using a hash
# this will cache the value in the hash when called
>> powers = Hash.new { |h, k| puts "2**#{k}"; h[k] = 2**k}
# first time the key is not there, so it hits the block
>> powers[24]
2**24
=> 16777216
# second time it just returns the value
>> powers[24]
=> 16777216
So this code originates from 2008 https://github.com/rails/rails/commit/8a9934a9d9fc98b56c4566ae2e3fd4d83e505d3e
It has changed a bit over the years and I took it over in 2011.
But it's never supported blocks, and no one has asked for it too until now.
So I'm just trying to understand what you're trying to do, so I can understand the problem.
@matthewrudy i am tried to achieve a stub i can rewite to something like
def fetch(*args, &block)
IceNine.deep_freeze(global_config.fetch(*args, &block).with_indifferent_access)
end
memoize :fetch
And also this is a live hash, so i can not deep_freeze it somewhere except fetch method. Also, this was a wrong decision because good memoization can not be done here
If you simply raise something like Memoist::BlocksNotSupported when memozied method received block, i can understand what is wrong in a moment, but if i memoized method by mistake, and no one used it with block for a while, it will be hard to debug.
@JelF cool.
So with the &block
I can do it pretty easy.
>> def with_block_arg(&block); end
>> method(:with_block_arg).parameters
=> [[:block, :block]]
I can check for that
But with yield
I don't know a way.
>> def with_yield(); yield; end
>> method(:with_yield).parameters
=> []
>> method(:with_yield).methods.sort - Object.methods
=> [:[], :arity, :call, :curry, :original_name, :owner, :parameters, :receiver, :source_location, :super_method, :to_proc, :unbind]
But yeah, let's add an error if the parameters
include an &block
@matthewrudy it will break back-comp and cause problems with parameters delegation. e.g.
def bar(x)
x + 1
end
def foo(*args, &block)
bar(*args, &block).to_s
end
memoize :foo