What is the real reason for Ruby class names being capitalised? - ruby

Ok, so everyone knows that capitalised identifiers are seen to be ‘constant’ in Ruby.
However, it is possible to assign a new value to constants, so the following works
class A
def self.hi; "hi"; end
end
class B
def self.hi; "ho"; end
end
A.hi # => "hi"
B.hi # => "ho"
A = B
# warning: already initialized constant A
# => B
A.hi # => "ho"
and also does assigning to a lowercase identifier work:
a = B
a.hi # => "ho"
However, the internal name is set to ‘B’ in all cases and the new identifier names are also only referencing ‘B’.
But if it’s technically okay for the identifier to have a lowercase name, why is this restriction on the internal name for the class? It can’t be that it needs to be constant, because it isn’t constant; so the other reason could be that lowercase identifiers have a different scope. But then: why not having a class with lowercase scope?
I’m wondering because the parser even allows for method names in unicode and such, so it seems strange that for classes it’s so much more restricted.

As you said, the name of a class is that of the first constant it has been assigned to. You can only use constants with the class keyword because it has been decided that the class keyword should only be used to create named classes.
The rationale probably being that allowing local variables would confuse uses, who would use class lowercase_class_name, not knowing the difference between lower case and upper case identifiers and then wonder why the classname was not visible everywhere (i.e. why def foo() lowercase_class_name.new end did not work).
By making the default way to create classes specific to constants, classes defined this way will be visible everywhere and there is at least a suggestion that the value associated with that name should not change (i.e. you get a warning otherwise).
People who know what they're doing can still do local_variable = Class.new { ... } if they need to.

The interpreter needs one way to find out if it is a Class name or a member variable of the current class/module.
The interpreter has to lookup class names in a global hash table while the member variables are in the class hash table. Local variables are different as they can be resolved by the interpreter without looking up hash tables at all (they have precedence over member variables).
And the only thing the interpreter knows about an identifier are the characters. Therefore there is the notational difference. Thats also the reason why global variables have a preceding $ and class variables an # character. For this the interpreter has other hash tables it has to search.
Other script languages have similar restrictions, for example PHP needs a dollar in front of each variable.

Related

Why we are using _ prefix in some cases to define instance variables in ruby?

I see in ruby classes some people using _ prefix to define instance variables like #_property while in normal condition attr_writer uses the normal name like #property to define instance variables.
What is the point of doing this and what is the difference?
The _ prefix isn't a language feature, it doesn't do anything special, it is just a convention.
In most cases, the developer wants to indicate that a variable is not in use, for example, a block variable that is not used in a block. Or they want to indicate that the variable is an internal variable of a module or gem and that others should not read or modify this variable directly.
There are 2 possible answers here depending on type of a variable.
Instance variable
When _ is used to prefix an instances variable (like in your question) it is usually just a convention to make it clear that that instance variable is private implementation detail and should not be used outside of the current scope. You might encounter it especially in modules which are to be included in some other classes - in which case the instance variable is defined and used by that module, but it belongs and is scoped to the object itself. I personally prefer object-scoped registries for this, but "private" instance variable is a quick, dirty and popular way to go. Alos, prefixing instance variable name with _ reduces chances of name conflict.
# Library code
module SomeExternalLibraryModule
def foo
#_something ||= SomeExternalLibraryModule::Something.new(self)
end
end
# Application code
class User
include SomeExternalLibraryModule
attr_reader :something # name conflict "avoided"! Phew!
def bar
#_something.do_sth
# "_" means - you'd better know what you're doing here!
# There is no guarantee that instance variable will be present in the future release
end
end
Local variable
When local variable is prefixed with _ this means that that variable is not being used in the code. It is especially useful when using iterators, or consuming other multi-element inputs of which you're interested in only one.
It is quite common to see just _ as a variable name. It has a bit of a special meaning for parser, which is you explicitly saying "I do not care what that is". As such, it is the only argument name that is allowed multiple time in a single definition:
def foo(_, _, a)
a
end
foo(1,2,3) #=> 3
def bar(a,a,b); end #=> SyntaxError
However, this is usually the best practice to use "I do not care" with a name, which will make your life easier in the future if you actually decide that you need to use other arguments:
def foo(_name, _html_options, options)
options.delete(:some_option)
super
end

Is this pattern considered idiomatic for declaring class options?

