[ruby-core:95881] [Ruby master Feature#16276] For consideration: "private do...end" / "protected do...end"
From:
merch-redmine@...
Date:
2019-11-19 04:27:40 UTC
List:
ruby-core #95881
Issue #16276 has been updated by jeremyevans0 (Jeremy Evans).
Dan0042 (Daniel DeLorme) wrote:
> > - Possibility #3: renders SyntaxError. This requires a massive rewrite=
of our parser. Theoretically possible but not in practice.
> =
> I'm a bit curious about this. My understanding is that a Proc object is n=
ot created for every block. So it should be possible to know that `private{=
}` is called with a block while `private(&block)` is called with a Proc (a=
nd raise an error in the latter case).
It may be possible to know at runtime whether a literal block is passed or =
not (if not, that is probably an easier change to make). However, you can'=
t really know at parse time (SyntaxError is raised at parse time). Example:
```ruby
class A
class << self
alias priv private
end
priv do
def
end
end
```
> In `invoke_block_from_c_bh` (from vm.c) I can see `switch (vm_block_handl=
er_type(block_handler))` which seems to do exactly that: telling apart the =
types of block. So in the case of `private`, if `vm_block_handler_type` ret=
urns `block_handler_type_proc`, it would make sense to me to raise an error=
. Or quite possibly I'm misunderstanding something about how this all works.
Since you seem to be in doubt, you should attach a debugger and call with a=
literal block and call with a block passed via `&`, and see what the diffe=
rence is.
adh1003 (Andrew Hodgkinson) wrote:
> I'm just asking for a very Ruby-like, clear, simple syntax extension that=
makes it obvious when a bunch of things are collected inside a specific vi=
sibility scope, in passing cleaning up nasty messes like "private_class_met=
hod" and solving a couple of (minor) formatting wars in passing.
What you consider making obvious, others may consider clouding the differen=
ce between instance methods of the class and singleton methods on the class.
`private_class_method` is just a shortcut. Calling it a nasty mess implies=
`define_singleton_method` is also a nasty mess. If you always define metho=
ds as regular methods, you don't need `private_class_method`:
```ruby
class A
class << self
def public_singleton_method
end
private
def private_singleton_method
end
end
def public_instance_method
end
private
def private_instance_method
end
end
```
----------------------------------------
Feature #16276: For consideration: "private do...end" / "protected do...end"
https://bugs.ruby-lang.org/issues/16276#change-82718
* Author: adh1003 (Andrew Hodgkinson)
* Status: Open
* Priority: Normal
* Assignee: =
* Target version: =
----------------------------------------
Private or protected declarations in Ruby classes are problematic. The sing=
le, standalone `public`, `private` or `protected` statements cause all foll=
owing methods - *except* "private" class methods, notably - to have that pr=
otection level. It is not idiomatic in Ruby to indent method definitions af=
ter such declarations, so it becomes at a glance very hard to see what a me=
thod's protection level is when just diving into a piece of source code. On=
e must carefully scroll *up* the code searching for a relevant declaration =
(easily missed, when everything's at the same indentation level) or have an=
IDE sufficiently advanced to give you that information automatically (and =
none of the lightweight editors I prefer personally have yet to support thi=
s). Forcibly indenting code after declarations helps, but most Ruby develop=
ers find this unfamiliar and most auto-formatters/linters will reset it or,=
at best, complain. Further, the difficulty in defining private *class* met=
hods or constants tells us that perhaps there's more we should do here - bu=
t of course, we want to maintain backwards compatibility.
On the face of it, I can't see much in the way of allowing the `public`, `p=
rivate` or `protected` declarations to - *optionally* - support a block-lik=
e syntax.
```
class Foo
# ...there may be prior old-school public/private/protected declarations.=
..
def method_at_whatever_traditional_ruby_protection_level_applies
puts "I'm traditional"
end
private do
def some_private_instance_method
puts "I'm private"
end
def self.some_private_class_method
puts "I'm also private - principle of least surprise"
end
NO_NEED_FOR_PRIVATE_CONSTANT_DECLARATIONS_EITHER =3D "private"
end
def another_method_at_whatever_traditional_ruby_protection_level_applies
puts "I'm also traditional"
end
end
```
My suggestion here confines all `public do...end`, `protected do...end` or =
`private do...end` protections strictly to the confines of the block alone.=
Outside the block - both before and after - traditional Ruby protection se=
mantics apply, allowing one to add new block-based protection-enclosed meth=
od declarations inside any existing code base without fear of accidentally =
changing the protection level of any methods defined below the new block. A=
s noted in the pseudocode above, we can clean up some of the issues around =
the special syntax needed for "private constants", too.
I see a lot of wins in here but I'm aware I may be na=EFve - for example, a=
rising unanswered questions include:
* Is the use of a block-like syntax making unwarranted assumptions about wh=
at the Ruby compiler can do during its various parsing phases?
* Does the use of a block-like syntax imply we should support things like P=
rocs too? (I *think* probably not - I see this as just syntax sugar to prov=
ide a new feature reusing a familiar idiom but without diving down any othe=
r rabbit holes, at least not in the first implementation)
I've no idea how one would go about implementing this inside Ruby Core, as =
I've never tackled that before. If someone is keen to pick up the feature, =
great! Alternatively, if a rough idea of how it *might* be implemented coul=
d be sketched out, then I might be able to have a go at implementation myse=
lf and submit a PR - assuming anyone is keen on the idea in the first place=
`:-)`
-- =
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:[email protected]?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>