16 Mar, 2010, Runter wrote in the 21st comment:
Votes: 0
flumpy said:
Runter said:
flumpy said:
I am guessing, but is rescue is like catching some kind of exception?


It's a specific exception I've defined to be associated with actions that can be taken by objects such as entering an exit.


Generally I would consider (in my own world, especially) an exception to be something, er, exceptional. Like if the exit was actually supposed to exist but somehow had been dereferenced for example. You know implicitly that an exit may not be able to be entered, so its not really an "exceptional" circumstance, you can handle it with logic, and probably should.

I wouldn't advocate doing it that way, but as I say, each to their own :D


Sounds like you are making up arbitrary rules for what an exception has to be.
16 Mar, 2010, KaVir wrote in the 22nd comment:
Votes: 0
Runter said:
I don't find doors to be important enough to merit their own object.

On a related note, I've been wondering about making 'locks' their own object. I guess that would work with or without doors - you could just attach the lock to an exit. But the locks could also be attached to chests, portals, furniture, chastity belts, cars, robots, cages, handcuffs, etc. The 'lock' class could then encapsulate the functionality for locking and unlocking it, picking it, breaking it, etc, factoring in different types of lock, traps, and so on.
16 Mar, 2010, Runter wrote in the 23rd comment:
Votes: 0
KaVir said:
Runter said:
I don't find doors to be important enough to merit their own object.

On a related note, I've been wondering about making 'locks' their own object. I guess that would work with or without doors - you could just attach the lock to an exit. But the locks could also be attached to chests, portals, furniture, chastity belts, cars, robots, cages, handcuffs, etc. The 'lock' class could then encapsulate the functionality for locking and unlocking it, picking it, breaking it, etc, factoring in different types of lock, traps, and so on.


This is an approach I took in the past. I probably wouldn't do it again unless I can find a compelling reason. Most players ignored it or it was the same difference to them. I think if someone really wanted to do all of those things you listed and be very detailed you'd need to model this. If not, it's just added complexity and more development time.

And the truth is I really didn't have that many locks in the game at the end of the day. This is partially for me why it didn't make a lot of sense.
16 Mar, 2010, KaVir wrote in the 24th comment:
Votes: 0
Well I already use locks in a number of places (although rather ironically I don't actually have keys or doors, just locks). It's grown beyond its original design, and the code has become a bit hacky as a result, so for me at least it would be nice to rework it into a more generic solution.
16 Mar, 2010, flumpy wrote in the 25th comment:
Votes: 0
Runter said:
flumpy said:
Runter said:
flumpy said:
I am guessing, but is rescue is like catching some kind of exception?


It's a specific exception I've defined to be associated with actions that can be taken by objects such as entering an exit.


Generally I would consider (in my own world, especially) an exception to be something, er, exceptional. Like if the exit was actually supposed to exist but somehow had been dereferenced for example. You know implicitly that an exit may not be able to be entered, so its not really an "exceptional" circumstance, you can handle it with logic, and probably should.

I wouldn't advocate doing it that way, but as I say, each to their own :D


Sounds like you are making up arbitrary rules for what an exception has to be.


Nope, at least not in my world as I said:

http://java.sun.com/docs/books/tutorial/... -
Quote
Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.


also this explains a bit more:

http://java.sun.com/docs/books/tutorial/...

Quote
Exceptions provide the means to separate the details of what to do when something out of the ordinary happens from the main logic of a program. In traditional programming, error detection, reporting, and handling often lead to confusing spaghetti code.



I'm not making this up.. I don't know about ruby but there it is.
16 Mar, 2010, David Haley wrote in the 26th comment:
Votes: 0
There was some discussion on this previous, here:
[link=post]21073[/link]
There, I argue against commands being methods on characters, mainly for data visibility and interface concerns.

I don't think it makes sense to have dude.move(room) although it feels natural to "tell" the dude to move to a room. The reason I do not like this is because the moving is not really operating on properties of the actor; it operates on properties in all kinds of other places (rooms, exits, other actors, triggers, etc.).
16 Mar, 2010, Deimos wrote in the 27th comment:
Votes: 0
Thanks for that link; it was a very interesting read. It doesn't sound like there was much of a consensus, though. I guess I had hoped that there would be more of a generally accepted design pattern in the community.
16 Mar, 2010, Runter wrote in the 28th comment:
Votes: 0
flumpy said:
stuff

I think your links are wrong. I don't know what this "java" is but I thought exceptions were only in C++.

Instead of getting into an argument with you about what is proper to do in Ruby maybe you should focus on disputing the actual difference in the approach I made.

You can just pretend the code was "corrected" by you. If it makes you feel better.
16 Mar, 2010, Deimos wrote in the 29th comment:
Votes: 0
I find that Java programmers love their conventions. Anything out of the box is the devil. :tongue:
16 Mar, 2010, David Haley wrote in the 30th comment:
Votes: 0
Speaking of conventions… there's an interesting article out there about Java being a kingdom of nouns. If you've written any non-trivial Java code, you will surely recognize some of the humor there. :wink:
16 Mar, 2010, Deimos wrote in the 31st comment:
Votes: 0
Quote
Brush your teeth? ToothBrusher(myTeeth).go().

Hahahaha. Classic.
16 Mar, 2010, shasarak wrote in the 32nd comment:
Votes: 0
Deimos said:
@Runter:
In the chain of events required to cast a spell, the following happens: A user issues a command. This input string gets passed up your network structure until it hits whatever's responsible for turning that string into a game-understandable command/event/whatever. Let's assume this is handled by a CLI class. Let's say the string was "cast refresh", and the CLI has now determined that this string needs to cast refresh on the issuing PC. A couple things could happen at this point, which is what I'm trying to figure out:

1) Our CLI calls "dude.cast(:refresh)" and washes its hands of any further processing. All processing is then under the control of the Dude class.
2) Our CLI calls "world.spell_manager.cast(dude,:refresh)" and washes its hands of any further processing. All processing is then under the control of the SpellManager class.
3) Our CLI handles the processing itself.

