ARGV in Ruby: The Meaning of a Constant - ruby

I am new to Ruby, so please bear my questions in case they might not make any sense. My question is,
A constant is where we assign values that should not be altered. Why is ARGV a constant, when we can pass as many arguments as we want to in it? Are the arguments not the values for ARGV? When we pass arguments to ARGV, are we assigning values or does ARGV already have its own sets of values?

A constant has to have its value newly assigned at some point. If you take the meaning of constant as something that is never newly assigned its value, then there would be no constant at all. A constant is therefore, a relative notion; you cannot define what a constant is without the relevant domain/scope. A constant remains consistant within that domain, but has its value assigned/changed outside of the scope.
In mathematics, suppose some mathematician used a constant A = 3 at some point in their life solving a certain problem. That does not mean that everyone from that point on using the constant A would always have to assume its value to be 3. In mathematics, the domain of a constant can be a single proof, an article, a book, or a convention throughout a subfield, etc.
For a computer program, the domain for a constant is usually the execution lifespan of a program. A constant remains constant relative to the execution of the program. ARGV has its values set prior to the execution of the Ruby program.

The point is that ARGV has constant value for the entire time span your program runs. Another reason is that you are not supposed to change the value of ARGV. From the Wikipedia page titled Constant (computer programming):
[…] a constant is an identifier whose associated value cannot typically be altered by the program during its execution […]
Ruby is a bit special because it allows you to reassign ARGV (as any other constant), although it will issue a warning. The following is valid Ruby code (but please don’t do this):
ARGV = [123]
# warning: already initialized constant ARGV
p ARGV
# [123]

ARGV is a constant array that is defined on initialization of a Ruby script, in which the values in that array are set to the arguments which were passed in to the script itself.
From the ARGF documentation:
ARGF is a stream designed for use in scripts that process files given as command-line arguments or passed in via STDIN.
The arguments passed to your script are stored in the ARGV Array, one argument per element. ARGF assumes that any arguments that aren't filenames have been removed from ARGV
See the documentation for ARGV for more details.

Related

Ruby: Add value to Variable and Clamp/limit the Variable in one line

Suppose I have several arrays in Ruby which I add/subtract values and afterwards I limit their range, like so:
array[x][y]=array[x][y]+1
array[x][y]=array[x][y].clamp (0..99)
Since I have many different arrays with rather long (index) names - and in order not to repeat those names twice in one line, I'd like to achieve something like
array[x][y]+=1.clamp (0..99)
Which is accepted by the interpreter, but doesn't work. It adds, but the value in the array does not get clamped.
Splitting it in at least two lines
array[x][y]+=1
array[x][y].clamp(0..99)
does also add, but doesn't clamp.
Is there any solution for this to fit the entire command in one line?
Many thanks!
The #clamp method doesn't take a range as a single argument for Ruby versions before 2.7, but rather two arguments representing the min and max, and #clamp does not mutate the object it's called on.
array[x][y] = (array[x][y] + 1).clamp(0, 99)
Note that because it's valid to call a method without parentheses, if parentheses are used around an argument list, there should not be any space between the method name and the parentheses. E.g. 1.clamp(0..4) rather than 1.clamp (0..4).

Warning : previous definition of Variable was here - Ruby

Every single time I load my program, even for the fist time, it says
file.rb:9: warning: already initialized constant W_mum
file.rb:6: warning: previous definition of W_mum was here.
a little help here?
W_mum = gets.to_i
elsif (W_mum = 1)
Ruby uses two different "storage bins" for data: variables and constants. In your source code, you can identify them y their first letter: constants always have a capital letter at the start of their name, variables a lower-case letter.
In your case, you thus have a constant named W_mum. Now, when you first set a value to a constant and then later set a different value to it, Ruby will show a warning (as such: you can set new values to constants, but you should not).
Now, as for why Ruby warns here: in your elsif, you are actually assigning the constant the value 1. This might be a bug though. Instead of an assignment with =, you likely intended to use a comparison here, using the == operator.

What does :^ in reduce method mean?

I was doing a challenge on Code Wars where I was given an array "numbers" with several (sometimes repeating) integers and I had to return one unique integer. I passed the challenge but when I looked at all the previously submitted solutions, I noticed this reduce method:
def stray (numbers)
numbers.reduce(&:^)
end
I know what reduce method generally does but I haven't been able to find what the symbol ^ means. Could anyone please let me know its purpose?
The reduce method is used on arrays to combine all elements of that array into a single item.
The reduce method accepts a starting value and a block of code.
What you are using is a shorthand version of reduce which means the following:
numbers.reduce(&:^)
The & character will attempt to call the method on the argument itself when it is used as a last argument of a method call or definition. The ^ character signifies the bitwise XOR operator.
Inject is also an alias for reduce in Ruby.
You can read more here.

