ChatGPT解决这个技术问题 Extra ChatGPT

What is Ruby's double-colon `::`?

What is this double-colon ::? E.g. Foo::Bar.

I found a definition:

The :: is a unary operator that allows: constants, instance methods and class methods defined within a class or module, to be accessed from anywhere outside the class or module.

What good is scope (private, protected) if you can just use :: to expose anything?

For the benefit of future googlers, if you're trying to search for a symbol, try symbolhound.com
Bless you, @AndrewGrimm. That is the best thing I've seen this week.

D
Derrell Durrett

:: is basically a namespace resolution operator. It allows you to access items in modules, or class-level items in classes. For example, say you had this setup:

module SomeModule
    module InnerModule
        class MyClass
            CONSTANT = 4
        end
    end
end

You could access CONSTANT from outside the module as SomeModule::InnerModule::MyClass::CONSTANT.

It doesn't affect instance methods defined on a class, since you access those with a different syntax (the dot .).

Relevant note: If you want to go back to the top-level namespace, do this: ::SomeModule – Benjamin Oakes


In C#, for instance, yes. On the other hand C++ (and Ruby) use :: for namespace resolution such as std::cout << "Hello World!";
Relevant note: If you want to go back to the top-level namespace, do this: ::SomeModule
@Benjamin The leading colons are implied, unless I happen to have a SomeModule inside another module and I want to get the top-level one instead, correct?
@Jo Yes. It can be helpful if you want to make sure you're referring to a constant at the top level namespace or a constant with the same name in another module (e.g. ::SomeOtherModule::ClassMethods).
This is very much like scope operand of C++
d
dimpiax

This simple example illustrates it:

MR_COUNT = 0        # constant defined on main Object class
module Foo
  MR_COUNT = 0
  ::MR_COUNT = 1    # set global count to 1
  MR_COUNT = 2      # set local count to 2
end

puts MR_COUNT       # this is the global constant: 1
puts Foo::MR_COUNT  # this is the local constant: 2

Taken from http://www.tutorialspoint.com/ruby/ruby_operators.htm


this is what causes the warning though. Is there a way to evade the warning?
@NullVoxPopuli Generally modifying constants is a really bad thing but if you for instance want to modify a constant in a badly written gem and do not want to fork it, it could be done by using .send(:remove_const) to the module that defines it, then redefining the constant.
m
mikej

:: Lets you access a constant, module, or class defined inside another class or module. It is used to provide namespaces so that method and class names don't conflict with other classes by different authors.

When you see ActiveRecord::Base in Rails it means that Rails has something like

module ActiveRecord
  class Base
  end
end

i.e. a class called Base inside a module ActiveRecord which is then referenced as ActiveRecord::Base (you can find this in the Rails source in activerecord-n.n.n/lib/active_record/base.rb)

A common use of :: is to access constants defined in modules e.g.

module Math
  PI = 3.141 # ...
end

puts Math::PI

The :: operator does not allow you to bypass visibility of methods marked private or protected.


So if one has class MyClass < ActiveRecord::Base, does that mean that MyClass only inherits methods from the class base and not anything inside the ActiveRecord module?
Why use the special double-colon for this namespace resolution rather than using the "." for this too? Context and capitalization would prevent confusion of meaning even if we were using the ".", wouldn't it?
@Jonah there are some cases where it would be ambiguous. e.g. consider class Foo; Baz = 42; def self.Baz; "Baz method!"; end; end (perfectly valid) Foo::Baz # => 42 and Foo.Baz # => "Baz method!". Note that Foo::Baz() (with parentheses) would also call the method though.
So the use case it solves it the ability to have class constant and a class method that have the exact same name? That doesn't seem like a strong argument in favor of the feature. Personally I'd much rather lose that ability (seems like trouble, anyway), lose the double-colon, and use "." for namespacing too.... Maybe there are additional use-cases it solves?
y
yfeldblum

What good is scope (private, protected) if you can just use :: to expose anything?

In Ruby, everything is exposed and everything can be modified from anywhere else.

If you're worried about the fact that classes can be changed from outside the "class definition", then Ruby probably isn't for you.

On the other hand, if you're frustrated by Java's classes being locked down, then Ruby is probably what you're looking for.


