Questions about with..yield

first is with…yield trying to achieve the same thing as ruby’s instance_eval? since crystal doesn’t have instance_eval ,

then

class Person
  def foo
    puts "person foo"
  end
end
def foo
  puts "foo"
end
def some_proc(&block : Int32 -> _)

  with Person.new yield 15
end
some_proc do
  foo
  break
end

outputs foo

while removing type declaration.

def some_proc(&block)

  with Person.new yield 15
end

outputs person foo

so the only difference here is type declaration,
which is quite confusing to me,
whether the block is captured or not(under both 2 circumstances),
I deliberate add break in block since the docs says captured doesn’t support break.

Yeah, it’s basically a subset of instance_exec’s functionality.

This sounds like a bug. Here is a more concise reproduction of it:

class Person
  def foo
    puts "foo"
  end
end

def some_proc(& : Int32 ->)
  with Person.new yield 15
end

some_proc { foo }

It doesn’t compile, but if you change it to def some_proc, it compiles and runs as expected. I have a feeling that it’s because when you use yield, you don’t need to provide a type declaration for the block (it’s inferred from the yield) and usage with the type declaration in place never ended up being tested.

1 Like

I think you just need to remove the 15 and do an empty yield, without the typed block mentioned previously. When using with ... yield you’re not supposed to give a value after the yield. Otherwise I’m pretty sure it just drops the with Person.new and yields 15. If that is in fact true, maybe some error could be raised pointing that out.

1 Like

hello, thanks.

then why introduce a new grammar?
just uses instance_eval or instance_exec method

it seemed now crystal doesn’t support eval(“str”), so instance_eval can raise an exception when accepting string argument.

As much as Crystal resembles Ruby, it is very much its own language. There are quite a few areas where Crystal isn’t like Ruby.

2 Likes

Just use yield is a non-captured block, a non-captured block is always inlined, no performance pency!

I guess, as describe by above, when use yield ???, there is no block actually, so any (& : Type → Type) will be ignored. but when yield use with with ??? yield separately, the inline invalid apparently, use &block, in this case, when you specify & : Int32 ->, will assume yield a number into block instead of yield self.

It seems that Crystal does anticipate scoped yields with arguments:

Personally I’d drop scoped yields from the language entirely, especially if the most common usage yields the scope itself as an argument.

Anyway, this is already reported here: with ... yield issue with type restriction · Issue #8722 · crystal-lang/crystal · GitHub

3 Likes

Because it has different semantics - instance_eval and instance_exec work at runtime - with … yield works at compile time.