[ruby-core:66121] [ruby-trunk - Bug #9907] Abbreviated method assignment with private attr_writer/attr_reader does not work.

From: headius@...
Date: 2014-11-06 16:41:14 UTC
List: ruby-core #66121
Issue #9907 has been updated by Charles Nutter.


I'm confused about how private dispatch against self should behave. I expected that *at least* all self.x calls would be considered private dispatch, but that's not the case.

For this code:

private
def foo; @a; end
def foo=(a); @a = a; end

puts begin; foo; rescue; 'foo failed'; else; 'foo worked'; end
puts begin; self.foo; rescue; 'self.foo failed'; else; 'self.foo worked'; end
puts begin; self.foo = 1; rescue; 'self.foo = 1 failed'; else; 'self.foo = 1 worked'; end
puts begin; self.foo += 1; rescue; 'self.foo += 1 failed'; else; 'self.foo += 1 worked'; end
puts begin; o = self; o.foo; rescue; 'o = self; o.foo failed'; else; 'o = self; o.foo worked'; end
puts begin; o = self; o.foo = 1; rescue; 'o = self; o.foo = 1 failed'; else; 'o = self; o.foo = 1 worked'; end

I have the following behavior with 2.2.0-preview1:

foo worked
self.foo failed
self.foo = 1 worked
self.foo += 1 worked
o = self; o.foo failed
o = self; o.foo = 1 failed

On 2.1, the self.foo += 1 case failed, which is the purpose of this bug.

However, I don't see why that case should pass and self.foo should fail. self.foo += must do an implicit self.foo call, meaning the "self" exception for private dispatch propagates through. It makes no sense that directly calling self.foo would produce an error and implicitly calling self.foo would not.

I would also argue that the "o" cases should pass as well, but I'm more concerned about the inconsistent spec change in this bug.

----------------------------------------
Bug #9907: Abbreviated method assignment with private attr_writer/attr_reader does not work.
https://bugs.ruby-lang.org/issues/9907#change-49831

* Author: Jörg W Mittag
* Status: Closed
* Priority: Normal
* Assignee: 
* Category: core
* Target version: current: 2.2.0
* ruby -v: ruby 2.2.0dev (2014-06-05 trunk 46357) [x86_64-darwin13]
* Backport: 2.0.0: REQUIRED, 2.1: DONTNEED
----------------------------------------
This looks like a hole in the specification:

~~~ruby
private def foo=(*) end
public  def foo; 0  end

self.foo =  42

self.foo += 42
# private method `foo=' called for main:Object (NoMethodError)

private :foo

self.foo += 42
# private method `foo' called for main:Object (NoMethodError)
~~~

There is an exception for `private` writers in the rule for private message sends, but apparently that exception needs to broadened so that it also works in the case of abbreviated assignments. I'm not entirely sure what this rule would be, but I don't think it would break backwards compatibility, since all situations that would work differently with the changed rule would currently raise a `NoMethodError` anyway.

The rule should be something like:

> * `private` methods can only be called without an explicit receiver.
> * An exception is made for method assignments, where the literal receiver `self` is also allowed in the assignee method expression.
> * This also applies to compound assignments: `self.foo ω= bar` shall *always* succeed if either or both of `foo` and `foo=` are `private`.



-- 
https://bugs.ruby-lang.org/

In This Thread

Prev Next