Your code above appears to be using #3, but you seem to advocating #1 in your explanation. So, I guess it seems confusing to me. Where, exactly, would your code be located? If it's in the CLI, then you're subscribing to #3, but if it's in the Dude, then I'm not sure how you got from interpreting the command into the Dude class. Certainly you aren't letting Dude interpret its own user input strings?

I wouldn't do any of those, exactly. I would handle it the same way I suggested handling movement: have a class whose function is to model the process of a spell being cast. Something else would do the necessary parsing to determine that the player is trying to cast a spell, which spell it is, and what the target is. You then create a new instance of SpellCast (or whatever it's called) and set its caster, target and spell property, and tell it to get on with it.

The Spellcast would then do things like:

- Check to see if the caster actually knows the spell in question
- Calculate how many mana points the spell will cost
- Determine whether the caster casts the spell correctly
- If he does, deduct points from his mana total
- Create and initialise a spell-effect object
- Apply the spell-effect to the target

The actual spell-effect would likely be a distinct class from both the spell and the SpellCast class. A Fireball spell might result in the creation of an instance of FireDamage, with the amount of damage derived from a value on the spell; you give the FireDamage object a target and tell it to get on with it. The FireDamage object invokes some kind of takeDamage() method on the target, passing in the type of damage (Fire) as one parameter. The target then determines how many hit points it actually loses by applying suitable modifying effects (e.g. because the target has 50% fire resistance).

So there isn't just one class involved, here, there are several, each of which has distinct responsibilities. So, for example, the class that determines whether or not the spell is cast successfully probably shouldn't be the same as the one that actually applies the effect of the spell to its target - SpellCast should not directly manipulate the target's hitpoints as a result of a fireball spell being cast. Similarly, a fire spell should not determine the precise effect on its target in terms of hitpoint reduction; it should tell the target "you've been hit for 30 unadjusted points of fire damage" but quite what the impact of that is on the target (e.g. whether the hit-point loss is increased or reduced because of vulnerability or resistance to fire magic) is something the target itself should determine.
16 Mar, 2010, Deimos wrote in the 33rd comment:
Votes: 0
shasarak said:
The Spellcast would then do things like:

