From: shevegen@... Date: 2018-03-09T02:42:37+00:00 Subject: [ruby-core:86062] [Ruby trunk Bug#14541] Class variables have broken semantics, let's fix them 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 `
' 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 `
' 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: