09 Jul, 2009, Runter wrote in the 1st comment:
Votes: 0
Just thought I'd outline the use of Weakref class in Ruby. It will almost certainly be useful at some point to a mud developer—and none of my Ruby books mentioned it even.

So you may have came across a problem where you wanted to use references but didn't want to be responsible for having to unlink all the references if the object was removed from the Object Space. (Because the object wouldn't be removed from the Object Space until these references are all removed.)

An easy solution to this problem is a Weak Reference. These act as normal references in Ruby, however, as expected their existence won't prevent the garbage collector from doing its job. So when using weak references you simply check if they are still valid before accessing them. (If they aren't you have to handle that.) Using a weak reference after their dereferenced object has left the Object Space will result in an exception, which can also be rescued pretty easily.

str = "a string"              # we assign str a new object
wr = WeakRef.new(str) # Then create a weak reference to the same object.

str = nil # There are no longer any references to our object.
# So the garbage collector is now free to take it at any time even with a weak reference left.

### Now we order the garbage collector to work immediately.
ObjectSpace.garbage_collect
if wr.weakref_alive?
# This test tells us wr is valid
else
# Weak reference is indeed no longer valid.
end
09 Jul, 2009, David Haley wrote in the 2nd comment:
Votes: 0
As I said on IMC when I proposed these, I still it's a little nicer if the checking is done behind the scenes. If I want to test "actor.follower != nil", I don't really care if it's actually nil or a stale reference – I just want to get the answer. So I would probably wrap this, either using another class or some kind of function, so that you'd do something like actor.getFollower().
09 Jul, 2009, Runter wrote in the 3rd comment:
Votes: 0
David Haley said:
As I said on IMC when I proposed these, I still it's a little nicer if the checking is done behind the scenes. If I want to test "actor.follower != nil", I don't really care if it's actually nil or a stale reference – I just want to get the answer. So I would probably wrap this, either using another class or some kind of function, so that you'd do something like actor.getFollower().



Of course, and since we're talking Ruby here in specific you could wrap it with an accessor method.
09 Jul, 2009, David Haley wrote in the 4th comment:
Votes: 0
Yes, that would make it even more transparent. In Python, you would use properties, and in Lua, you would use the __index event of the metatable.
09 Jul, 2009, Runter wrote in the 5th comment:
Votes: 0
require 'weakref'
class Player
### define some accessors
def follower=(f)
@follower = WeakRef.new(f)
end

def follower
return false if @follower == nil

if @follower.weakref_alive?
@follower
else
false
end
end
end

### create 2 players
p = Player.new
p2 = Player.new

### p2 referenced as the follower of p1
p.follower = p2

### p2 is no longer valid
p2 = nil
ObjectSpace.garbage_collect

### p.follower returns false instead of the follower.
puts p.follower
09 Jul, 2009, Chris Bailey wrote in the 6th comment:
Votes: 0
Runter - It seems to me an excellent way of tying up loose ends, I'm currently recreating my implementation of several features to take advantage of this. What I'm wondering though are the repercussions of such an implementation. It seems too simple to just be the answer we were looking for. Does anyone with more knowledge than me know of a reason, or way, that this can be bad? Considering of course that the exceptions are properly handled and you take precaution to make sure you aren't using references to objects that have been accidentally cleaned up.
09 Jul, 2009, David Haley wrote in the 7th comment:
Votes: 0
Weak references are in fact extremely powerful tools; not many people know about them or understand them. Don't let the apparent simplicity fool you. :smile:

Sometimes the most elegant solutions are the ones that seem simplest.

I'm not saying that the solution is completely without problems, it's just that you shouldn't be thrown off by the relative simplicity. I can't write more now so will expand tomorrow if somebody hasn't by then.
09 Jul, 2009, Runter wrote in the 8th comment:
Votes: 0
For one thing you have to ensure the garbage collector has been invoked. Otherwise the reference could be valid after you intend it to be squashed.
09 Jul, 2009, Runter wrote in the 9th comment:
Votes: 0
flumpy said:
FYI the JVM also has weak references. You can use WeakHashMap or WeakReference objects to do the same thing.