- Check to see if the caster actually knows the spell in question
- Calculate how many mana points the spell will cost
- Determine whether the caster casts the spell correctly
- If he does, deduct points from his mana total
- Create and initialise a spell-effect object
- Apply the spell-effect to the target

Yes, this is the type of "overseeing of the process" that I'm referring to. On an atomic level, there would be several different classes involved in the process, but something has to organize all of this piecemeal logic into steps that actually perform the command. You advocate an instanced class for doing this. Is there a reason you would choose this over, say, a universal SpellManager class that handles casting for everyone? I guess I don't see the benefits.
16 Mar, 2010, David Haley wrote in the 34th comment:
Votes: 0
Instanced classes are obviously correct. See also:
MovementManager.new(playerObject.getMovementProxy()).go(targetRoom.getDestinationProxy())


EDIT:
Less facetiously, you would use an instanced class if there is some kind of state to store with respect to that particular transaction, that lives beyond the life of the transaction.
16 Mar, 2010, flumpy wrote in the 35th comment:
Votes: 0
Ok now we've all had a good chuckle at Java, there is actually a serious point to why I mentioned using exceptions for control flow:

1. As I first mentioned, in java there is a significant overhead in creating an exception over controlling with logic
2. I find that throwing them instead of handling logic makes the code harder to read
3. When you do not explicitly clamp down on what actually really is a program error over a situation you can predict it can get silly, and you can start throwing errors all over the shop. It's like goto, or break, or continue: just use them where you need to. And door control logic is not one of those places IMHO

But, laugh if you want. Java is kinda silly sometimes :)

Edit: read this blog post for a better explanation than I gave:here
16 Mar, 2010, David Haley wrote in the 36th comment:
Votes: 0
Different languages use exceptions different ways. The Pythonic way to get an element out of a map (dict), for example, is not to test if it's present and then get it, but to just get it and catch the KeyError that's raised if it's not present. Different languages have different overhead for exceptions; Java has overhead but IIRC less than C++, for example. So what might be silly in one language might be extremely appropriate in another.
16 Mar, 2010, Deimos wrote in the 37th comment:
Votes: 0
flumpy said:
Ok now we've all had a good chuckle at Java, there is actually a serious point to why I mentioned using exceptions for control flow:

1. As I first mentioned, in java there is a significant overhead in creating an exception over controlling with logic
2. I find that throwing them instead of handling logic makes the code harder to read
3. When you do not explicitly clamp down on what actually really is a program error over a situation you can predict it can get silly, and you can start throwing errors all over the shop. It's like goto, or break, or continue: just use them where you need to. And door control logic is not one of those places IMHO

But, laugh if you want. Java is kinda silly sometimes :)

1. I find that people tend to overestimate "overhead." Exceptions, even used to control logic flow, are not going to be prevalent enough to produce any kind of noticeable overhead.
2. I get that this basically boils down to personal preference, but I fail to see how it's harder to understand something like "catch ( DoorNotOpenException e )" than "if ( door.isOpen() == false )".
3. "Real" program exceptions are easily distinguishable by their not-a-user-defined-exception-ness. That, and their type and/or message.

Personally, I use exceptions in certain situations to control flow because I find that it allows you to handle the failure logic wherever you want to, rather than confining you to the calling method. If you have a method with several predictable failure points, you either have to return false from all of them and have the calling context be unaware why it failed, or you have to put the failure handling logic inside the method. Sometimes you want the failure logic handled differently under different circumstances which that method doesn't need to know about. I've yet to find anything outside of exceptions that's able to do this elegantly.



Edit: I should qualify #1 by saying "if you don't go crazy."
16 Mar, 2010, flumpy wrote in the 38th comment:
Votes: 0
1. wrong. 10 - 100x slower, when scaled up to a system handling 5000 concurrent users, could mean a very great deal slower.
2. No, its not personal preference. Exceptions should be used, as DH says, with explicit regard to the language being used.
3. I was not talking about "program" exceptions versus "user code" exceptions. I was distinguishing between a real exception use case (file cannot be found, out of memory when allocating, door reference being null) as opposed to program flow "conditional" errors (is the door open, does the file exist, is there enough memory?). Each of these conditions can be checked before performing a task, so the exception really is exceptional (i thought i had a door but now i don't, i tried to allocate memory i thought i had space for but now can't - oops).

