[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Indexers and blocks?

Stephan Mueller

10/9/2007 9:47:00 AM

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 [](key)
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.

9 Answers

David A. Black

10/9/2007 10:27:00 AM

0

Stephan Mueller

10/9/2007 12:09:00 PM

0

Hi,

* David A. Black <dblack@rubypal.com> [09.10.2007]:

> You can do:
>
> c.[](:text) { "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.

Robert Dober

10/9/2007 2:02:00 PM

0

On 10/9/07, Stephan Mueller <d454d@web.de> wrote:
> 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 [](key)
> 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).
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
--
what do I think about Ruby?
http://ruby-smalltalk.blo...

Stephan Mueller

10/9/2007 2:41:00 PM

0

* Robert Dober <robert.dober@gmail.com> [09.10.2007]:

> 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... :)


Cheers,

Steph.

Brian Adkins

10/9/2007 5:48:00 PM

0

On Oct 9, 10:40 am, Stephan Mueller <d4...@web.de> wrote:
> * Robert Dober <robert.do...@gmail.com> [09.10.2007]:
> > 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 [](key)
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]

Gary Wright

10/9/2007 6:35:00 PM

0


On Oct 9, 2007, at 1:50 PM, Brian Adkins 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 Wright




Brian Adkins

10/9/2007 10:57:00 PM

0

On Oct 9, 2:35 pm, Gary Wright <gwtm...@mac.com> wrote:
> On Oct 9, 2007, at 1:50 PM, Brian Adkins 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.

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.

Stephan Mueller

10/10/2007 12:03:00 PM

0

* Brian Adkins <lojicdotcom@gmail.com> [10.10.2007]:

> > 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! :) 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.

Pit Capitain

10/12/2007 7:56:00 AM

0

2007/10/10, Stephan Mueller <d454d@web.de>:
> 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