Also, Java has another type of reference called a SoftReference, which is similar.

Here's java's definition of Strong, Weak and Soft types:

http://java.sun.com/j2se/1.4.2/docs/api/...
Quote
Reachability
Going from strongest to weakest, the different levels of reachability reflect the life cycle of an object. They are operationally defined as follows:

* An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it.
* An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.
* An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.
* An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.
* Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.


[edit]… interestingly phantom references can occur if you drop out of a scoped block within a method, and do not nullify your object reference. Phantom objects can be the cause of memory leaks if not looked out for !!


Sounds like a good post to go on the Java board. ;)
09 Jul, 2009, flumpy wrote in the 10th comment:
Votes: 0
Chris Bailey said:
Runter - It seems to me an excellent way of tying up loose ends, I'm currently recreating my implementation of several features to take advantage of this. What I'm wondering though are the repercussions of such an implementation. It seems too simple to just be the answer we were looking for. Does anyone with more knowledge than me know of a reason, or way, that this can be bad? Considering of course that the exceptions are properly handled and you take precaution to make sure you aren't using references to objects that have been accidentally cleaned up.


I think weak references should really only be used when being a "passive observer" of a system (like the follower example), tracking statistics etc rather than a way to design your system.

For example, in your world object (my registry) you need to make absolutely sure that when you dest an object it is removed, and not removed by something else. This should definitely be strongly referenced. That is a system designed to behave how you would expect: when you want to remove the object from the game, the object is forcibly removed by you. If you made your object world "weak", you may end up gc'ing the object in between the times you remove it from one strong reference and placing it into another (ie, when moving from room to room perhaps) - it's unlikely if you remove the object and then immediately put it into the next strong container, but it could happen. It will definitely happen a lot if you have weak inventory containers too tho.

I expect you *could* use weak references in inventory handling for rooms and players, so that you don't have to unlink it from their inventory when dest'ing. But I have not really made up my mind about this part. I expect I might be unhappy about losing control of whether or not the items need removing myself, and want the surety that they will not "disappear" before I have had a chance to do something with them, or hang around in the memory causing a leak.

The only certain scenario is if you are a passive bystander, observing objects and keeping an eye on whats going on. Anything else I wouldn't be happy with I think.
09 Jul, 2009, flumpy wrote in the 11th comment:
Votes: 0
Runter said:
Sounds like a good post to go on the Java board. ;)