I found a blog with benchmarks for ruby, the first results are bunkum but the second lot are all real:

http://www.simonecarletti.com/blog/2010/...
16 Mar, 2010, Deimos wrote in the 39th comment:
Votes: 0
flumpy said:
1. wrong. 10 - 100x slower, when scaled up to a system handling 5000 concurrent users, could mean a very great deal slower.

What MUD do you know with 5000 concurrent users? I'm pretty sure we're just talking in the context of MUDs here, not scalable enterprise applications.

flumpy said:
2. No, its not personal preference. Exceptions should be used, as DH says, with explicit regard to the language being used.

Be careful using the word "should". Several paradigms you take for granted in day-to-day coding started out being used for things they "shouldn't" have been used for. Besides which, "should" is a very good indicator of "personal preference", and you completely ignored the question, which was "why is it less readable?", not "what should exceptions be used for?"

flumpy said:
3. I was not talking about "program" exceptions versus "user code" exceptions. I was distinguishing between a real exception use case (file cannot be found, out of memory when allocating, door reference being null) as opposed to program flow "conditional" errors (is the door open, does the file exist, is there enough memory?). Each of these conditions can be checked before performing a task, so the exception really is exceptional (i thought i had a door but now i don't, i tried to allocate memory i thought i had space for but now can't - oops).

An "exception use case" is any case one uses an exception to handle. That's it. You're back to what people "should" and "shouldn't" use them for, and that's personal preference.

flumpy said:
I found a blog with benchmarks for ruby, the first results are bunkum but the second lot are all real:

http://www.simonecarletti.com/blog/2010/...


require "benchmark"

class ExceptionBenchmark

def begin(iter)
Benchmark.bmbm(10) do |bm|
bm.report("exception") { iter.times { test_exception() } }
bm.report("return") { iter.times { test_return() } }
end
end

def test_exception()
begin
method_one();
rescue Exception;
end;
end

def test_return()
if method_two() == false
end
end

def method_one()
raise Exception
end

def method_two()
false
end

end

bm = ExceptionBenchmark.new()
bm.begin(100_000)


Rehearsal ———————————————
exception 1.300000 0.130000 1.430000 ( 1.468609)
return 0.140000 0.050000 0.190000 ( 0.183466)
———————————— total: 1.620000sec

user system total real
exception 1.290000 0.160000 1.450000 ( 1.521496)
return 0.130000 0.050000 0.180000 ( 0.177468)


That's only a ~1.4 second variance across 100,000 iterations. That's a dump-truck load of unopenable doors, my friend.
16 Mar, 2010, Runter wrote in the 40th comment:
Votes: 0
I was hoping to avoid this type of petty arguing, but fine. We all know exceptions are costly. They're costly when they're thrown. In my example I was exception handling code entered. Not user input. What does this mean? It means we can expect the method call to be valid in the context of the code.

Why are benchmarks regarding exception handling dubious? Well, that blog you linked to was particularly dubious for other reasons, but putting that aside if we consider–as already established–only when an exception is thrown we pay that overhead if a vast majority of the calls do not raise an exception the overhead doesn't exist. Here's some code to prove it if you just don't believe it.

require 'benchmark'

def raises_somefin
raise
end

def raises_noffin

end

Benchmark.bm do |b|
b.report("When raised: ") do
100000.times do
begin
raises_somefin
rescue
next
end
end
end

b.report("No raise: ") do
100000.times do
begin
raises_noffin
rescue
next
end
end
end
end


standard output said:
user system total real
When raised: 1.130000 0.020000 1.150000 ( 1.193605)
No raise: 0.010000 0.000000 0.010000 ( 0.017503)


And yes, that would be a lot of unopened doors, but actually, in my example it would be a lot of locked doors. (Or doors that failed for some other reason, like I said.) It's a catch-all-uncommon-circumstance. It guards the user (the programmer writing the code). This isn't an unreasonable place to use it. I'm somewhat surprised that you've really taken it this far.
20.0/163