This prints 1:
def sum(i)
i=i+[2]
end
$x=[1]
sum($x)
print $x
This prints 12:
def sum(i)
i.push(2)
end
$x=[1]
sum($x)
print $x
The latter is modifying the global variable $x. Why is it modified in the second example and not in the first one? Will this will happen with any method (not only push) of the class Array?
Variable scope is irrelevant here.
In the first code, you are only assigning to a variable i using the assignment operator =, whereas in the second code, you are modifying $x (also referred to as i) using a destructive method push. Assignment never modifies any object. It just provides a name to refer to an object. Methods are either destructive or non-destructive. Destructive methods like Array#push, String#concat modify the receiver object. Non-destructive methods like Array#+, String#+ do not modify the receiver object, but create a new object and return that, or return an already existing object.
Answer to your comment
Whether or not you can modify the receiver depends on the class of the receiver object. For arrays, hashes, and strings, etc., which are said to be mutable, it is possible to modify the receiver. For numerals, etc, which are said to be immutable, it is impossible to do that.
In the first snippet, you assign new local variable to hold result of $x + [2] operation which is returned, but it doesn't change $x (because + method doesn't modify receiver object). In your second snipped, you use Array#push method, which modifies an object (in this case, object assigned to $x global var and passed as i into your sum method) on which it's called.
i.push(2) appends 2 to the array pointed by i. Since this is the same array pointed by $x, $x gets 2 appended to it as well.
i=i+[2] creates a new array and set i to it - and now this is a different array than the one pointed by $x.
Related
I am new to ruby and lots of things are confusing me. I believe this specific one is from Sorbet which is some type checking library? not sure. This specific piece of code is right before a method declaration
sig { params(order: T::Hash[
String, T.any(
T.nilable(String), T::Hash[
String, T.any(
Integer, T.nilable(String)
)
]
)
]).returns(Types::Order) }
def self.build_prescription(prescription)
# method implementation
The order object is a json object coming from REST API. Can someone explain what this nesting thing is going on.
This is indeed a Sorbet signature. You can read more about Sorbet in their official documentation
The signature itself in this case is just describing the shape of the parameters and return type of the build_prescription method.
Slightly reformatting to make it easier to annotate:
sig { # A ruby method added by Sorbet to indicate that the signature is starting.
params( # Start to declare the parameters that the method takes
order: T::Hash[ # First param. In this case, it's a Hash...
String, # ... where they key is a String ...
T.any( # ... and the value can be either: ...
T.nilable(String), ... # a nilable String
T::Hash[ # or a Hash ...
String, # ... where the key is a String...
T.any(Integer, T.nilable(String)) # ... and the value is either an Integer or nilable string String
]
)
])
.returns(Types::Order) # Declaration of what the method returns
}
def self.build_prescription(prescription) # the regular Ruby method declaration
Note, though, that this will fail a Sorbet validation, as the signature declares the parameter as order, while the method declares it as prescription. Those two names should match.
There's a way to re-write this signature to make it a bit nicer to read/understand
sig do
params(
prescription: T::Hash[
String,
T.nilable(
T.any(
String,
T::Hash[String, T.nilable(T.any(Integer, String)]
)
)
])
.returns(Types::Order) # Declaration of what the method returns
}
def self.build_prescription(prescription)
Note that I'm moving the T.nilables out one level, as T.any(Integer, T.nilable(String)) means that same as T.nilable(T.any(Integer, String)) but it's more immediately obvious for a reader that the value can be nil
Since you are specifically asking about syntax, not semantics, I will answer your question about syntax.
What you see here, is called a message send. (In other programming languages like Java or C#, it might be called a method call.) More precisely, it is a message send with an implicit receiver.
A message is always sent to a specific receiver (just like a message in the real world). The general syntax of a message send looks like this:
foo.bar(baz, quux: 23) {|garple| glorp(garple) }
Here,
foo is the receiver, i.e. the object that receives the message. Note that foo can of course be any arbitrary Ruby expression, e.g. (2 + 3).to_s.
bar is the message selector, or simply message. It tells the receiver object what to do.
The parentheses after the message selector contain the argument list. Here, we have one positional argument, which is the expression baz (which could be either a local variable or another message send, more on that later), and one keyword argument which is the keyword quux with the value 23. (Again, the value can be any arbitrary Ruby expression.) Note: there a couple of other types of arguments as well in addition to positional arguments and keyword arguments, namely splat arguments and an optional explicit block argument.
After the argument list comes the literal block argument. Every message send in Ruby can have a literal block argument … it is up to the method that gets invoked to ignore it, use it, or do whatever it wants with it.
A block is a lightweight piece of executable code, and so, just like methods, it has a parameter list and a body. The parameter list is delimited by | pipe symbols – in this case, there is only one positional parameter named garple, but it can have all the same kinds of parameters methods can have, plus block-local variables. And the body, of course, can contain arbitrary Ruby expressions.
Now, the important thing here is that a lot of those elements are optional:
You can leave out the parentheses: foo.bar(baz, quux: 23) is the same as foo.bar baz, quux: 23, which also implies that foo.bar() is the same as foo.bar.
You can leave out the explicit receiver, in which case the implicit receiver is self, i.e. self.foo(bar, baz: 23) is the same as foo(bar, baz: 23), which is of course then the same as foo bar, baz: 23.
If you put the two together, that means that e.g. self.foo() is the same as foo, which I was alluding to earlier: if you just foo on its own without context, you don't actually know whether it is local variable or a message send. Only if you see either a receiver or an argument (or both), can you be sure that it is a message send, and only if you see an assignment in the same scope can be sure that it is a variable. If you see neither of those things it could be either.
You can leave out the block parameter list of you're not using it, and you can leave out the block altogether as well.
So let's dissect the syntax of what you are seeing here. The first layer is
sig {
# stuff
}
We know that this is a message send and not a local variable, because there is a literal block argument, and variables don't take arguments, only message sends do.
So, this is sending the message sig to the implicit receiver self (which in a module definition body is just the module itself), and passes a literal block as the only argument.
The block has no parameter list, only a body. The content of the body is
params(
# stuff
).returns(Types::Order)
Again, we know that params is a message send because it takes an argument. So, this is sending the message params to the implicit receiver self (which is here still the module itself, because blocks lexically capture self, although that is part of the language semantics and you asked strictly about syntax). It also passes one argument to the message send, which we will look at later.
Then we have another message send. How do we know that? Well, it takes an argument and has a receiver. We are sending the message returns to the object that was returned by the params message send, passing the expression Types::Order as the only positional argument.
Types::Order, in turn, is a constant reference (Types), the namespace resolution operator (::), followed by another constant reference (Order).
Next, let's look at the argument to params:
params(order: T::Hash[
# stuff
])
Here we have a keyword argument order whose value is the expression T::Hash[ … ]. T::Hash is of course again a constant reference, the namespace resolution operator, and another constant reference.
So, what is []? Actually, that is just another message send. Ruby has syntacic sugar for a limited, fixed, list of special messages. Some examples:
foo.call(bar) is the same as foo.(bar).
foo.+(bar) is the same as foo + bar. (And similar for *, **, /, -, <<, >>, |, &, ==, ===, =~, !=, !==, !~, and a couple of others I am probably forgetting.)
foo.+# is the same as +foo. (And similar for -#.)
foo.! is the same as !foo. (And similar for ~.)
self.`("Hello") is the same as `Hello`, which is somewhat obscure.
foo.[](bar, baz) is the same as foo[bar, baz].
foo.[]=(bar, baz, quux) is the same as foo[bar, baz] = quux.
So, this is simply sending the message [] to the result of dereferencing the constant Hash within the namespace of the object obtained by dereferencing the constant T, and passing two positional arguments.
The first positional argument is String, which is again a constant reference. The second positional argument is the expression T.any( … ), which is a constant reference to the constant T, and then sending the message any to the object referenced by that constant, passing two positional arguments.
The first argument is the expression T.nilable(String), which is dereferencing the constant T, sending the message nilable to the result of dereferencing the constant T, passing a single positional argument, which is the result of dereferencing the constant String.
The second argument is the expression T::Hash[ … ] … and I am going to stop here, because there is really nothing more to explain here. There's constants, message sends, and arguments, and we've seen all of those multiple times before.
So, to summarize, as to your question about syntax: the syntax elements we are seeing here are
message sends
arguments
constants
the namespace resolution operator (which is actually not really a separate syntax element, but simply one of many operators)
and a block literal
foo = 1
p +foo
This example code prints 1 just like if the + was not there. I know - in front of a variable gets the opposite of what the variable was (-29 becomes 29) but is there any case where a variable with a + in front of it ever does anything or can I safely remove it every time I see it? To clarify this a bit I am asking no specifically about numbers assigned to variables but any datatype in ruby.
+ is both a unary operator (one argument) and a binary operator (two arguments). It is defined on the Numeric class. Unary operators are defined using # suffix to differentiate from the binary operator.
Unary Plus—Returns the receiver.
This is the source for the method:
num_uplus(VALUE num)
{
return num;
}
So to answer your question,
Does + in front of a variable in ruby ever do anything?
NO, for Numeric values.
I just looked it up for strings and yes it does do something for frozen strings.
If the string is frozen, then return duplicated mutable string.
If the string is not frozen, then return the string itself.
static VALUE
str_uplus(VALUE str)
{
if (OBJ_FROZEN(str)) {
return rb_str_dup(str);
}
else {
return str;
}
}
is there any case where a variable with a + in front of it ever does anything
Yes. Every time. It calls the +# method.
or can I safely remove it every time I see it?
No, you can't. It will change the semantics of your code: before, it will call the +# method, after, it won't.
Whether or not that changes the outcome of your program, depends on what that method is doing. The default implementation for Numeric#+# simply returns self, but of course someone could have monkey-patched it to do something different.
Also, String#+# does something more interesting: if self is a frozen string, it will return an unfrozen, mutable copy; if self is already mutable, it returns self.
Other objects in the core library don't have a +# method, so they will usually raise a NoMethodError. If you remove the call, they won't; that is also a behavioral change.
Is there a method to overwrite variable without copying its name? For example, when I want to change my_var = '3' to an integer, I must do something like this:
my_var = my_var.to_i
Is there way to do this without copying variable's name? I want to do something like this:
my_var = something_const.to_i
For numbers there exists +=, -= etc, but is there universal way to do this for all methods ?
There is no way to covert a string to an integer like that, without repeating the variable name. Methods such as String#upcase! and Array#flatten! work by mutating the object; however, it is not possible to define such a method like String#to_i! because we are converting the object to an instance of a different class.
For example, here is a (failed) attempt to define such a method:
# What I want to be able to do:
# my_var = "123"
# my_var.to_i! # => my_var == 123
class String
def to_i!
replace(Integer(self))
end
end
my_var = "123"
my_var.to_i! # TypeError: no implicit conversion of Fixnum into String
...And even if this code were valid, it would still offer no performance gain since a new object is still being created.
As for your examples of += and -=, these are in fact simply shorthand for:
x += 1
# Is equivalent to:
x = x + 1
So again, there is no performance gain here either; just slightly nicer syntax. A good question to ask is, why doesn't ruby support a ++ operator? If such an operator existed then it would offer performance gain... But I'll let you research for yourself why this is missing from the language.
So to summarise,
is there universal way to do this for all methods?
No. The special operators like +=, -=, |= and &= are all predefined; there is no "generalised" version such as method_name=.
You can also define methods that mutate the object, but only when appropriate. Such methods are usually named with a !, are called "bang-methods", and have a "non-bang" counterpart. On String objects, for example, there is String#capitalize! (and String#capitalize), String#delete! (and String#delete), String#encode! (and String#encode), .... but no String#to_i! for the reasons discussed above.
I am in the midst of learning Ruby and thought I was clever with the following piece of code:
[#start,#end].map!{ |time| time += operation == :add ? amount : -(amount) }
where #start, #end are two module level variables, operation can be one of :add or :sub, and amount is an float amount to adjust both #start and #end by.
Granted it only saves me a line of code, but why doesn't this approach work, and how can I get something similar that does?
(My expected output is for #start/#end to be modified accordingly, however unit tests show that they stay at their original values.)
It's important in Ruby to remember the distinction between variables and the objects they hold. Simply setting a variable will never change the object referenced by that variable. When you do a += b, it's just shorthand for a = a + b. So you're assigning a new value to the variable a, not changing the object that used to be there or changing any other references to that object. So changing the variable time doesn't change #start.
In order to assign to an instance variable, you need to actually assign to that instance variable. Here's a way to do what you were looking for:
operation = :+
amount = 12
#start, #end = [#start, #end].map {|time| time.send(operation, amount)}
You'll notice that we're not faffing around with that :add and :sub business either — we can just pass the actual name of the message we want to send (I used + in this case, but it could be anything).
If you had a big, dynamically generated list of ivars you wanted to set, it's only a little bit more complicated. The only difference there is that need to get and set the ivars by name.
ivars = [:#start, :#end, :#something_else]
operation = :+
amount = 12
ivars.each {|ivar| instance_variable_set(ivar, instance_variable_get(ivar).send(operation, amount))}
The += operator changes the value of time but it returns the old value of time, therefore the right code is:
#start,#end = [#start,#end].map!{ |time| time + (operation == :add ? amount : -amount) }
EDIT
Updated the code to actually change #start and #end.
The addition operation in the block doesn't modify 'time', it returns a new value. So the elements in the array aren't modified, they're replaced.
If curly brackets ('{' and '}') are used in Lua, what are they used for?
Table literals.
The table is the central type in Lua, and can be treated as either an associative array (hash table or dictionary) or as an ordinary array. The keys can be values of any Lua type except nil, and the elements of a table can hold any value except nil.
Array member access is made more efficient than hash key access behind the scenes, but the details don't usually matter. That actually makes handling sparse arrays handy since storage only need be allocated for those cells that contain a value at all.
This does lead to a universal 1-based array idiom that feels a little strange to a C programmer.
For example
a = { 1, 2, 3 }
creates an array stored in the variable a with three elements that (coincidentally) have the same values as their indices. Because the elements are stored at sequential indices beginning with 1, the length of a (given by #a or table.getn(a)) is 3.
Initializing a table with non-integer keys can be done like this:
b = { one=1, pi=3.14, ["half pi"]=1.57, [function() return 17 end]=42 }
where b will have entries named "one", "pi", "half pi", and an anonymous function. Of course, looking up that last element without iterating the table might be tricky unless a copy of that very function is stored in some other variable.
Another place that curly braces appear is really the same semantic meaning, but it is concealed (for a new user of Lua) behind some syntactic sugar. It is common to write functions that take a single argument that should be a table. In that case, calling the function does not require use of parenthesis. This results in code that seems to contain a mix of () and {} both apparently used as a function call operator.
btn = iup.button{title="ok"}
is equivalent to
btn = iup.button({title="ok"})
but is also less hard on the eyes. Incidentally, calling a single-argument function with a literal value also works for string literals.
list/ditionary constructor (i.e. table type constructor).
They are not used for code blocks if that's what you mean. For that Lua just uses the end keyword to end the block.
See here
They're used for table literals as you would use in C :
t = {'a', 'b', 'c'}
That's the only common case. They're not used for block delimiters. In a lua table, you can put values of different types :
t={"foo", 'b', 3}
You can also use them as dictionnaries, à la Python :
t={name="foo", age=32}