Feature #7299

Ruby should not completely ignore blocks.

Added by Marc-Andre Lafortune over 1 year ago. Updated over 1 year ago.

[ruby-core:49018]
Status:Rejected
Priority:Normal
Assignee:-
Category:core
Target version:-

Description

Ruby should not completely ignore blocks.

const_set :Example, Class.new do
p "Hello, world"
end
# Doesn't print anything, generate any warning nor error.

To minimize any impact, Ruby should issue a warning, and in future version could even raise an error.

Even unused variables provide warnings in verbose mode, and they have their use.

I can't think of a case where passing a block to a builtin method that doesn't accept a block is not a programming error though.

If this is approved, I volunteer to implement this.

History

#1 Updated by Yukihiro Matsumoto over 1 year ago

  • Status changed from Open to Feedback

I considered this issue before, and had problem with how to detect non block calling block.
Things go easier if & block argument is mandatory for block taking methods, but I am not doing so in near future.
Do you have any good idea?

Matz.

#2 Updated by Marc-Andre Lafortune over 1 year ago

  • Status changed from Feedback to Open

matz (Yukihiro Matsumoto) wrote:

I ... had problem with how to detect non block calling block.

Sorry, I am not sure I understand completely.

To avoid case like the example I gave, we could modify "rbmodconstset" by adding "WARNIFBLOCKGIVEN", for example, or create a more advanced version of "rbcheckarity" like "rbcheckarityandblock" that accepts a parameter to warn if there is a block given.

What I would really like to do is create an improved "rbdefinemethod" with arguments to specify:
* mininum arity
* maximum arity
* if block is accepted
* and ideally parameter names, at least for methods with simple interfaces

This way:
* easier to warn if block is accepted
* improved result for "".method(:gsub).arity
* much improved result for "".method(:gsub).parameters
* possible to implement arity_max or arity_range with good result if ever it is accepted
* improved behavior when using curry

Also, this would simplify many method that would not have to call rb_check_arity like we do now.

#3 Updated by Yukihiro Matsumoto over 1 year ago

  • Status changed from Open to Rejected

So you think of changing introducing new functions. I see.
In that case, it's better to submit a new issue for the idea, with API proposal.

Matz.

#4 Updated by Anonymous over 1 year ago

On Wed, Nov 07, 2012 at 01:06:34PM +0900, marcandre (Marc-Andre Lafortune) wrote:

Issue #7299 has been reported by marcandre (Marc-Andre Lafortune).


Feature #7299: Ruby should not completely ignore blocks.
https://bugs.ruby-lang.org/issues/7299

Author: marcandre (Marc-Andre Lafortune)
Status: Open
Priority: Normal
Assignee:
Category: core
Target version:

Ruby should not completely ignore blocks.

const_set :Example, Class.new do
p "Hello, world"
end
# Doesn't print anything, generate any warning nor error.

To minimize any impact, Ruby should issue a warning, and in future version could even raise an error.

Even unused variables provide warnings in verbose mode, and they have their use.

I can't think of a case where passing a block to a builtin method that doesn't accept a block is not a programming error though.

This happens with normal ruby code:

ruby -w -e'def foo; 10; end; p foo { raise };'

Why would "builtin" methods be special?

--
Aaron Patterson
http://tenderlovemaking.com/

#5 Updated by Rodrigo Rosenfeld Rosas over 1 year ago

Em 07-11-2012 11:00, Aaron Patterson escreveu:

On Wed, Nov 07, 2012 at 01:06:34PM +0900, marcandre (Marc-Andre Lafortune) wrote:

Issue #7299 has been reported by marcandre (Marc-Andre Lafortune).


Feature #7299: Ruby should not completely ignore blocks.
https://bugs.ruby-lang.org/issues/7299

Author: marcandre (Marc-Andre Lafortune)
Status: Open
Priority: Normal
Assignee:
Category: core
Target version:

Ruby should not completely ignore blocks.

const_set :Example, Class.new do
p "Hello, world"
end
# Doesn't print anything, generate any warning nor error.

To minimize any impact, Ruby should issue a warning, and in future version could even raise an error.

