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


> This is one of those change requests that I have thought about for
> a long time already but didn't request it because I thought it
> would not be accepted.

I may be wrong but I think that matz has indicated a possibility to
change the behaviour (for ruby 3.x, I assume, probably not in the
2.x branch). Perhaps it may not be accepted for 2.x, but I assume
that there may be a possibility for 3.x.

If I recall correctly - and this is mostly based on matz giving
presentations over the last ~4 years or so, also in particular 
the one about "good change, bad change" - matz said that there was
pain/problems/complaints in regards to the change between ruby 1.8.x
and  1.9.x leading up towards 2.x and he wants to avoid that when
possible.

And this may be one of the primary reasons why some changes may not
happen too quickly, if only to not avoid breaking a lot of code.

Though matz has also said that ruby 3.x can make backwards incompatible
changes, so there may be a possibility to see @@variables revisited.
It's not on my personal list of very important things, since I do not
use them - but I otherwise agree with Benoit. :) I think the main 
thing is that @@variables do not really provide a huge, compelling
advantage over other means to write ruby code. At the least I have
not found a situation where I would miss @@variables - in the past
I misused CONSTANTS to store data, until I found out that I could
use @foo variables too and use setters/getters on the module/class
level. :D

I think what may be useful in regards to any possibility to revisit
@@variables is if other (more) ruby hackers could add to the tracker
here whether they use class variables; and what their usage pattern
is for them. So far it seems as if those who commented here, do not
really use/need them.

It may be that almost nobody uses them these days, I have no idea :) -
but in the event that some day @@variables may be changed or 
removed, perhaps those who may be affected by it could comment; and
a transition path could be suggested for those who still use them.
Transition meaning such as a warning for deprecation and perhaps a
documentation explaining how to avoid having to use them or suggest
alternatives, in a doc at https://www.ruby-lang.org/en/. A bit
similar to the doc that explains the "Symbol versus String" situation
that has been added recently.

On the other hand, if not many ruby hackers complain about @@vars,
then perhaps this is an indication that class variables are not
really that much in use in the first place. In these cases, changing
or removing them may not affect many people. For example, to me the
two biggest problems from ruby 1.8.x and ruby versions past that 
were the encoding situation and the yaml->psych transition. These
days I am not affected that much by either, but back then it was
a lot harder to transition. (I am also trying to stay up to date
when it comes to ruby versions, so the xmas releases systematically
replace my current ruby.)

The upcoming ruby developer meeting at:

https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20180315Japan

will discuss it soon, so anyone who wants to chime in before
the meeting, please do so, no matter if you like or dislike,
use or don't use class variables.

----------------------------------------
Bug #14541: Class variables have broken semantics, let's fix them
https://bugs.ruby-lang.org/issues/14541#change-70927

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-01-29 trunk 62091) [x86_64-linux]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
Class variables have the weird semantics of being tied to the class hierarchy and being inherited between classes.
I think this is counter-intuitive, dangerous and basically nobody expects this behavior.

To illustrate that, we can break the tmpdir stdlib by defining a top-level class variable:

    $ ruby -rtmpdir -e '$SAFE=1; @@systmpdir=42; p Dir.mktmpdir {}'
    -e:1: warning: class variable access from toplevel
    Traceback (most recent call last):
    	3: from -e:1:in `<main>'
    	2: from /home/eregon/prefix/ruby-trunk/lib/ruby/2.6.0/tmpdir.rb:86:in `mktmpdir'
    	1: from /home/eregon/prefix/ruby-trunk/lib/ruby/2.6.0/tmpdir.rb:125:in `create'
    /home/eregon/prefix/ruby-trunk/lib/ruby/2.6.0/tmpdir.rb:125:in `join': no implicit conversion of Integer into String (TypeError)

Or even simpler in RubyGems:

    $ ruby -e '@@all=42; p Gem.ruby_version'
    -e:1: warning: class variable access from toplevel
    Traceback (most recent call last):
    	3: from -e:1:in `<main>'
    	2: from /home/eregon/prefix/ruby-trunk/lib/ruby/2.6.0/rubygems.rb:984:in `ruby_version'
    	1: from /home/eregon/prefix/ruby-trunk/lib/ruby/2.6.0/rubygems/version.rb:199:in `new'
    /home/eregon/prefix/ruby-trunk/lib/ruby/2.6.0/rubygems/version.rb:199:in `[]': no implicit conversion of String into Integer (TypeError)

So defining a class variable on Object removes class variables in all classes inheriting from Object.
Maybe @@systmpdir is not so prone to conflict, but how about @@identifier, @@context, @@locales, @@sequence, @@all, etc which are class variables of the standard library?

Moreover, class variables are extremely complex to implement correctly and very difficult to optimize due to the complex semantics.
In fact, none of JRuby, TruffleRuby, Rubinius and MRuby implement the "setting a class var on Object removes class vars in subclasses".
It seems all implementations but MRI print :foo twice here (instead of :foo :toplevel for MRI):

~~~ ruby
class Foo
  @@cvar = :foo
  def self.read
    @@cvar
  end
end

p Foo.read
@@cvar = :toplevel
p Foo.read
~~~


Is there any library actually taking advantage that class variables are inherited between classes? I would guess not or very few.
Therefore, I propose to give class variable intuitive semantics: no inheritance, they behave just like variables of that specific class, much like class-level instance variables (but separate for compatibility).

Another option is to remove them completely, but that's likely too hard for compatibility.

Thoughts?



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

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>