Issue #16276 has been updated by shevegen (Robert A. Heiler).


In general I agree with the proposal, or at the least with the basic gist o=
f it, e. g.:


private {
  do_stuff
}

public {
  do_stuff
}

I do not know how old private/public distinction is in ruby but I think mat=
z added
this very early on, perhaps even in the first public releases. I remember i=
n the
old pickaxe, it was explained that "private" and "public" are sort of typic=
ally
used as "toggling the state" that is - you write code, and then you may add
e. g. "private", and write all the code that is, well, private.

Personally I do not use the private and public distinction. This is mostly =
in the
way how you (as a ruby user) may want to use ruby. Some prefer a more java-=
centric
OOP model; perhaps this was a use case as to why .public_send() was added by
matz at a later time (I think .send() was much older than .public_send() but
I do not know when the latter was added). In my opinion, using .send and av=
oiding
private, is more "idiomatic", but this depends on the point of view. Person=
ally
I like the self/smalltalk view on OOP more than the C++/java view. Ruby has=
 its
own view, sort of; while I think the primary focus is on OOP, ruby has alwa=
ys
been multi-paradigm. I think matz likes to play with ideas and concepts. :)

But anyway, back to the suggestion. The reason why I am +1 for this proposa=
l,
even though I personally do not use that distinction really, is because I =

actually would find it convenient. I don't know if this may create incompat=
ibilites
or not, but purely from a convenience point of view, I think that would be a
good idea.

There are a few parts I disagree with your proposal though. For example,
you wrote:

> to have that protection level

I am not putting too emphasis here really, so excuse my nit-picking, but IM=
O ruby =

does not have a strong "protection" level because I think it would not be c=
ompletely
well aligned with ruby's philosophy of flexibility, more-than-one-way and i=
n general
letting people decide what they want to use it, and how. (Compare this to p=
ython in
many ways, which pursues a different model.) For example, we can use .send(=
) to =

"get access" to literally anything; we can obtain instance variable and cha=
nge them
if we want to. I love this dynamic nature. Others may dislike it, if they t=
hink
that ruby should be less dynamic. When you have "two sides", one saying tha=
t a
particular use case is bad, the other saying that it is good, it is difficu=
lt
to align them with the same thought, since these thoughts are orthogonal and
conflicting. I'd always reason in favour of .send() for example and never u=
se
.public_send() myself. :)

But I am a bit nit-picking here, so don't mind this comment too much.

> It is not idiomatic in Ruby to indent method definitions after such decla=
rations

I would not use the word "idiomatic", but I actually agree with you for ano=
ther
reason. Indenting code can be a bit annoying. Typically most people may tend
to use two spaces per indent level. I actually ignore that when I define cl=
asses
in modules, e. g.:

    module Foo
    module Bar
      class Cat

^^^ module Bar "should" be two spaces to the right, but I much prefer it to=
 the
very left, and then using just one indent for class. Now - I don't expect m=
any
other people to use this, but I liked it; and while this is not completely =
related
to the same use case and the description of the feature here, I concur with=
 you =

here. I actually never indent when private/public is used. Actually, I do s=
ometimes
use private, but I then use something crazy:

    def foo
    end; private :foo

This is more work but ... I like that I don't have to indent to the right. =
:P

So for this and similar reason, I actually agree with your premise mostly, =

even though I do not use the same argument(s).

> so it becomes at a glance very hard to see what a method's protection lev=
el
> is when just diving into a piece of source code.

Yup - I sort of agree with you here. Even though I guess we both may write
ruby code differently. :)

Makes sense to me what you write in this context.

> As noted in the pseudocode above, we can clean up some of the issues arou=
nd
> the special syntax needed for "private constants", too.

I have no problem either way but I think "constants" is a bit of a misnomer
in general. The ruby philosophy here is more that ruby allows you to change
it if you want to. Which I think makes sense, oddly enough; at the same =

time, I remember apeiros wondered about the name constant, and I sort of ag=
ree
because people may assume that "a constant may never change". Which is not =

wrong, either. Just more-than-one-way to look at something (perhaps it shou=
ld
have another name than constant, so people don't get confused).

This is also a bit strange when it comes to "private" constants in ruby. Can
these be changed? Should these be changed? Are there even really "private"
constants in ruby?

I actually really don't know. It has been rare that I used constants "dynam=
ically"
and changed them. These days I tend to use @foo toplevel instance variable =
more,
like:

    module Foo
      @bar =3D {}

and work from here IF it has to be dynamic (aka data that is to be changed =
for
some reason or another).

> Does the use of a block-like syntax imply we should support things like P=
rocs too? =


Aren't blocks in ruby in general procs too? But anyway, to answer the quest=
ion - I
don't think every method supports blocks uniformly strongly, meaning that s=
ome
methods make use of blocks more, and other methods don't. To me blocks are =
more
like an additional argument that is more flexible (usually). Sort of you ca=
n use
it if you want to - but you don't have to. So from here, I don't really see=
 a =

problem if private/public were to have a {} block variant.

There may perhaps be other issues, though, such as backwards incompatibilit=
y. I
guess this all has to be discussed and of course you have to ask matz about=
 the
design consideration for private/public. Perhaps there was a reason why the
block variant was not considered or used or there were some other problems.


----------------------------------------
Feature #16276: For consideration: "private do...end" / "protected do...end"
https://bugs.ruby-lang.org/issues/16276#change-82290

* 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>