Ruby object variables and why they always equal the same name?

In the books I'm reading, I always see
def initialize (side_length)
#side_length = side_length
end
If the object variable always equals the variable with the same name why not write the language to just equal it without having to type it out?
For example:
def initialize (side_length)
#side_length # this could just equal side_length without stating it
end
That way we don't have to type it over with over.
In the example given:
def initialize(side_length)
#side_length = side_length
end
The #side_length = side_length is just an assignment, passing the available argument to an instance variable, in this case it happens to be the same name as the argument.
However those two values don't have to have same names - it's usually named that way for readability/convention reasons. That same code could just as easily be:
def initialize(side_length)
#muffin = side_length
end
The above code is perfectly fine, it just wouldn't read as well (and might slightly confuse someone giving it a first glance). Here's another example of the argument not being assigned to an instance variable of the same name.
It would be possible to write the language in a way which assumes that the argument variable should automatically be assigned to an instance variable of the same name, but that would mean more logic for handling arguments, and that same assumption may result in more restrictions for the developer, for example, someone who may actually want to assign side_length to #muffin for whatever reason.
Here's a SO question similar to this one - the accepted answer provides an interesting solution.
Hope this helps!
It is because "the object variable [does not] always [equal] the variable withthe [sic] same name".

Does the actual value of a enum class enumeration remain constant/invariant?

Given code for an incomplete server like:
enum class Command : uint32_t {
LOGIN,
MESSAGE,
JOIN_CHANNEL,
PART_CHANNEL,
INVALID
};
Can I expect that converting Command::LOGIN to an integer will always give the same value?
Across compilers?
Across compiler versions?
If I add another enumeration?
If I remove an enumeration?
Converting Command::LOGIN would look something like this:
uint32_t number = static_cast<uint32_t>(Command::LOGIN);
Some extra information on what I am doing here. This enumeration is fed onto the wire by converting it to an integer sending it along to the server/client. I do not really particularly care what the number is, as long as it will always stay the same. If it will not stay the same, then obviously I will have to provide my own numbers through the usual way.
Now my sneaking suspicion is that it will change depending on what compiler was used to compile the code, but I would like to know for sure.
Bonus question: How does the compiler/language determine what number to use for Command::LOGIN?
Before submitting this question, I have noticed some changes from say 3137527848 to 0 and back, so it is obviously not valid to rely on it not changing. I am still curious about how this number is determined, and how or why that number is changing.
From the C++11 Standard (or rather, n3485):
[dcl.enum]/2
If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one.
Additionally, [expr.static.cast]/9
A value of a scoped enumeration type can be explicitly converted to an integral type. The value is unchanged if the original value can be represented by the specified type.
I think it's obvious that the values of the enumerators can be represented by uint32_t; if they weren't, [dcl.enum]/5 says "if the initializing value of an enumerator cannot be represented by the underlying type, the program is ill-formed."
So as long as you use the underlying type for conversion (either explicitly or via std::underlying_type<Command>::type), the value of those enumerators are fixed as long as you don't add any enumerators before them (in the same enumeration) or alter their order.
As Nicolas Louis Guillemo pointed out, be aware of possible different endianness when transferring the value.
If you assign explicit integer values to your enum constants then you are guaranteed to always have the same value when converting to the integer type.
Just do something like the following:
enum class Command : uint32_t {
LOGIN = 12,
MESSAGE = 46,
JOIN_CHANNEL = 5,
PART_CHANNEL = 0,
INVALID = 42
};
If you don't specify any values explicitly, the values are set implicitly, starting from zero and increasing by one with each move down the list.
Quoting from draft n3485:
[dcl.enum] paragraph 2
The enumeration type declared with an enum-key of only enum is an
unscoped enumeration, and its enumerators are unscoped enumerators.
The enum-keys enum class and enum struct are semantically equivalent;
an enumeration type declared with one of these is a scoped
enumeration, and its enumerators are scoped enumerators. [...] The
identifiers in an enumerator-list are declared as constants, and can
appear wherever constants are required. An enumerator-definition with
= gives the associated enumerator the value indicated by the constant-expression. If the first enumerator has no initializer, the
value of the corresponding constant is zero. An
enumerator-definition without an initializer gives the enumerator the
value obtained by increasing the value of the previous enumerator by
one.
The drawback of relying on this, is that if the list order somehow changes in the future, then your code might silently break, so I would advise you be explicit.
Command::LOGIN will always be 0 as long as it's the first enum in the list. Just be careful with the rest of the enums, because they will have different binary representations based on if the computer is using big endian or little endian.

Resources