From: faraz.yashar@... Date: 2015-05-16T08:06:35+00:00 Subject: [ruby-core:69213] [Ruby trunk - Bug #11156] Indeterminate Behavior for Curly-braced Blocks with Function Argument Missing Parenthesis Issue #11156 has been updated by Faraz Yashar. I'm trying to demonstrate that the syntax is very confusing and error-prone, especially given that `do ... end` blocks do not behave similarly due to precedence differences. Consider the `travel_to` time travel method given by Rails' `ActiveSupport::Testing::TimeHelpers`. One would naturally expect that the following two statements would behave equivalently... ~~~ruby travel_to Time.parse('2015-01-01 00:00:00 +0000') do Time.now # => 2015-01-01 00:00:00 +0000 end travel_to Time.parse('2014-01-01 00:00:00 +0000') { Time.now # => 2015-05-16 03:52:24 -0400 } ~~~ ...but they don't because of precedence behaviors. To me, these differences violate the principle of least astonishment, and they cause more confusion and open room for errors. ---------------------------------------- Bug #11156: Indeterminate Behavior for Curly-braced Blocks with Function Argument Missing Parenthesis https://bugs.ruby-lang.org/issues/11156#change-52465 * Author: Faraz Yashar * Status: Rejected * Priority: Normal * Assignee: * ruby -v: ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux] * Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN ---------------------------------------- Given a function that takes an argument and a block, the behavior wildly varies when parenthesis are omitted from the functions argument. Consider the following function: ~~~ruby require 'time' def example(arg) puts arg if block_given? puts yield else puts "no block" end end ~~~ Each of the following example sets presents one `example` call with parentheses explicitly defined and one whether the parenthesis are omitted. For most literals (e.g. 1, 'string', true, false, nil, %w[array]), missing parenthesis causes a syntax error. ~~~ruby example(1) { "block" } # 1 # block example 1 { "block" } # SyntaxError: syntax error, unexpected '{', expecting end-of-input ~~~ Array literals, however, succeed: ~~~ruby example([1]) { "block" } # 1 # block example [1] { "block" } # 1 # block ~~~ Identifiers are called as methods if parentheses are omitted: ~~~ruby example(Time) { "block "} # Time # block example Time { "block" } # NoMethodError: undefined method `Time' for main:Object a = 1 example(a) { "block" } # 1 # block example a { "block" } # NoMethodError: undefined method `a' for main:Object ~~~ Object with method calls simply skip the block when no parenthesis are present: ~~~ruby example(Time.now) { "block" } # 2015-05-15 18:16:50 -0400 # block example Time.now { "block" } # 2015-05-15 18:16:50 -0400 # no block ~~~ Method calls with arguments behave about the same as the above... ~~~ruby example(Integer(1)) { "block" } # 1 # block example Integer(1) { "block" } # 1 # no block ~~~ ...except `Time.parse` gets weird: ~~~ruby example(Time.parse('2015-01-01 0:00:00+00:00')) { "block" } # 2015-01-01 00:00:00 +0000 # block # => nil example Time.parse('2015-01-01 0:00:00+00:00') { "block" } # 0000-01-01 00:00:00 +0000 <---- Year 2000?! # no block # => nil ~~~ The lack of consistency across these use cases is extremely confusing and misleading. I'm of the opinion that parentheses omission should, in all cases, lead to a syntax error. -- https://bugs.ruby-lang.org/