Why won't this Ruby each loop break? - ruby

I have the following code in one of my personal projects:
def allocate(var, value) # Allocate the variable to the next available spot.
#storage.each do |mem_loc|
if mem_loc.free?
mem_loc.set(var, value) # Set it then break out of the loop.
break
end
end
end
Each item in the storage array is an object that responds to free? and set. What I am trying to do is cycle through the array, looking for the next free (empty) object to set the variable to. My problem is, this just cycles through every object and sets them all. Am I using the break function incorrectly?
Testing it, I call the following:
store.allocate(:a, 10)
store.allocate(:b, 20)
So store[1] should be set to :b and 20. But when I output the contents, it's value is 10, as is the rest of the array.

I believe I have found the mistake, and it wasn't actually in the code above.
When I set up the storage array, I did like so:
#storage = [Memory_location.new] * 1000
Believing it would create 1000 different objects. What I think actually happened, was that it created 1000 references to the same object, so when I changed one of them, I changed all of them. I could prove this by using the puts method on two different array locations, with both of them returning:
#{Memory_location:0x2bc8b74}

Related

Ruby - function changes hash but not integer variable

I have a function that takes in some parameters including a hash and an integer variable and adjusts their value. The function alters the value of the hash to be used again, however the integer variable resets itself. I believe it's because it's altering a copy of that variable, but I wanted to know how I can change it fully. I've been reading things about proc's but unfortunately I can't seem to solve my issue.
My code is below:
def buyProducts(product, amount, balance, foods, myProducts)
totalPrice = foods[product] * amount
balance -= totalPrice
myProducts[product] = amount
puts "You bought some #{product}\n"
puts "Your remaining balance is $#{balance}\n"
puts "Your current inventory is #{myProducts}"
end
Here, myProducts is a hash which updates each time. balance however is not, thats set as 100 from the start. while the line "your remaining balance" does update, when the function is called again it resets to 100.
I appreciate this is a simple question but any help would be gratefully received!
Here's the key difference: you reassign [the local variable] balance, but not myProducts. Instead, you simply change state of myProducts. That's why these changes "survive" across invocations of the method: the object is the same, it just holds different content.
This is not possible with integers, because each integer is its own object and doesn't have any mutable state.
Your method will have to communicate the changes to the external state by, for example, returning new value of balance (it will then be the caller's responsibility to track/apply the new value). Or you could set an instance variable.

Why can't I overwrite self in the Integer class?

I want to be able to write number.incr, like so:
num = 1; num.incr; num
#=> 2
The error I'm seeing states:
Can't change the value of self
If that's true, how do bang! methods work?
You cannot change the value of self
An object is a class pointer and a set of instance methods (note that this link is an old version of Ruby, because its dramatically simpler, and thus better for explanatory purposes).
"Pointing" at an object means you have a variable which stores the object's location in memory. Then to do anything with the object, you first go to the location in memory (we might say "follow the pointer") to get the object, and then do the thing (e.g. invoke a method, set an ivar).
All Ruby code everywhere is executing in the context of some object. This is where your instance variables get saved, it's where Ruby looks for methods that don't have a receiver (e.g. $stdout is the receiver in $stdout.puts "hi", and the current object is the receiver in puts "hi"). Sometimes you need to do something with the current object. The way to work with objects is through variables, but what variable points at the current object? There isn't one. To fill this need, the keyword self is provided.
self acts like a variable in that it points at the location of the current object. But it is not like a variable, because you can't assign it new value. If you could, the code after that point would suddenly be operating on a different object, which is confusing and has no benefits over just using a variable.
Also remember that the object is tracked by variables which store memory addresses. What is self = 2 supposed to mean? Does it only mean that the current code operates as if it were invoked 2? Or does it mean that all variables pointing at the old object now have their values updated to point at the new one? It isn't really clear, but the former unnecessarily introduces an identity crisis, and the latter is prohibitively expensive and introduce situations where it's unclear what is correct (I'll go into that a bit more below).
You cannot mutate Fixnums
Some objects are special at the C level in Ruby (false, true, nil, fixnums, and symbols).
Variables pointing at them don't actually store a memory location. Instead, the address itself stores the type and identity of the object. Wherever it matters, Ruby checks to see if it's a special object (e.g. when looking up an instance variable), and then extracts the value from it.
So there isn't a spot in memory where the object 123 is stored. Which means self contains the idea of Fixnum 123 rather than a memory address like usual. As with variables, it will get checked for and handled specially when necessary.
Because of this, you cannot mutate the object itself (though it appears they keep a special global variable to allow you to set instance variables on things like Symbols).
Why are they doing all of this? To improve performance, I assume. A number stored in a register is just a series of bits (typically 32 or 64), which means there are hardware instructions for things like addition and multiplication. That is to say the ALU, is wired to perform these operations in a single clock cycle, rather than writing the algorithms with software, which would take many orders of magnitude longer. By storing them like this, they avoid the cost of storing and looking the object in memory, and they gain the advantage that they can directly add the two pointers using hardware. Note, however, that there are still some additional costs in Ruby, that you don't have in C (e.g. checking for overflow and converting result to Bignum).
Bang methods
You can put a bang at the end of any method. It doesn't require the object to change, it's just that people usually try to warn you when you're doing something that could have unexpected side-effects.
class C
def initialize(val)
#val = val # => 12
end # => :initialize
def bang_method!
"My val is: #{#val}" # => "My val is: 12"
end # => :bang_method!
end # => :bang_method!
c = C.new 12 # => #<C:0x007fdac48a7428 #val=12>
c.bang_method! # => "My val is: 12"
c # => #<C:0x007fdac48a7428 #val=12>
Also, there are no bang methods on integers, It wouldn't fit with the paradigm
Fixnum.instance_methods.grep(/!$/) # => [:!]
# Okay, there's one, but it's actually a boolean negation
1.! # => false
# And it's not a Fixnum method, it's an inherited boolean operator
1.method(:!).owner # => BasicObject
# In really, you call it this way, the interpreter translates it
!1 # => false
Alternatives
Make a wrapper object: I'm not going to advocate this one, but it's the closest to what you're trying to do. Basically create your own class, which is mutable, and then make it look like an integer. There's a great blog post walking through this at http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html it will get you 95% of the way there
Don't depend directly on the value of a Fixnum: I can't give better advice than this without knowing what you're trying to do / why you feel this is a need.
Also, you should show your code when you ask questions like this. I misunderstood how you were approaching it for a long time.
It's simply impossible to change self to another object. self is the receiver of the message send. There can be only one.
If that's true, how do bang! methods work?
The bang (!) is simply part of the method name. It has absolutely no special meaning whatsoever. It is a convention among Ruby programmers to name surprising variants of less surprising methods with a bang, but that's just that: a convention.

Sum array of numbers [duplicate]

This question already has answers here:
How to sum array of numbers in Ruby?
(16 answers)
Closed 8 years ago.
Q: Write a method, sum which takes an array of numbers and returns the sum of the numbers.
A:
def sum(nums)
total = 0
i = 0
while i < nums.count
total += nums[i]
i += 1
end
# return total
total
end
There has to be another way to solve this without using while, right? Anyone know how?
Edit: This is not an exam or test. This is a practice problem provided on github for app academy. They provide the question and answer as an example. I just read however that good programmers don't like to use while or unless, so I was curious if I could learn something to solve this problem a better way. Like with enumerable? (Noob at Ruby here, obviously..)
Also, I would love any walkthrough or methods that I should learn.. This question is also different because I am asking for specific examples using this data.
The usual way of doing that would be this:
def sum(nums) nums.reduce(&:+) end
which is short for something like this:
def sum(nums) nums.reduce(0) { |total, num| total + num } end
I see that Neil posted a similar solution while I was typing this, so I'll just note that reduce and inject are two names for the same method - Ruby has several aliases like this so that people used to different other languages can find what they're looking for. He also left off the &, which is optional when using a named method for reduce/inject, but not in other cases.
Explanation follows.
In Ruby you don't normally use explicit loops (for, while, etc.). Instead you call methods on the collection you're iterating over, and pass them a block of code to execute on each item. Ruby's syntax places the block after the arguments to the method, between either do...end or {...}, so it looks like traditional imperative flow control, but it works differently.
The basic iteration method is each:
[1,2,3].each do |i| puts i end
That calls the block do |i| puts i end three times, passing it 1, then passing it 2, and finally passing it 3. The |i| is a block parameter, which tells Ruby where to put the value(s) passed into the block each time.
But each just throws away the return value of the block calls (in this case, the three nils returned by puts). If you want to do something with those return values, you have to call a different method. For example, map returns an array of the return values:
[1,2,3].map do |i| puts i end
#=> [nil, nil, nil]
That's not very interesting here, but it becomes more useful if the block returns something:
[1,2,3].map do |i| 2*i end
#=> [2,4,6]
If you want to combine the results into a single aggregate return value instead of getting back an array that's the same size as the input, that's when you reach for reduce. In addition to a block, it takes an extra argument, and the block itself is also called with an extra argument. The extra parameter corresponding to this argument is called the "accumulator"; the first time the block is called, it gets the argument originally passed to reduce, but from then on, it gets the return value of the previous call to the block, which is how each block call can pass information along to the next.
That makes reduce more general than map; in fact, you can build map out of reduce by passing in an empty array and having the block add to it:
[1,2,3].reduce([]) do |a,i| a + [2*i] end
#=> [2,4,6]
But since map is already defined, you would normally just use it for that, and only use reduce to do things that are more, well, reductive:
[1,2,3].reduce(0) do |s, i| s + 2*i end
#=> 12
...which is what we're doing in solving your problem.
Neil and I took a couple extra shortcuts. First, if a block does nothing but call a single method on its parameters and return the result, you can get an equivalent block by prefixing &: to the method name. That is, this:
some_array.reduce(x) do |a,b| a.some_method(b) end
can be rewritten more simply as this:
some_array.reduce(x, &:some_method)
and since a + b in Ruby is really just a more-familiar way of writing the method call a.+(b), that means that you can add up numbers by just passing in &:+:
[1,2,3].reduce(0, &:+)
#=> 6
Next, the initial accumulator value for reduce is optional; if you leave it out, then the first time the block is called, it gets the first two elements of the array. So you can leave off the 0:
[1,2,3].reduce(&:+)
#=> 6
Finally, you normally need the & any time you are passing in a block that is not a literal chunk of code. You can turn blocks into Proc objects and store them in variables and in general treat them like any other value, including passing them as regular arguments to method calls. So when you want to use one as the block on a method call instead, you indicate that with the &.
Some methods, including reduce, will also accept a bare Symbol (like :+) and create the Proc/block for you; and Neil took advantage of that fact. But other iterator methods, such as map, don't work that way:
irb(main):001:0> [-1,2,-3].map(:abs)
ArgumentError: wrong number of arguments (1 for 0)
from (irb):1:in `map'
from (irb):1
from /usr/bin/irb:12:in `<main>'
So I just always use the &.
irb(main):002:0> [-1,2,-3].map(&:abs)
#=> [1, 2, 3]
There are lots of good online tutorials for Ruby. For more general information about map/reduce and related concepts, and how to apply them to problem-solving, you should search for introductions to "functional programming", which is called that because it treats "functions" (that is, blocks of executable code, which in Ruby are realized as Proc objects) as values just like numbers and strings, which can be passed around, assigned to variables, etc.
Probably the most idiomatic way of doing this in Ruby is:
nums.inject(:+)
. . . although this basically hides all the working, so it depends what the test is trying to test.
Documentation for Array#inject

ruby shorthand for conditionals, when to use instance variables and efficiency of looping through parsed xml versus storing as hash

I'm learning ruby and have a few questions about some code I wrote for a newbie challenge. Purpose of challenge is to find country with largest population from an xml document.
I've included my code below. Questions I have are:
Is there a way to avoid having to initialize the #max_pop variable (#max_pop=0)?
Is there shorthand for combining the entire conditional block into 1 line?
Do I have to use instance vars #max_pop, #max_pop_country? Got error without them.
Which is more efficient:
Loop through each country and check if pop > max_pop (approach in code below)
Create pop hash (pop[:country]) and then find country with highest pop
Is there hash method to return key value pair for largest element in hash (to do 4.1)?
Source Code:
#max_pop=0
doc.elements.each("cia/country") do |country|
if country.attributes["population"].to_i > #max_pop
#max_pop=country.attributes["population"].to_i
#max_pop_country=country.attributes["name"]
end
end
puts "country with largest pop is #{#max_pop_country} with pop of #{#max_pop}
I am not familiar with rexml, but you ought to be able to simplify everything to something like this:
max_pop_elem = doc.elements.enum_for(:each, "cia/country").max_by { |c| c.attributes["population"].to_i }
max_pop_country = max_pop_elem.attributes["name"]
max_pop = max_pop_elem.attributes["population"].to_i
Yes, see above.
Yes, see above.
No. You should use local variables instead of instance variables when possible.
Don't worry about efficiency of CPU time until you have a slow program. Then use ruby-prof. Until then, just worry about the efficiency of coding time (do things the easy way).
Yes, just do key, value = hash.max_by{|k,v| v}.
In general, if you are going to be iterating over things you should learn about Ruby's Enumerable module. I made a reference sheet for it here.

The scope is confusing

I am confused with the scope of a variable inside a block. This works:
f = 'new'
[1,2,3].each do |n| puts f * n end
#=> new newnew newnewnew
But this doesn't:
[1,2,3].each do |n|
a ||=[]
a << n
end
a
#=>a does not exsit!
Why is this? And please put some resource on this topic for me.
What's confusing?
In the first snippet f is created and then the each block is executed, which can see things outside itself (called enclosing scope). So it can see f.
In the second snippet you create a inside the block, and so its scope is that block. Outside the block, a doesn't exist.
When you refer to a name (a, for instance) ruby will go from the current scope outwards, looking in all enclosing scopes for the name. If it finds it in one of the enclosing scopes, it uses the value that name is associated with. If not, it goes back to the most local scope and creates the name there. Subsequent name lookups will yield the value tied to that name.
When a block ends, the names that were in that scope are lost (the values aren't lost, just the names; values are lost when the garbage collector sees that no more names (or anything) refer to that value, and the gc collects the value to reuse its memory).
If visualization is your thing, I find it helpful to think of scopes as a staircase, and at the beginning of a program, you are standing on the top step1. Every time a block is entered, you step down one step. You can see everything on the current step, and everything on steps above the one you're on, but nothing on the steps below. When you refer to a variable name, you look around on the step you're on to find it. When you see it, you use that value. If you don't see it, you look to the next step above the one you're on. If you see it, you use that value. You do this over and over till you've looked at the very top step but don't see that name. If this happens, you create the name on the step you are standing on (and give it a value, if you're looking it up for an assignment). The next time you look for that name, you'll see it on the step you're standing on, and use it there.
When a block ends, you step up one stair step. Because you can't see any names on the steps below, all the names on the step you were previously on are lost.
If that helps you, think of it that way. If not, don't.
1 Actually you're on the second step because you're not in global scope, but to use names from global scope, you have to use a $ at the beginning of the name. So in the staircase example, if the name you are looking for has an $ at the beginning, you look directly at the top step. If not, you don't look that far. However, this is kind of wrong, since all the stairs in the program would share the same top step, which is weird to think about.
map works much better:
a = [1,2,3].map do |n|
n
end
No need to declare a outside of the block.
It's simple, a variable defined inside a block is not visible outside (if this happened, we'd say the variable had leaked, and as the word suggests, this would be bad):
>> lambda { x = 1 }.call
=> 1
>> x
NameError: undefined local variable or method `x' for main:Object

Resources