I am trying to write a Greedy Algorithm for a certain problem. Simplified it looks like this:
There's an object called Foo with an randomized attribute called value and a method that changes this value change_value in a way that depends on an integer input
class Foo
def initialize
value = rand(1,10)
end
def change_value(input)
#changes the value in a certain way
end
end
Now the Greedy Algorithmus just gets the new value of Foo for all possible inputs and return the best input.
foo = Foo.new
best_value = 0
best_input = 0
(1..inputs).each do |k|
temp_foo = foo.clone
temp_foo.change_value(k)
if temp_foo.value>best_value
best_value = temp_foo.value
best_input = k
end
end
Foo.change_value(best_input)
The code works nearly as intended. The big problem is that the change_value-method within the each-funtion alters the temp_foo and the foo. What do I need to change to makes those objects completly dependent of each other? I also tried .dub by the way.
I think #clone or #dup won't work because they will share a reference to #value inside Foo.
In any case, you can do it more readably by changing Foo#change_value so it doesn't actually mutate the object but returns a copy:
class Foo
def initialize(value = nil)
#value = value || rand(10)
end
def change_value(input)
# returns a new Foo instance
Foo.new(#value + 1)
end
def value
#value
end
end
Because you're copying data in any case, using an immutable object (Value Object) is more general than some kind of deep clone.
I assume you assign value to the instance variable #value in Foo#initialize not the local variable value.
I also assume you don't have a simple primitive like in your code above but rather another object that contains a pointer, otherwise you most probably would not have such problem. In other words, I assume your change_value method makes an operation that relies on the #value pointer, such as #value[key] = some_new_value and not pure assignment, such as #value = some_new_object. When your object gets copied with clone or dup, that particular pointer is being copied, instead of the underlying structure, and therefore any calls to temp_foo.change_value will result in changes to foo's underlying #value.
To avoid this, you need to duplicate the object #value refers to. There is a trick you can use with Marshal, as discussed in this post, but I recommend against it since it causes a great deal of overhead. Instead, I would define a deep_dup method, such as below:
class Foo
def deep_dup
# Either this
#value = #value.dup
# OR this, and define the method #deep_dup in the class of #value
# to dup its internal structure too:
#value = #value.deep_dup
end
end
Then instead of doing temp_foo = foo.clone do temp_foo = foo.deep_dup.
Related
Is there were a way to make an #property into a method with set and get, so, #property would call a method instead of returning an actual property, and #property = someval would also call a method instead of assigning to an actual property?
In my project, objects store values in a database. Consider this simple database module that stores records in memory. In my real life project it's a DBM like PostgreSQL:
module MyDB
RECORDS = {}
def self.create(pk)
RECORDS[pk] ||= {}
end
def self.set(pk, key, val)
return RECORDS[pk][key] = val
end
def self.get(pk, key)
return RECORDS[pk][key]
end
end
Objects have fields that are stored in that database. So, in this class, the species field is stored in and retrieved from the database:
class Pet
def initialize(pk)
#pk = pk
MyDB.create(#pk)
end
def species=(val)
MyDB.set #pk, 'breed', val
end
def species()
return MyDB.get(#pk, 'breed')
end
end
A simple use of the Pet class could look like this:
motley = Pet.new('motley')
motley.species = 'cat'
It works currently, but here's where I ran into an annoyance. I did something like this within the class:
def some_method(newval)
#species = newval
end
Then, when I ran the code I got this result:
motley.some_method 'whatever'
puts motley.species #=> cat
Then I realize that wasn't corrent and what I should have done is:
def some_method(newval)
self.species = newval
end
I think #species = newval makes sense. It feels like I'm setting a property of the object.
Is were a way to assign a method to the property, something like:
def :#species=(val)
return MyDB.set(#pk, 'breed', 'val')
end
def :#species
return MyDB.get(#pk, 'breed')
end
Is there a way to do such a thing? Should there be?
Is there a way to do such a thing?
No. In Ruby setter and getter methods are the way to get/set the internal state of an object. Instance variables are just lexical variables that are scoped to an instance.
Ruby is a language based on message passing and #foo = bar sends the message =, bar to the recipient that is the lexical variable #foo. If it called self##foo= instead that would break the entire model of the language.
Should there be?
Hell no.
Do we really need a completely new language feature just because you find it hard to remember to call self.foo= instead of #foo =? No.
Would this feature add anything to the language that cannot already be done? No.
Would it break existing code? Yes.
So basically, I'm trying to have different instances of the same object. I'm coming from java, and in java you can just use the new keyword and you're done. I tried "Digit.new" and the last assigned instance of that object changed all instances of that object
I've tried using the "self" keyword, but it just crashes my program.
n_one = Digit.new
n_two = Digit.new
n_three = Digit.new
n_four = Digit.new
am_pm = Digit.new
.
.
.
n_three.set_type 3
n_four.set_type 1
class Digit
##type = nil
#This will determine what strings will be returned
def set_type num
##type = num
end
end
What's expected is the type of n_three is 3 and n_four is 1. But n_one, two, three, and four are all 1.
To fill in what max said in comments:
The ## sigil defines a class variable (kind of like Java's static). Instance variables are identified by the # sigil. All of your objects have the same value because they are all sharing the same class variable.
set_type looks quite unRubyish in most cases. Java's convention of getFoo translates to just foo in Ruby, and setFoo to foo=. As in
def foo
#foo
end
def foo=(value)
#foo = value
end
Furthermore, obj.foo = bar is a syntactic sugar for obj.foo=(bar) (invoking the function foo= with argument bar), so the code looks natural (i.e. using a setter looks like assigning a variable).
attr_accessor :foo will make both of those methods for you. attr_reader :foo and attr_writer :foo make just the getter, or just the setter method. Thus, your code can be written as
class Digit
attr_writer :type
end
n_three = Digit.new
n_three.type = 3
which is identical to
class Digit
def type=(value)
#type = value
end
end
n_three = Digit.new
n_three.type=(3)
Of course, if you wish to read n_three.type, you will need to also define a getter (or replace attr_writer with attr_accessor in the first snippet). Note that you also do not need to initialize #type to nil, as it is the default value of an uninitialised instance variable. But you could initialise it in the initialize method.
Java conflates constructor and initialiser; in Ruby, the constructor is ::new (the class method we typically call to create new objects, which you almost never need to override); and the initialiser is #initialize (automatically called by the default constructor). You cannot initialise instance variables outside a method like you can in Java. So, the correct way to initialise an instance variable would be:
class Digit
attr_writer :type
def initialize(type)
#type = type
end
end
If you defined a setter, you could (and likely should) use self.type = type instead of #type = type.
I'm working through the "Pickaxe Book" and the author gives the following example as a technique for giving a module/mixin state without using an instance variable:
...the module could use a module-level hash, indexed by the current
object ID, to store instance-specific data...
module Test
State = {}
def state=(value)
State[object_id] = value
end
def state
State[object_id]
end
end
class Client
include Test
end
c1 = Client.new
c2 = Client.new
c1.state = 'cat'
c2.state = 'dog'
c1.state # => "cat"
c2.state # => "dog"
I am unclear on how this works exactly. In particular, object_id. How is the object_id method able to access the Client instance in this manner? I tried using length to see if it would index according to that, but I got:
NameError: undefined local variable or method `length' for #<Client:0x00000000ecc570>
I'd like to make sure I understand the principles of what's going on here.
How is the object_id method able to access the Client instance in this
manner?
The state=() method is inherited from the Test module when it is included. Included modules create an anonymous class that is inserted right above the including class in the inheritance chain.
This line:
c1.state = 'cat'
is equivalent to:
c1.state=('cat')
And when c1 calls state=(), inside the state=() method self will be equal to c1. Inside a def, self is equal to the object that called the method.
When you call a method with no receiver, then self is the implicit receiver. Inside state=():
def state=(value)
State[object_id] = value
end
the object_id() method is called with no receiver, so self becomes the receiver. As a result, the line:
State[object_id] = value
is equivalent to:
State[self.object_id] = value
which is equivalent to:
State[c1.object_id] = value
If Client includes Test, and c1 is a Client, then object_id is c1.object_id, inherited from Object. Each Ruby object is guaranteed a unique object_id. Not all objects are guaranteed to have length (and furthermore, many objects will have non-unique length, e.g. "f" and [8] share the length 1).
This isn't exactly a singleton, but it's close, so I imagine it's common. I have a class (Foo) in which instances correspond to external data structures with unique IDs. I want to ensure that no two instances of Foo can have the same ID - if a constructor is called with the same id value, the original Foo instance with that ID, and all the other values are simply updated. In other words, something like:
class Foo
def initialize(id, var1, var2)
if Foo.already_has? id
t = Foo.get_object(id)
t.var1 = var1
t.var2 = var2
return t
else
#var1 = var1
#var2 = var2
end
end
I can think of two ways to do this:
I could keep an array of all instances of Foo as a class-level variable, then calling foo_instances.push(self) at the end of the initialization method. This strikes me as kind of ugly.
I believe Ruby already keeps track of instances of each class in some array - if so, is this accessible, and would it be any better than #1?
??? (Ruby seems to support some slick [meta-]programming tricks, so I wouldn't be surprised if there already is a tidy way of doing this that I'm missing.
You can override Foo.new in your object, and do whatever you want in there:
class Foo
def self.new(id, var1, var2)
return instance if instance = self.lookup
instance = self.allocate
instance.send :initialize, var1, var2
return self.store(instance)
end
end
You can also, obviously, use a different class method to obtain the object; make the initialize method private to help discourage accidental allocation.
That way you only have one instance with every ID, which is generally much less painful than the pattern you propose.
You still need to implement the store and lookup bits, and there isn't anything better than a Hash or Array in your class to do that with.
You want to think about wrapping the things you store in your class in a WeakRef instance, but still returning the real object. That way the class can enforce uniqueness without also constraining that every single ID ever used remain in memory all the time.
That isn't appropriate to every version of your circumstances, but certainly to some. An example:
# previous code omitted ...
return store(instance)
end
def self.store(instance)
#instances ||= {}
#instances[instance.id] = WeakRef.new(instance)
instance
end
def self.lookup(id)
#instances ||= {}
if weakref = #instances[id] and weakref.weakref_alive?
return weakref.__getobj__ # the wrapped instance
else
return nil
end
end
In an Array subclass (just an array that does some coercing of input values) I've defined #concat to ensure values are coerced. Since nobody ever uses #concat and is more likely to use #+= I tried to alias #+= to #concat, but it never seems to get invoked. Any ideas?
Note that the coercing is actually always to objects of a particular superclass (which accepts input via the constructor), in case this code seems not to do what I describe. It's part of an internal, private API.
class CoercedArray < Array
def initialize(type)
super()
#type = type
end
def push(object)
object = #type.new(object) unless object.kind_of?(#type)
super
end
def <<(object)
push(object)
end
def concat(other)
raise ArgumentError, "Cannot append #{other.class} to #{self.class}<#{#type}>" unless other.kind_of?(Array)
super(other.inject(CoercedArray.new(#type)) { |ary, v| ary.push(v) })
end
alias :"+=" :concat
end
#concat is working correctly, but #+= seems to be completely by-passed.
Since a += b is syntactic sugar for a = a + b I'd try to overwrite the + method.