ahh crud, this is the ruby board. sorry chaps. :S post deleted.
09 Jul, 2009, flumpy wrote in the 12th comment:
Votes: 0
… what I was trying to say earlier (god i really should drink more caffeine in the morning :() was that you shouldn't really use a Weak ref in situations where you "know" the life time of the objects you are tracking. Sorry for the ramble above :D
09 Jul, 2009, David Haley wrote in the 13th comment:
Votes: 0
Right, there's a difference between ownership and reference. A character can reasonably be said to "own" its inventory, but not so of the person it is following or the room it is in. It's the same conceptual problem you have in non-GC'ed languages like C++ where you need to decide who owns the pointer and therefore who is responsible for freeing it.

Regarding forcing the gc to be run, whether or not you want to do that at, say, the end of every main loop is up to your particular language implementation. It could be a fast process or a slow one. I think that Lua lets you disable automatic GC runs, so you could control it yourself if you wanted to. I imagine other languages might have similar features.

Still, it's not too bad to act on something that should be a "dead" character but is still floating around. At worst you might report that you're following somebody who has quit or something like that; it's unlikely to cause a "null pointer exception" or other kind of invalid memory exception (or the equivalent in the relevant language).
09 Jul, 2009, Runter wrote in the 14th comment:
Votes: 0
Quote
Still, it's not too bad to act on something that should be a "dead" character but is still floating around. At worst you might report that you're following somebody who has quit or something like that; it's unlikely to cause a "null pointer exception" or other kind of invalid memory exception (or the equivalent in the relevant language).


Not sure that's the worst case, but fair enough.

flumpy said:
… what I was trying to say earlier (god i really should drink more caffeine in the morning :() was that you shouldn't really use a Weak ref in situations where you "know" the life time of the objects you are tracking. Sorry for the ramble above :D

More true for some languages than others. I mean, yes, there are specific places it has uses and it doesn't make sense to use it in other places. Just keep in mind in Ruby you lose little/nothing to do it. So if there's any benefit it makes sense. They're technically the same thing as a reference (which everything has to be in Ruby).
10 Jul, 2009, Tyche wrote in the 15th comment:
Votes: 0
I think you'll be very disappointed if any of your game logic relies on the gc removing the object.
10 Jul, 2009, David Haley wrote in the 16th comment:
Votes: 0
Are Ruby's guarantees on what the GC does that weak? (no pun intended)

I agree that in general depending on the GC for game logic isn't a great idea, but I'm not sure where people were doing that here.
11 Jul, 2009, Tyche wrote in the 17th comment:
Votes: 0
David Haley said:
I agree that in general depending on the GC for game logic isn't a great idea, but I'm not sure where people were doing that here.


Oh I don't know whether they were or not. I'm just saying that while the "follower" example might appear to work correctly in a short bit of test code, I wouldn't rely on it being a solution to a problem like… "making sure when a player logs out everyone stops following them". References have a way of being held in unexpected places like on the stack, in lambas/procs, finalizers, and of course, the garbage collector is rather implementation specific. The only guarantee is the Weakref may be a candidate for collection, not that it will be.
11 Jul, 2009, Grimble wrote in the 18th comment:
Votes: 0
Tyche said:
I think you'll be very disappointed if any of your game logic relies on the gc removing the object.

I have no experience with Ruby, and wondered about this in the sample code when it forced garbage collection.

However, doesn't it make the utility of weak reference in Ruby rather questionable if it isn't cleared when the object it references is reset? I use weak and strong references in C++, and their deterministic behavior is crucial. One example is a timer that expires after the object it has a weak reference to has been deleted. In this case, nothing happens, but how would I ensure the same behavior with a weak reference in Ruby? It seems like a show-stopping limitation.
11 Jul, 2009, Tyche wrote in the 19th comment:
Votes: 0
Grimble said:
However, doesn't it make the utility of weak reference in Ruby rather questionable if it isn't cleared when the object it references is reset?


Oh that part is guaranteed. Maybe I should correct my last sentence:
"The only guarantee is the Weakref reference may be a candidate for collection, not that it will be. "

Grimble said:
I use weak and strong references in C++, and their deterministic behavior is crucial. One example is a timer that expires after the object it has a weak reference to has been deleted. In this case, nothing happens, but how would I ensure the same behavior with a weak reference in Ruby? It seems like a show-stopping limitation.


Yes the utility of Weakref is questionable, because there is no way to explicitly destruct an object.
C++ implementations of strong and weak smart pointers rely on the fact that the application can explicitly call an object's destructor.

The Weakref class itself is written in ruby. It defines a finalizer on the original object, and delegates all calls to that object it references via the object_id.
http://svn.ruby-lang.org/cgi-bin/viewvc....
12 Jul, 2009, David Haley wrote in the 20th comment:
Votes: 0
Incidentally this is why I prefer doing my own management on top of the weakref, where I can explicitly invalidate an object (by setting a 'valid' flag to false, for example), then making my own representation system that only returns a pointer if the object (a) exists and (b) has its 'valid' flag set to true. Then I use weakrefs on top of that, so that if something somehow isn't being invalidated it doesn't cause problems.
0.0/21