I’ve been unable to find this in searching. If it doesn’t exist, how do I approximate it?
Could you elaborate on what you mean? Maybe post some pseudo code.
def some_code(akey,aval)
if !defined?(ahash)
ahash=Hash.new(0)
anum = 1
end
puts "anum and ahash: #{anum} #{ahash}"
ahash[akey] += aval*anum
anum*=3
return ahash.sum { |k,v| v }
end
some_code(‘a’,4)
some_code(‘b’,6)
puts “Total of ‘a’ ‘b’ ‘c’: #{some_code(‘c’,10)}”
I’ve forgotten how to specify that I’m inserting code, so please excuse the formatting.
You use 3 apostrophes to delimit posted code.
I can’t see why this would be a problem… Can’t you just use an instance variable to maintain the state between calls?
Are you sure you don’t want a closure?
#! /usr/bin/env ruby
# frozen_string_literal: true
class MyFuncs
def self.get_num()
num = 0
Proc.new {|x| num += 1; num}
end
end
func2 = MyFuncs.get_num()
func3 = MyFuncs.get_num()
puts func2.call()
puts func2.call()
puts func2.call()
puts func3.call()
Thank you.
I will do that if it’s really necessary.
I’m an old lady whose first language was Fortran and I was hoping to avoid setting up a class…
I’m doing the problems in the Exercism Ruby Track purely for amusement, not aiming for mastery, but I’m glad that there are people out here to help.
The only exposure I had with Fortran was Problem Solving and Structured Programming in WATFIV(35 years ago). Still have the book.
Generally, changing variables outside the scope of a method is considered as bad practice.
If you want to handle a stativ-variable, why not use an instance var?
def ahash
if @ahash.nil?
@ahash=Hash.new(0)
anum = 1
end
@ahash
end
def ahash= val
@ahash = val
end
def some_code(akey,aval)
puts "anum and ahash: #{anum} #{ahash}"
ahash[akey] += aval*anum
anum*=3
ahash.sum { |k,v| v }
end
Hi @thelmalu,
As said, Ruby is object oriented, class is something you will use a lot
The difficulty here is you miss a concept: the scopes. I hope this post will help you:
“Variable Scope and Visibility”.
To summarize, you have 4 scopes in Ruby:
- Global: variable start with ‘$’. Visible across all your application. Be aware than constants (start with a capital) are global. If you wonder why a class or module start with a capital, it’s because Ruby assign it to a constant.
- Instance: variable start with ‘@’. Visible into a living object (as an instance of a class).
- Locale: any other variables. Only visible within the current context.
The last is the class variable, start with ‘@@’ and can be a nightmare because its use-case is special. Don’t use it for now.
Okay, now your example.
You try to reuse a locale variable into your method. But this variable will be gone when the method returns. You will create a new local variable for each call.
The best solution for you is to use an object to track the content of your “ahash” and “anum” values.
If you think an object is overkill for you, you can use an anonymous function. Perhaps it’s a bit premature to introduce you to this, but it’s really a simple concept. We call it a “lambda”.
The advantage of a lambda is than you have the same rule as with a method but a lambda live in the context of where it was created. So, you can access any variable declared beforehand.
Because lambda is an object, you can’t call it directly as with a method. You must use “.call” to fire the code into it.
Ready for a try? Open an irb console and copy-past the code:
ahash = Hash.new(0)
anum = 1
some_code = lambda do |akey, aval|
puts "anum and ahash: #{anum} #{ahash}"
ahash[akey] += aval*anum
anum*=3
ahash.sum { |k,v| v }
end
Now, test our code. Don’t foget a lambda (or a proc) need to use the method call
:
some_code.call("a", 4)
# anum and ahash: 1 {}
# => 4
some_code.call("b", 6)
# anum and ahash: 3 {"a"=>4}
# => 22
ahash
# => {"a"=>4, "b"=>18}
That’s it.
But the most usual way is to play with object. It’s not much efforts:
class MyObject
def initialize
@ahash = Hash.new(0)
@anum = 1
end
def some_code(akey, aval)
puts "anum and ahash: #{@anum} #{@ahash}"
@ahash[akey] += aval*@anum
@anum*=3
@ahash.sum { |k,v| v }
end
end
And play with it:
my_object = MyObject.new
my_object.some_code("a", 4)
# anum and ahash: 1 {}
# => 4
my_object.some_code("b", 6)
# anum and ahash: 3 {"a"=>4}
# => 22
It’s ok too. What is the internal state of your object?
puts my_object.inspect
# <MyObject:0x000055984d84e690 @ahash={"a"=>4, "b"=>18}, @anum=9>
Keep in mind than any method / lambda / proc / block will return the last expression. No need to explicitly use
return
because your last line will always return.
Have enjoy in your coding
Thank you. This is very clear and helpful. I knew about lambda, but didn’t realize it could be used in this way.
I will, however, take everyone’s advice, and create a class object. Otherwise, what I’m really doing is trying to reduce Ruby to an emulation of my mid-1960’s Fortran.
Maybe this will help? In this code I’m using readline instead of the gets method for a basic repl.
CODE:
require ‘readline’
def phase_color(circuit)
a = circuit.to_i % 6
if a == 0
puts “blue/yellow”
end
if a == 1
puts "black/brown"
end
if a == 2
puts "black/brown"
end
if a == 3
puts "red/orange"
end
if a == 4
puts "red/orange"
end
if a ==5
puts "blue/yellow"
end
if a == 6
puts "blue/yellow"
end
puts a
end
This method is very basic. I had to use multiple if statments because I used dcoder on my phone.
This program I made to help me identify phase colors in the American standard. The formula is simple. The circuit number divided by 6. I don’t need anything but the remainder. So circuit.to_i % 6 will divide my input number and only return the remainder value.
The second half of the code:
while input = Readline.readline("circuit number: ")
phase_color(input)
exit(0)
break if input == “exit”
end
This part of the code gives the user a prompt. This case, a numeric input. It takes the user input and updates the circuit argument for phase_color, then runs the algorithm within the a variable of the method. Depending on the return of variable a, the if statement that is true will be returned.