Even unused variables provide warnings in verbose mode, and they have their use.

I can't think of a case where passing a block to a builtin method that doesn't accept a block is not a programming error though.
This happens with normal ruby code:

ruby -w -e'def foo; 10; end; p foo { raise };'

Why would "builtin" methods be special?

I agree. I'd prefer to just raise an exception when a block is passed
and no block_given? or yield is called for the method.

I was bitten some times by bugs hard to detect because of this behavior
where I thought the block was being given to a method while it was being
given to another one that didn't even expect any block.

#6 Updated by Marc-Andre Lafortune over 1 year ago

matz (Yukihiro Matsumoto) wrote:

So you think of changing introducing new functions. I see.
In that case, it's better to submit a new issue for the idea, with API proposal.

Of course, but first I wanted to validate you were positive with the idea of warning for unused block

tenderlove wrote:

This happens with normal ruby code:
Why would "builtin" methods be special?

Agreed, it would be best if user methods also warned. I was just lacking ambition by suggesting it only for builtin methods :-)

Rodrigo's suggestion of flagging block_given?, yield, (as well as Proc.new, super and &capture_block) would work.

#7 Updated by Yukihiro Matsumoto over 1 year ago

I am positive as long as there's rational way to declare methods as 'non-block taking'.
Last time I tried, I couldn't think any good idea to do so (without adding new API).
New API (alternative version of rbdefinemethod, I suppose) is a good idea.
The remaining problem should be how to declare Ruby-define methods to be 'non-block taking'.
Under the current language spec, absence of '& argument' may or may not mean the method would take a block.

Matz.

#8 Updated by Koichi Sasada over 1 year ago

(2012/11/08 5:48), matz (Yukihiro Matsumoto) wrote:

Under the current language spec, absence of '& argument' may or may not mean the method would take a block.

I agree that such checking is very useful.

# example code
p 'str'.gsub('x') do

end

One idea:

If compiled method does not contain
- `yield' statement
- super statement
- block argument
then the method is marked as "block is not needed" method.

This approach introduce incompatibility because we can call block in `eval'.

# example
def foo str
eval str
end

foo('yield') do
...
end

And maybe there are other issues.

--
// SASADA Koichi at atdot dot net

#9 Updated by Shyouhei Urabe over 1 year ago

On 11/07/2012 03:23 PM, SASADA Koichi wrote:

This approach introduce incompatibility because we can call block in `eval'.

So you are proposing to deprecate eval? :p

#10 Updated by Marc-Andre Lafortune over 1 year ago

ko1 (Koichi Sasada) wrote:

If compiled method does not contain
- `yield' statement
- super statement
- block argument
then the method is marked as "block is not needed" method.

This approach introduce incompatibility because we can call block in `eval'.

And maybe there are other issues.

There is also Proc.new...

def foo
  Proc.new.call
end

foo{ p 42 } # => prints 42

Both eval and Proc.new are strange cornercases though. The only valid uses I can think of for Proc.new also imply use of super. If we only issue a warning, the incompatibility would be very minimal.

So I'll make a proposal for an expanded API for rb_define_method. OTOH, marking ruby methods as {non-}block taking would seriously challenge my cruby skills

#11 Updated by Nobuyoshi Nakada over 1 year ago

(12/11/09 1:53), marcandre (Marc-Andre Lafortune) wrote:

ko1 (Koichi Sasada) wrote:

If compiled method does not contain
- `yield' statement
- super statement
- block argument
then the method is marked as "block is not needed" method.

There is also Proc.new...

Also proc, lambda, and defined?(yield).

--
Nobu Nakada

#12 Updated by Charles Nutter over 1 year ago

Perhaps methods that want to ensure nobody accidentally passes in a block should just check for it? fail if block_given? for example?

An option for a syntactic check in Ruby code: def foo(&nil) => raise error on call if a block is given.

I don't think magic checks should be put in place for Ruby code that doesn't have an explicit block parameter. There are a lot of edge cases where the block is used and we don't know about it until later. eval/binding has been brought up, Proc.new (which should be deprecated) has been brought up, and so on.

Also available in: Atom PDF