Is this pattern OK for declaring class level options? What is Options considered here? A class (class names start with a capital letter)? A constant? A normal variable inside the class?
class Markdown
Options = {
no_intra_emphasis: true,
fenced_code_blocks: true,
strikethrough: true
}
def initialize(text, options = {})
#text = text
#options = options.reverse_merge!(Options)
end
end
Whether it is usual or unusual does not matter. It is valid, and can be useful. It is a constant referring to a hash, not a class, nor a variable.
It is not that particularly a class name starts with a capital letter. A constant starts with a capital letter, of which a class name is a special case. But a capital does not necessarily mean a constant. Method names may or may not start with a capital.
As Options is a constant, I would rather use a name like OPTIONS, which is closer to Ruby convention (you can see that id uses names like File::Constants::APPEND, in http://www.ruby-doc.org/core-2.1.0/File/Constants.html). The way it is written now, it makes me think of a class rather than a constant.
Can you tell what it's doing and why within a few seconds of looking at it? If so, it communicates its point effectively, even if it is somewhat non-idiomatic. In this case, it looks like it defines some default values for #options, so it looks good to me - unless it does something else in the context of your overall program, in which case it's confusing because it does something besides what it looks like it's doing.
Also, Options is capitalized to indicate that should be treated as a constant and ideally shouldn't be changed at runtime. That's also why class names are usually capitalized: they are usually constants. (Ruby doesn't actually enforce this. It's a convention used to make it easier to tell what values shouldn't be changed without deliberately using metaprogramming techniques.)
The CSV library does this too; the constant is called DEFAULT_OPTIONS there.

Redundancy of notation in instance_variable_set, instance_variable_get

When I set or get instance variables using some name, for example #foo, I can do something like:
instance_variable_set("#foo", some_value)
...
instance_variable_get("#foo")
But often, I use a variable for the method name, which does not include the # prefix, so that I end up doing:
method = :foo
...
instance_variable_set("##{method}", some_value)
...
instance_variable_get("##{method}")
But since all instance variables are prefixed with #, I think it redundant to have to type "##{method}" instead of simply typing method. Why are the methods instance_variable_set and instance_variable_get not designed to accept string/symbol without # as its first argument like this:
method = :foo
...
instance_variable_set(method, some_value)
...
instance_variable_get(method)
where the variable to be actually set will be #foo rather than foo?
Is there any advantage with the way it is?
The reason is, quite simply, that the instance variable is named #foo, not foo. The # is part of the variable name, just as the $ is part of the global variable name $foo.
The reason that # is not necessary when calling attr_accessor and friends is because they define attribute methods, so it makes sense to provide the method names, not the variable names.
Of course there is no technical reason instance_variable_set cannot prepend the # itself. However, the method accepts a symbol that corresponds to the variable name. A symbol by definition represents the identifier with the given name. So the only symbol that corresponds to the instance variable #foo is :#foo. That is why you have to include the #, because we know that :foo does not correspond to any instance variable identifier at all. (And if you supply a string, it will be converted to a symbol internally first.)
Update: In the C Ruby implementation (MRI), there is actually no mention of # anywhere in the code that handles instance variables. Only the parser knows instance variables start with a #. So it seems that separating code parsing from implementation is another possible reason.

How do I define a setter for a property whose name ends with a question mark?

I'm trying to add a property called "enabled?" to a model with both a getter and a setter. However, when I do the following:
def enabled?= value
# .. logic goes here ..
end
I get syntax error, unexpected '?', expecting '\n' or ';'
What should I be doing instead?
Yes, ruby syntax only allows ? in method names if it's the last character, so foo?= is not valid. One thing you could do, that would be pretty idiomatic, is to define enabled?, enable and disable (or enable! and disable! if you want to emphasize that they're mutating methods).
If that doesn't fit your needs, you can just name the methods enabled? and enabled= and just live with the slight incosistency between the names.
A method name in ruby starts with a lower case letter or underscore optionally followed by upper and lower case letters underscores and digts. A method name may optionally end with a question mark, exclamation mark or equals sign.
So you can't!
You could follow the usual ruby idiom of defining enabled as follow :-
def enabled?
#enabled
end
def enabled=(value)
#enabled = value
end
To summarise. If you want to expose properties to the outside world then ensure your variable name will allow that within the confines of the rules for method names.
One small variation would be to alias the getter method, allowing both enabled and enabled?:
def enabled
#enabled
end
def enabled=(value)
#enabled = value
end
alias_method :enabled?, :enabled
Name your property just enabled
The query methods are just syntactic sugar, they are not mean to be used as properties or instance variables. You can add the method enabled? for syntactic sugar if you wish too.
I always name my boolean variables to start with 'is', as in 'isEnabled'. Then it has the same meaning as having the question mark w/o the need for complexity.

What does Ruby constant mean?

What does Ruby constants really mean? The following code doesn't show any 'constant' attribute. The warning is there, but I still get to change what A refers to.
A = 1
puts A # => 1
A = 2 # warning: already initialized constant A
puts A # => 2
Or is Ruby constants are just an indication without any enforcement?
That's right, constants are just like variables in ruby, but you get a warning if you change them.
Also, there's one difference with mere variables: You can access constants even if they are defined inside another class or module, for example given this snippet:
module Constants
PI = 3,1415
other = "variable"
end
You can reach PI doing Constants::PI while Constants::other will not work.
Yes, Ruby constants aren't enforced, other than printing that warning.
That's right -- assigning to a constant is a warning, not an error; "constants" are just an indicator of how you should use something, not a rule that you do use it that way.
That may sound horrendous coming from a static-programming world, but it's immensely useful in various metaprogramming facilities, and it enables things that would otherwise be completely impossible in static languages.
That said, if you really want to make sure people keep their grubby hands off your references, you can use Object#freeze. It's still okay to change what a reference points to with this; you just can't change the contents of the reference itself:
irb(main):001:0> class Fruit; attr_accessor :name; end
=> nil
irb(main):002:0> f = Fruit.new
=> #<Fruit:0xb7e06570>
irb(main):003:0> f.name = "apple"
=> "apple"
irb(main):004:0> f.freeze # After freeze, can't touch this Fruit.
=> #<Fruit:0xb7e06570 #name="apple">
irb(main):005:0> f.name = "banana"
TypeError: can't modify frozen object # Kablammo!
from (irb):5:in `name='
from (irb):5
But this is okay:
irb(main):006:0> f = Fruit.new
=> #<Fruit:0xb7dfed84>
irb(main):007:0> f.name = "banana"
=> "banana"
"Constant" is really a misnomer, the most important aspect of Ruby's "Constants" is not their immutability but their lookup rules.
see: http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/
Constants are used to store values that should not be changed. Their names must start with an uppercase letter. By convention, most constant names are written in all uppercase letters with an underscore as word separator, such as SOME_CONSTANT.
Constants defined within classes can be accessed by all methods of that class. Those created outside a class can be accessed globally (within any method or class).
class Car
WHEELS = 4
def initialize
puts WHEELS
end
end
c = Car.new # Output: 4
Note that Ruby does not stop us from changing the value of a constant, it only issues a warning.
SOME_CONSTANT = "foo"
SOME_CONSTANT = "bar"
warning: already initialized constant SOME_CONSTANT
warning: previous definition of SOME_CONSTANT was here
In Ruby, all class and module names are constants, but convention dictates they should be written in camel case, such as SomeClass.
Constants can be accessed from outside the class, even within another class, by using the :: (double colon) operator. To access the WHEELS constant from outside the Car class, we would use Car::WHEELS. The :: operator allows constants, public instance methods and class methods to be accessed from outside the class or module on which they are defined.
A built-in method called private_constant makes constants private (accessible only within the class on which they were created). The syntax is as follows:
class Car
WHEELS = 4
private_constant:WHEELS
end
Car::WHEELS # Output: NameError: private constant Car::WHEELS referenced
If you're coming from other programming languages, Ruby handles constants differently than what you may be used to. Constants, in general, take values that do not change through the entire application. The syntax is to use all capital letters while naming your constant so that the application knows how to handle it. For example, to set a constant to hold a baseball team you would declare it this way:
TEAM = "Angels"
I know you know this much, bear with me here. Typically, other programming languages will not allow you to change the value of TEAM. However, Ruby does not hold you back and takes the last value assigned to the constant. In the above example, I can change its value to:
TEAM = "Athletics"
Other programming languages would either throw an error or would print the value of Angels. However, Ruby prints the value Athletics because that is the last value assigned to the variable TEAM. Also, it gives a warning message that says that the constant was already initialized and was changed because changing a constant is considered a poor programming practice. But, it still allows you to make the change and follows the Ruby convention of trusting the developer to make the right programming decision. So, be careful while using constants in Ruby since they can be overridden.

Resources