09 Aug, 2010, JohnnyStarr wrote in the 1st comment:
Votes: 0
I noticed in CoffeeMud that it really takes advantage of classes for individual Mobs. Instead
of creating a generic Mob class, it creates a new class for the Mob itself. My vision for Ruby
might look like:

class AngryOgre < Ogre
def initialize()
super
set :name = "an angry ogre"
set :short = "An angry ogre is here."
set :level = 30
end
end

# the reset could just be a string used with eval
# in specific room.rb:
def room_update()
reset = "@mobs << AngryOgre.new"
total = 5
total.times {eval reset}
end


What's nice about this to me, is it takes advantage of scripting much like LPC.
Any ideas? What are your thoughts about using this for rooms too?
09 Aug, 2010, Runter wrote in the 2nd comment:
Votes: 0
My plan for coralmud is not file based. It'll use editor fields and it won't use the headers. Code in specific places will have understood scope. I think this I'd far easier to use. Oh, also sandboxed.
17 Aug, 2010, JohnnyStarr wrote in the 3rd comment:
Votes: 0
Not sure if this was brought up before, but I've discovered a way to implement modules as interfaces.
Well, dynamic typing makes it to where you don't really need interfaces, but at the same time it's nice to have them.

I've seen some of Runter's posts where you can use mix-in modules and use case-when constructs. But, personally, I
feel that because modules implement the methods, it sort of makes objects less encapsulated. Since you may override
method names in Ruby, it might makes sense to do:

module Consumes
def eat(food)
bug = "Method not implemented exception!"
raise bug
log.bug bug
end
end

# then in the class
class Character
include Consumes

def eat(food)
hp += food.hp_value
end
end


This way, you HAVE to override the method in order not to raise an exception.
17 Aug, 2010, Chris Bailey wrote in the 4th comment:
Votes: 0
Interesting idea, but wouldn't proper specs and tests kind of remove that need?
17 Aug, 2010, JohnnyStarr wrote in the 5th comment:
Votes: 0
Interfaces in Ruby aren't needed really at all. The only downside to mix-ins is that as you include the implementation
of the methods, you are potentially breaking encapsulation. I am aware that by overriding methods when necessary this is
avoided. For instance, if a Mob and a Player mix-in Moveable, yet players are also added to the rooms player
list, this would be an issue:
module Moveable
def on_move()
@in_room.characters << self
# still needs to take care of the player list
# * crummy example, but you get the point
end
end

You could override the entire on_move() method for each class that requires specificity. My idea isn't changing much here,
other than the fact if you know in advance which methods are going to require custom implementation, make those raise an
error if not overridden.
17 Aug, 2010, Runter wrote in the 6th comment:
Votes: 0
My thoughts on this is don't design a module to only work as desired for one class and be surprised when that's rhe case.

In your example if your list was for all things it would make sense. The need to separate types in different lists is usually a thoughtless impulse by people using low level languages mostly.

list.select{|o| o.is_a(Player)}

In your example I would not have defined on move. Instead I'd call it if its defined while running incidental code. I wouldn't put incidental code in there by default.

obj.responds_to?(:on_move)

