Trouble with Capturing blocks

#1

https://play.crystal-lang.org/#/r/6ktm

test = Hash(Int32, Int32).new
test[2] = 20
test[1] = 50

def max_by_internal_test(&block : Hash(Int32, Int32) -> Hash(Int32, Int32))
  each_with_index do |elem, i|
    #value = yield elem
    
    puts elem
  end
end


max_by_internal_test do |i|
   test
end

Error:

undefined local variable or method ‘each_with_index’

I’m trying to see how this line of code works:

I have specified the input, and output types
Also, what does “forall U” do?

0 Likes

#2

https://play.crystal-lang.org/#/r/6kuk/edit

Getting closer. Not sure >_<

edit: Hmm so max_by_internal_test { |value| value } seems to be working. But now, I get

in line 26: no overload matches 'Tuple(Int32, Int32)#>' with type Int32
Overloads are:
 - Comparable(T)#>(other : T)

New Playground: https://play.crystal-lang.org/#/r/6kux

I also don’t understand how this line has |value| yield value, but if I use the yield keyword… I receive an error:

Error in line 38: ‘Test.new’ is expected to be invoked with a block, but no block was given

0 Likes

#3

You’re trying to call a Hash method as a method in the top-level namespace. It seems like you figured this out already, though.

forall U specifies a method as generic. In the case of

private def max_by_internal(&block : T -> U) forall U

this means that the method takes a block that takes the generic type T of the Enumerable and returns any type U.

In regards to your playground links (let’s use this one, the issue with yield isn’t that you just can’t use it but that you’re passing to yield a Tuple (which is a Hash key and value) in line 25 and then the block that you’re giving in line 9 just returns that Tuple. Then, in line 26 you’re comparing value, which is a Tuple, to max, which is an Int32. That just doesn’t work. If you instead return, for example, the Hash value, it will run: https://play.crystal-lang.org/#/r/6lrv

1 Like