Feature #7914

Case for local class methods

Added by Thomas Sawyer about 1 year ago. Updated about 1 year ago.

[ruby-core:52701]
Status:Open
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:next minor

Description

=begin
Here is a use case for local class methods.

Say we wish to give certain classes and all subclasses a special name.

class X
def self.special_name
"special:#{name}"
end
end
class Y < X; end
class Z < Y; end

Z.special_name #=> "special:Z"

But what if Y has a unique special name?

class Y < X
def special_name
'unique:Y'
end
end

Problem that arises:

Z.special_name  #=> "unique:Y"  # wrong!

Currently, to solve this would require creating an additional method, e.g. unique_name and redefine special_name to first look for unique_name then fallback to default special name if non-found. It works, but adds additional complexity to API.

Nicer solution would be local class methods.

class Y < X
  def special_name
    'unique:Y'
  end
  local :special_name
end

Y.special_name  #=> "unique:Y"
Z.special_name  #=> "special:Z"

The idea being that local class methods are skipped in super/lookup chain.

This idea is not without precedence. Module class methods can be thought of as being local. So this idea has other side of the notion, that modules could have class methods that are not skipped over in the super/lookup chain. In that case we would need a term that means opposite of local, so I'll use nonlocal:

module M
  def self.q; "q"; end
  nonlocal :q
end

class X
  include M
end

X.q  #=> "q"

=end

History

#1 Updated by Rodrigo Rosenfeld Rosas about 1 year ago

This doesn't seem to be supported by any OO concept I've heard about and basically breaks the conceptual inheritance model in OO in my opinion. I wouldn't like to have to debug a code that behaved like this. It would make understanding an existent code base much harder in my opinion. Don't you think so?

#2 Updated by Rodrigo Rosenfeld Rosas about 1 year ago

What about the code below?

class Y < X
def special_name
self.class.name == 'Y' ? 'unique:Y' : super
end
end

#3 Updated by Rodrigo Rosenfeld Rosas about 1 year ago

Maybe you could ask for some special method/keyword to know if the class is the same as the declared one (instead of some inheriting class):

def specialname
local
class? ? 'unique:Y' : super
end

Or instead of "local_class" you could ask if it has been called as a "super" method:

def specialname
called
by_super? ? super : 'unique:Y'
end

#4 Updated by Koichi Sasada about 1 year ago

  • Assignee set to Yukihiro Matsumoto
  • Target version changed from 2.1.0 to next minor

(I don't have any idea about this ticket. but I feel the name `local' recall perl)

#5 Updated by Nobuyoshi Nakada about 1 year ago

It seems trivial and usually avoidable.

I guess it could achieve with Module#using.

#6 Updated by Thomas Sawyer about 1 year ago

@rosenfeld Maybe I approached this backwards. I just wanted to show one possible use case for supporting local vs. non-local class methods. Your in-method conditional solution works for this specific case, true. But how well does it translate to other cases? For instance, it would not work with anonymous classes. calledbysuper is an interesting notion, but after some thought it feels like a make shift approach that only address part of the wider issue. The module non-local side of this is important too. And its use case is much more obvious --everywhere the included/ClassMethods hack is used.

#7 Updated by Yura Sokolov about 1 year ago

Thomas Sawyer, you are the language troll, IMHO.

(But, maybe I'm too)

Everyone else, excuse me for not being polite.
23.02.2013 12:17 пользователь "trans (Thomas Sawyer)" transfire@gmail.com
написал:

Issue #7914 has been updated by trans (Thomas Sawyer).

@rosenfeld Maybe I approached this backwards. I just wanted to show one
possible use case for supporting local vs. non-local class methods. Your
in-method conditional solution works for this specific case, true. But how
well does it translate to other cases? For instance, it would not work with
anonymous classes. calledbysuper is an interesting notion, but after some
thought it feels like a make shift approach that only address part of the
wider issue. The module non-local side of this is important too. And its
use case is much more obvious --everywhere the included/ClassMethods hack
is used.


Feature #7914: Case for local class methods
https://bugs.ruby-lang.org/issues/7914#change-36827

Author: trans (Thomas Sawyer)
Status: Open
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: next minor

=begin
Here is a use case for local class methods.

Say we wish to give certain classes and all subclasses a special name.

class X
def self.special_name
"special:#{name}"
end
end
class Y < X; end
class Z < Y; end

Z.special_name #=> "special:Z"

But what if Y has a unique special name?

class Y < X
def special_name
'unique:Y'
end
end

Problem that arises:

Z.special_name  #=> "unique:Y"  # wrong!

Currently, to solve this would require creating an additional method, e.g.
unique_name and redefine special_name to first look for unique_name
then fallback to default special name if non-found. It works, but adds
additional complexity to API.

Nicer solution would be local class methods.

class Y < X
  def special_name
    'unique:Y'
  end
  local :special_name
end

Y.special_name  #=> "unique:Y"
Z.special_name  #=> "special:Z"

The idea being that local class methods are skipped in super/lookup chain.

This idea is not without precedence. Module class methods can be thought
of as being local. So this idea has other side of the notion, that modules
could have class methods that are not skipped over in the super/lookup
chain. In that case we would need a term that means opposite of local, so
I'll use nonlocal:

module M
  def self.q; "q"; end
  nonlocal :q
end

class X
  include M
end

X.q  #=> "q"

=end

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

Also available in: Atom PDF