Indexers and blocks?

Hi,

if I have an array-like class, is it possible to call the index with a
block?

class MyClass
def find(key)
return nil
end

def
if (val = find(key))
return val
else
return yield(key) if block_given?
end
end
end

c = MyClass.new
c[:test] { “default” }

triggers a syntax error (Ruby 1.8.6).

Is there a way to accomplish this or do i need to do tricks like giving
the block to the constructor?

Cheers,

Steph.

Hi –

On Tue, 9 Oct 2007, Stephan M. wrote:

def

triggers a syntax error (Ruby 1.8.6).

Is there a way to accomplish this or do i need to do tricks like giving
the block to the constructor?

You can do:

c. { “default” }

but that’s kind of ugly. I guess the whole point of c[] is to conceal
the fact that it’s a method call, which means that it then doesn’t try
to duplicate the full method call anatomy.

David

On 10/9/07, Stephan M. [email protected] wrote:

def

triggers a syntax error (Ruby 1.8.6).
I agree with you that this is unfortunate for the general case.
In your case however – unless it was only an example – I would favor
the

following idiom

c[:test] or “default”

HTH
Robert

Hi,

You can do:

c. { “default” }

ah, thanks, have not thought of that.

but that’s kind of ugly. I guess the whole point of c[] is to conceal
the fact that it’s a method call, which means that it then doesn’t try
to duplicate the full method call anatomy.

at least its better than having a #[] and a #get(…) member where one
forwards to the other one. Will this change in 1.9 or later?

Cheers,

Steph.

I agree with you that this is unfortunate for the general case.
In your case however – unless it was only an example – I would favor the

following idiom

c[:test] or “default”

nice! But in my case I will need the block because

a) in practice a simple literal will not suffice
b) the result of the block should be assigned to the internal array at
the same step. (this was not part of my example code, sorry)

Without these requirements I like your idea best… :slight_smile:

Cheers,

Steph.

On Oct 9, 2007, at 1:50 PM, Brian A. wrote:

c = MyClass.new(‘default’)
c[:foo] = ‘foo’
puts c[:foo]
puts c[:test]
c = MyClass.new {|obj,key| “default for #{key}” }
puts c[:test]

This looks to me like you’ve just recreated features
of Hash. Might as well just use Hash.

I’d also like to point out Hash#fetch, which allows
you to override the hash default logic:

a = Hash.new(0)
a[1] # 0
a.fetch(1) { |k| -k} # -1
a[1] # 0
a.fetch(1) # IndexError exception

Gary W.

On Oct 9, 10:40 am, Stephan M. [email protected] wrote:

c[:test] or “default”

nice! But in my case I will need the block because

a) in practice a simple literal will not suffice

You’re not limited to a simple literal.

b) the result of the block should be assigned to the internal array at
the same step. (this was not part of my example code, sorry)

Your example seems more hash-like than array-like to me, and it sounds
like using the same technique that Hash uses (passing a block to
Hash.new for default value computation) may work for you if the
computed value is a function of the object and/or the key.

class MyClass
def initialize obj=nil, &b
if block_given?
@default_block = b
elsif obj
@default_block = lambda {|h,k| obj }
end
@h = Hash.new
end

def
if !@h.has_key?(key) && @default_block
@h[key] = @default_block.call(self, key)
puts “‘#{@h[key]}’ assigned to #{key}”
end
@h[key]
end

def []=(key, value)
@h[key] = value
end
end

c = MyClass.new(‘default’)
c[:foo] = ‘foo’
puts c[:foo]
puts c[:test]
c = MyClass.new {|obj,key| “default for #{key}” }
puts c[:test]

On Oct 9, 2:35 pm, Gary W. [email protected] wrote:

of Hash. Might as well just use Hash.
Presumably the OP had a reason for wanting an “array-like class”
instead of an actual Array or Hash. I only used a Hash in the example
for simplicity.

This looks to me like you’ve just recreated features
of Hash. Might as well just use Hash.

Presumably the OP had a reason for wanting an “array-like class”
instead of an actual Array or Hash. I only used a Hash in the example
for simplicity.

right! :slight_smile: Thanks fpr your example, I decided to chose the variant where
the block is given to the constructor. If there wasn’t the
syntax-problem
with the block on #[] i would have chosen that as it seems to be more
intuitive.

Anyway, thanks for the interesting discussion. It’s nice to see how
different people target the same problem with different solutions.

Cheers,

Steph.

2007/10/10, Stephan M. [email protected]:

a) in practice a simple literal will not suffice
b) the result of the block should be assigned to the internal array at
the same step. (this was not part of my example code, sorry)

and

Anyway, thanks for the interesting discussion. It’s nice to see how
different people target the same problem with different solutions.

Stephan, here’s one more:

c[:test] ||= (

)

Gruß,
Pit