Now you're asking for the entire justification of my class to exist.
Say there is an algorithm you want to run where you are grouping things into a deeply nested set of categories. A nested hash referencing arrays is a good data structure for this. In PHP this is trivial (though not terribly efficient). In Ruby you have to deal with maintaining the hash. There are many ways to do it, but my SafeNestedHash class lets you do it with a concise, natural syntax. Perhaps if you have an aversion to using a library for this then you would define a pair of methods like key_exists?(hash, key_chain) and set_key(hash, key_chain). You could also monkey-patch hash to have those methods. You could also encapsulate the logic into an object that handles all the logic. Or (as you seem to suggest) you could let the interpreter throw an exception and then handle it with rescue, which IMO would be just a notch behind monkey-patching in terms of bad practice since exceptions should be for unexpected circumstances. I just happened to go with creating a class that abstracts this all away. Yes there is a bit of leakiness, but there is no monkey patching, and any other solution would require either ballooning the actual function with incidental accounting details, or else utilizing some other abstraction which would need to be used with the same understanding of its purpose, at which point it's just a matter of taste.
I think you're misinterpreting exceptions in so much that you feel they need to be unexpected. Say you have a list like [[1,2,3],[4,5,6]]. You could count each of the lists and loop through them individually, or you could create a recursive function that assumes a flat list and switches when an index error occurs:
def wtf(l, count=0):
cl = l[0]
try:
return wtf(cl[count:], count+1)
except IndexError:
# Reverse the list and start over
cl = l[::-1]
return wtf(cl, 0)
Hopefully that gets my point across. Basically, exceptions are very useful, and there is nothing wrong with expecting and catching their throws under certain circumstances.
Or I can just use my class and everything is a zillion times cleaner. I don't see why you're still arguing with me over this. My class is very clean and guaranteed to be compatible with all other code. Perhaps you got thrown by a previous commenter saying I "redefined nil?". But actually I did was define a nil? method on my internal UndefinedHash class, overriding the default Object implementation (ie. standard inheritance stuff, nothing dangerous).
I know you can do useful things with Exceptions when necessary. However I have to say unequivocably that using an exception in this case would be the worst possible idea. Why? Because the exception would be NoMethodError (ie. from nil[:key]). This equivalent to a NullException in Java, indicating all manner of generic logic errors that could have occurred anywhere within the stack.
If you looked at what I was actually doing, you might agree that SafeNestedHash is an incredibly useful abstraction. Hell, if it was written in PHP you could look at the algorithm and say, "wow, that's fast, elegant and readable." I'm not sure why you're so dead set that I'm doing something wrong, but you're just pulling this stuff out of thin air without any context.
Say there is an algorithm you want to run where you are grouping things into a deeply nested set of categories. A nested hash referencing arrays is a good data structure for this. In PHP this is trivial (though not terribly efficient). In Ruby you have to deal with maintaining the hash. There are many ways to do it, but my SafeNestedHash class lets you do it with a concise, natural syntax. Perhaps if you have an aversion to using a library for this then you would define a pair of methods like key_exists?(hash, key_chain) and set_key(hash, key_chain). You could also monkey-patch hash to have those methods. You could also encapsulate the logic into an object that handles all the logic. Or (as you seem to suggest) you could let the interpreter throw an exception and then handle it with rescue, which IMO would be just a notch behind monkey-patching in terms of bad practice since exceptions should be for unexpected circumstances. I just happened to go with creating a class that abstracts this all away. Yes there is a bit of leakiness, but there is no monkey patching, and any other solution would require either ballooning the actual function with incidental accounting details, or else utilizing some other abstraction which would need to be used with the same understanding of its purpose, at which point it's just a matter of taste.