I've heard some rubyists say that instance variables aren't exposed, that even attr_accessor merely makes methods that modify the variable. (Then again there's instance_eval)
Correct, there's instance_eval. But there's also instance_variable_get and instance_variable_set. Ruby is just too dynamic for constraints.
Y
Yuri Ghensev

Adding to previous answers, it is valid Ruby to use :: to access instance methods. All the following are valid:

MyClass::new::instance_method
MyClass::new.instance_method
MyClass.new::instance_method
MyClass.new.instance_method

As per best practices I believe only the last one is recommended.


D
Daniel Viglione

Surprisingly, all 10 answers here say the same thing. The '::' is a namespace resolution operator, and yes it is true. But there is one gotcha that you have to realize about the namespace resolution operator when it comes to the constant lookup algorithm. As Matz delineates in his book, 'The Ruby Programming Language', constant lookup has multiple steps. First, it searches a constant in the lexical scope where the constant is referenced. If it does not find the constant within the lexical scope, it then searches the inheritance hierarchy. Because of this constant lookup algorithm, below we get the expected results:

module A
  module B
      PI = 3.14
      module C
        class E
          PI = 3.15
        end
        class F < E
          def get_pi
            puts PI
          end
        end
      end
  end
end
f = A::B::C::F.new
f.get_pi
> 3.14

While F inherits from E, the B module is within the lexical scope of F. Consequently, F instances will refer to the constant PI defined in the module B. Now if module B did not define PI, then F instances will refer to the PI constant defined in the superclass E.

But what if we were to use '::' rather than nesting modules? Would we get the same result? No!

By using the namespace resolution operator when defining nested modules, the nested modules and classes are no longer within the lexical scope of their outer modules. As you can see below, PI defined in A::B is not in the lexical scope of A::B::C::D and thus we get uninitialized constant when trying to refer to PI in the get_pi instance method:

module A
end

module A::B
  PI = 3.14
end

module A::B::C
  class D
    def get_pi
      puts PI
    end
  end
end
d = A::B::C::D.new
d.get_pi
NameError: uninitialized constant A::B::C::D::PI
Did you mean?  A::B::PI

This should be higher in the order of answers.
F
Francisco Soto

No, it is not to access every method, it is a "resolution" operator, that is, you use it to resolve the scope (or location you can say) of a constant/static symbol.

For example in the first of your line, Rails use it to find the Base class inside the ActiveRecord.Module, in your second one it is used to locate the class method (static) of the Routes class, etc, etc.

It is not used to expose anything, its used to "locate" stuff around your scopes.

http://en.wikipedia.org/wiki/Scope_resolution_operator


by "(static)" do you mean "(draw)"?!?
M
Mefitico

Ruby on rails uses :: for namespace resolution.

class User < ActiveRecord::Base

  VIDEOS_COUNT = 10
  Languages = { "English" => "en", "Spanish" => "es", "Mandarin Chinese" => "cn"}

end

To use it :

User::VIDEOS_COUNT
User::Languages
User::Languages.values_at("Spanish") => "en"

Also, other usage is : When using nested routes

OmniauthCallbacksController is defined under users.

And routed as:

devise_for :users, controllers: {omniauth_callbacks: "users/omniauth_callbacks"}


class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

end

M
Mongus Pong

It is all about preventing definitions from clashing with other code linked in to your project. It means you can keep things separate.

For example you can have one method called "run" in your code and you will still be able to call your method rather than the "run" method that has been defined in some other library that you have linked in.


F
Francesca Rodricks
module Amimal
      module Herbivorous
            EATER="plants" 
      end
end

Amimal::Herbivorous::EATER => "plants"

:: Is used to create a scope . In order to access Constant EATER from 2 modules we need to scope the modules to reach up to the constant


A
Aaquib Jawed

In simple it is a namespace, now namespace is container for modules, classes, function and other. and it also help to solve the problem name conflict. and in ruby you can access namespace by module like

module A
  class Article
     def Base
     end
  module B
  end
end

so to access the class Article we use A::Article. and in some cases you see that A::Article


b
bubbaspaarx

Reviving this thread a little. Can we create a 'ruby' name for this operator :: Surprised that we haven't already since we have splats, spreads, hash rockets etc.

Surely we can come up with something more fun than 'double colon' or 'unary operator'

Thinking

quad dot

four eyes

tetra dot

Nibble (half a byte - 4 bits)