I don't mean to sound critical. I'm on my phone and can't write more code atm.
18 Aug, 2010, Tyche wrote in the 7th comment:
Votes: 0
$ irb
irb(main):001:0> class Character
irb(main):002:1> end
=> nil
irb(main):004:0> Character.new.eat "apple"
NoMethodError: undefined method `eat' for #<Character:0x7fd2bed0>
from (irb):4
irb(main):005:0>

Why write code you don't have to?
If Character doesn't implement 'eat' exception is already raised.
18 Aug, 2010, JohnnyStarr wrote in the 8th comment:
Votes: 0
@Tyche

I think you missed my point. The entire idea is to mix-in the method def, but not the implementation.
Of course you reach an error if it's not defined. The reason it would raise the error, is it is in fact included
in the class, just not specifically implemented for that class.

@Runter

I agree, I would never have a player list separate from a character list. My point was that if you
have an object mix-in a module, not all objects will require the exact same implementation.

I suppose you could create a clause for this using is_a? or responds_to?, but i think that there
is something to be said about the formality of static typed language principles in a dynamic environment.


Overall, if I thought that I was 100% right on this, I wouldn't care to discuss it on a forum. My
purpose is in fact to discuss this to determine any reason why this isn't necessary to do. So far
Runter's example of why you would have one list in a higher level sense is the only observation that
reasons with the matter at hand.
18 Aug, 2010, Runter wrote in the 9th comment:
Votes: 0
I shrug.


I shrug because I haven't ran into these issues. I think you may just need to shift your paradigm a bit and embrace the ruby way if you're going to use it.

The use of respond_to is a good way to provide hooks by virtue of a method just being defined.
18 Aug, 2010, JohnnyStarr wrote in the 10th comment:
Votes: 0
First off, I appreciate your guys insight, and hope I'm not coming across as rude either.
Runter said:
Instead I'd call it if its defined while running incidental code. I wouldn't put incidental code in there by default.

This interests me because a big part of what I'm trying to understand is this type of design anyway.
I have always dealt with this type of logic linearly from diku-ish experience. At this point however, I am in fact trying to embrace new concepts.
One of which is to design behavioral events based on predictability.

For instance, in my mind something like a Room would mix-in a Habitable module. The reason to modularize this is because entities could reside in Rooms,
Caves, Cok-Pits, Fields, Forests, etc. So I would figure that each Habitable might have an on_enter() method. Why? Because all MUDs apply some
sort of logic on_enter():

south room> Aragorn floats to the north.
north room> Aragorn floats in from the south.

If this sort of logic was only coded in something like move_char(), it would lose the ability to predefine predictable behavior for specific areas. A cokpit that seats
one, would not need to loop through a list of other players. A dense Cave might not inform other players of your arrival because it might be too dark, too cramped
or too quiet to notice you.

At the end of the day, my aim is to simplify things. I'm tired of spaghetti diku code that has a million "if" statements.


PS: I spelled C O C K P I T that way because of the filter. :biggrin:
18 Aug, 2010, Runter wrote in the 11th comment:
Votes: 0
Presumably the most important thing Habitable would define is methods relating to adding or removing things from it.

obj.add(ch)

Inside of add perhaps it has

if self.responds_to?(:on_enter)
self.on_enter(ch)
end

Then if you need additional functionality for any specific class that mixes in Habitable you have a hook by defining on_enter.

Then given 3 different Habitable objects of different classes you can call add without concern for what incidental code may fire. Its possible hooks like this exist on the singleton class. The type would backfire in that sense. Two objs of the same type may do different things. One may define on enter. Another my not have.
18 Aug, 2010, David Haley wrote in the 12th comment:
Votes: 0
In Python, you can declare a so-called meta-class that lets you check that certain methods marked as "pure virtual" in superclasses are in fact implemented in subclasses. The same thing is of course possible in Lua, because you implement the class mechanism yourself so you can have it do whatever you like. I would imagine that you could do something similar in Ruby and avoid having to write all the exception-raising yourself.

Unit tests might solve this problem, I guess, but I don't really believe that's how development works in practice on a large enough system with a large enough number of objects. There's a reason why compilers are sometimes helpful, after all.

That said, many people would just say "hrm, just duck type it and be happy, and if it's wrong, Don't Do It Wrong". This view has its ups and downs; whether or not it suits you is really only up to you to decide.
18 Aug, 2010, Runter wrote in the 13th comment:
Votes: 0
I guess I'm missing something as tyche was.

o = Object.new
puts o.roar rescue "exception raised"

Furthermore you can define method missing for a hook for when this exception is raised. You can log it and halt if you think you must.
18 Aug, 2010, David Haley wrote in the 14th comment:
Votes: 0
Sometimes you want a method that does something, yet still requires subclasses to override it – in those cases the method is not in fact undefined.

Of course, an alternate way of writing it is:
define superclassfunction()
do some stuff
call self.subclassfunction()
end
// do not define subclass function

this way if they don't override subclassfunction, the exception is raised.

Some people see value in having an explicit list of defined methods, which might be missing implementations, as opposed to methods that aren't defined and shouldn't be. The hook that lets you catch undefined methods doesn't really help distinguish those two cases.
18 Aug, 2010, Runter wrote in the 15th comment:
Votes: 0
The hook let's you determine which symbol was called. That's a way to distinguish.


Putting that aside he was already doing what you described. Define the method for a default action on the module.
18 Aug, 2010, David Haley wrote in the 16th comment:
Votes: 0
Quote
The hook let's you determine which symbol was called. That's a way to distinguish.

Yes, but you have to write it all out. This is why Tyche's post missed the point. Just putting in the hook doesn't automatically solve the problem, although it can let you tell (at method invocation time) if the method should have been defined. The method I proposed lets you tell at class definition time (so, before class instantiation time).
18 Aug, 2010, JohnnyStarr wrote in the 17th comment:
Votes: 0
Ok, I see why it's a bit confusing, maybe this will make more sense:

module Consumes
def eat; end
end

class Character; end

c = Character.new.eat # => error - as mentioned earlier, Ruby knows that eat is undefined

class Character
include Consumes
end

c = Character.new.eat # => not an error, which is the PROBLEM because it doesnt force
# the author to impelement the method


In other words, it's not about a missing method, in fact you are going to guarentee
that the method is defined by including the Consumes module.

I dunno, maybe I'm the one missing something here. It's not that Ruby is hard for me to grasp, but I just
don't see why decoupling isn't considered just as important in a dynamic environment. Maybe it's just something
that I have to accept about Ruby, and maybe I would be more comfortable with Python? I guess I'm just a fan of
strictness. Mainly because it keeps me from doing stupid things later on.
18 Aug, 2010, David Haley wrote in the 18th comment:
Votes: 0
Quote
I dunno, maybe I'm the one missing something here.

What the "hard-core Rubyers" will tell you is that your 'Consumes' mix-in is useless because it doesn't actually do anything. They would say that you shouldn't define empty-methods unless you, for some reason, mean for them to be empty. In other words, you wouldn't do it the Java interface way.

Python is the same as Ruby here, by the way.

That said, other people see value in having the interfaces defined up-front, with checks that prevent you from defining the subclass unless it implements all abstract methods.
18 Aug, 2010, Runter wrote in the 19th comment:
Votes: 0
The bottom line is that in your example eat is defined. Its defined to do nothing. If you want it undefined then don't define it. If you want it defined to raise an exception then do that.
18 Aug, 2010, David Haley wrote in the 20th comment:
Votes: 0
…that is exactly what Johnny said at the beginning, and the three of you were telling him it was weird. :wink:
0.0/54