[ruby-core:95582] [Ruby master Feature#16276] For consideration: "private do...end" / "protected do...end"
From:
ahodgkin@...
Date:
2019-10-29 20:38:56 UTC
List:
ruby-core #95582
Issue #16276 has been updated by adh1003 (Andrew Hodgkinson).
shevegen (Robert A. Heiler) wrote:
> > As noted in the pseudocode above, we can clean up some of the issues ar=
ound
> > the special syntax needed for "private constants", too.
> =
> I have no problem either way but I think "constants" is a bit of a misnom=
er
> in general. The ruby philosophy here is more that ruby allows you to chan=
ge
> it if you want to.
Agree with all you said and appreciate the detailed feedback - but on this,=
and in many ways on the use of `send`, those are workarounds for "I really=
know what I'm doing". Private methods are not normally callable by convent=
ional syntax, and constants pretty much are constants; attempts to redefine=
them raise warnings, so although it's possible it is, again, inadvisable a=
nd private scope constants _are_ a thing (and are useful).
The reason for public/protected/private is not just about what "can be done=
". It's about the contract you're drawing within your class or module, to w=
hich clients of that class or module must adhere. Public things are for any=
one; protected things for subclasses; private things are implementation. Th=
is is vital - no mere decoration - it goes to the very core of OOP and soft=
ware engineering. Calling `send`=A0 to hack into a private method means the=
caller is breaking the contract with the target entity and risks breaking =
at any time, since that entity is freely at liberty to change anything in i=
ts private implementation at any time.
duerst (Martin D=FCrst) wrote:
> > class Foo
> > def bla
> > end
> > private
> > def hop
> > end
> > end
> =
> This simply is sloppy coding [...left-indent "private"...]
Coding style wars wage often. Some of it is functional and objective, but m=
uch of it is aesthetic and subjective. The complaint about the coding style=
does not, I think, really change whether or not we might want to tighten t=
he behaviour of the public/protected/private declarations using block-like =
syntax in a manner that would be 100% backwards compatible with all existin=
g code (since the no-block syntax would still be there and not be deprecate=
d).
shyouhei (Shyouhei Urabe) wrote:
> - C++: There are `private`, but no `private {}`
> - Java: There are `private`, but no `private {}`
> - Scala: There are `private`, but no `private {}`
> - Kotlin: There are `private`, but no `private {}`
> - Rust: Everything are private by default, there is `pub` instead. But t=
here is no `pub {}`
> =
> Correct me if I'm wrong. But it seems the idea of "private with a block"=
isn't seen anywhere.
In those languages it's impossible (or extremely difficult, via complex ref=
lection programming) to call a private method as a client of the class, but=
in Ruby you just use `send` - not that you usually should. In most of thos=
e languages it's impossible (or again extremely difficult) to redefine a co=
nstant, but in Ruby you can do so easily (`const_defined?`, `remove_const`,=
`const_set`) - again, not that you should. All of those languages are stat=
ically, strongly typed, but Ruby is not. Things like C++ or Java are surely=
(in general) bad (or at best, difficult) places to look for syntax to copy=
, since they're generally hopelessly over complicated and require extremely=
heavy IDE support to make any kind of sense out of a typical code base. Ru=
by is typically far simpler and clearer; that's part of the reason why it w=
as made in the first place.
Ruby is its own language. Just because other languages don't do it, does no=
t mean Ruby would not benefit. And again, this is an _extension_ to the exi=
sting syntax, not a replacement.
----------------------------------------
Feature #16276: For consideration: "private do...end" / "protected do...end"
https://bugs.ruby-lang.org/issues/16276#change-82370
* 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:ruby-core-request@ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>