18 Aug, 2010, JohnnyStarr wrote in the 21st comment:
Votes: 0
I guess if it was a very small app, I wouldn't really mind. But in my opinion, a MUD with a bunch of objects that share
similar behavior could really benefit from sharing modules. I guess the Ruby Way would be to mix-in the modules and
only override what is necessary. What scares me about this idea, is say your lib has 100 base objects, and you are
mixing-in multiple modules per object. It seems that without great care, things could get out of hand.

By the way, I'm talking more of an LPC approach which may be the problem. I would be using a file based system that
takes advantage of scripting at run-time. An example might look like:

class Item < Obj
include Obtainable # items are objs that can be picked up
end

class Weapon < Item
include Wieldable # not all items may be wielded.
end

class Sword < Weapon
include Harmful # weapons cause harm (damage), but so could poisoned bread, which is a food item.
end

class MyAwesomeBlade < Sword
include Magical # abra cadabra
include Destructible # this particular sword can be destroyed
include Marketable # you may sell this item at the market
include Actionable # you may sell this at an auction house
end


#in do_get(ch, item)

if item.is_a?(Obtainable)
ch.get item
item.on_get() # this method might need to be specific.
else
ch.send "You can't obtain this item"
end
18 Aug, 2010, David Haley wrote in the 22nd comment:
Votes: 0
It almost seems like you're going for a component system of some sort.
18 Aug, 2010, JohnnyStarr wrote in the 23rd comment:
Votes: 0
David Haley said:
It almost seems like you're going for a component system of some sort.


I'm not familiar with that type of system. Can you expound on that?

Like I said, this makes the most sense to me right now. Also, I think it's more fun because you can specify every tiny detail of an object,
without having to use bit-flags for every characteristic. I can see how you would refer to these traits as components.
18 Aug, 2010, David Haley wrote in the 24th comment:
Votes: 0
A component system is, uh, like what you're doing. :tongue:

More seriously, a component system is where objects don't do much as-is, but you mix-in 'components' of functionality, like being a weapon, or being a container, or being a mobile object, and so forth. You then send messages to an object, and it delegates them to components. So for example if you try to damage an object that doesn't have a "damageable" component, it just ignores the message.

There have been a few threads about this; I like this one quite a bit: http://www.mudbytes.net/index.php?a=topi....

One comment I made in there that I feel applies here is that you can distinguish between your code's object class structure, and your game's objects structure. In other words, you can have an object that implements all kinds of components, but the underlying data structure doesn't mirror this inheritance structure. It's kind of like having two type systems, one in the host language, and one implemented by the host language.
18 Aug, 2010, Runter wrote in the 25th comment:
Votes: 0
It depends on how agnostic your designing the modules to be. I personally like this use of modules.
18 Aug, 2010, David Haley wrote in the 26th comment:
Votes: 0
Ya know, phone posting is nice and all, but it greatly reduces the explanatory value of posts. :tongue:
18 Aug, 2010, Runter wrote in the 27th comment:
Votes: 0
I mean its important to be aware of the modular design of the components. It can create coupling otherwise that is quite arresting.

Yes, I have just been phoning it in ill try to do better.

I was toying around with composition under closure a few months ago.

Weapon = wearable(obtainable(wieldable(Obj)))
Sword = damage(:slash, Weapon)
18 Aug, 2010, JohnnyStarr wrote in the 28th comment:
Votes: 0
My reason for changing things has been because in past attempts, I focused a lot on the server mostly.
By focusing solely on the lib first, especially by creating all the modules first. This way, I know what to expect
from objects way in advance.

I am separating driver from lib. I don't know if "driver" is so much the right word, but my goal is for the driver section
to take care of: Server, Sockets, Meta-Programming, Network Protocols, Background Services, etc. The lib will contain
the core objects, as well as helpers and managers.

After creating a diagram, I've decided to create a bridge level library for intermediate objects. One such example would be Controller.
Each object in-game that mix-ins the Controllable module will contain a "Controller". As discussed in other threads, the controller could
be a socket descriptor, an AI, or a proxy that allows a controlled object, to control another object ( perfect for a Jedi-Mind-Trick type scenario ).
The bridge level objects will also contain Menu and Screen objects that allow you to customize menu systems on the fly.

I realize this may be more organizational than functional, but I want to start off with everything considered.
18 Aug, 2010, Tyche wrote in the 29th comment:
Votes: 0
JohnnyStarr said:
@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.


I understand what you are doing. It's just that in ruby, the concept don't apply. Look at the reasons
behind Java interfaces. Java interfaces are static typing mechanisms, whose real purpose is to
enforce compile time type-checking.

There's an excellent old ruby-talk post on this, How to duck type? - the psychology of st...
Embrace the duck. :-)
18 Aug, 2010, David Haley wrote in the 30th comment:
Votes: 0
The concept applies, if you want it to, and if you feel that it is useful in the relevant project. So yeah, look at the reasons behind Java interfaces, but look beyond the first degree obvious statement that they're only for compile-time type-checking sacrifices to the gods. They let you catch errors at compile-time, rather than have to wait until something blows up because you made a mistake that could have been avoided. It's even nicer to catch these errors at compile time when catching them at runtime means wasting several hours' worth of computations (e.g., in a scientific or financial computing application).

This is not to say that you must slavishly adhere to static checking. In my own work, professionally and otherwise, I embrace full duck typing in many places and am much happier for it. But to say that static checking is useless is rather just as silly as to say that static typing is always necessary.

Another problem with duck-typing is that just because something responds to a given method name does not mean that that thing is actually the right kind of thing. In other words, two extremely different types might both have a method named X, but whereas one of these types is appropriate for some method, the other might not be. There is a difference between a method's name and a method's semantics.
18 Aug, 2010, Tyche wrote in the 31st comment:
Votes: 0
Runter said:
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.


Here's another interesting post by a Java programmer coming to Ruby. Now he also quickly came to the conclusion that writing such code was indeed a waste of time and none of his prodigious output of Ruby code contains any of this, because he made the shift in paradigm. He has an excellent blog that's definitely worth reading. There are even a few Ruby design by contract modules out there to make ruby seem more like Eiffel.

Don't get me wrong. One can satisfy that urge and make Ruby look like something else, but in the end IMHO you're still wasting time adding in conceptual baggage that grew out of compile time type checking.

Edit: Testing is where most rubyists handle this. That's why there's dozens of test frameworks. Write tests to make sure Character can 'eat' in the way you expect.
19 Aug, 2010, Chris Bailey wrote in the 32nd comment:
Votes: 0
Me said:
Interesting idea, but wouldn't proper specs and tests kind of remove that need?


I agree with Tyche, some of these testing frameworks are very robust and sometimes even FUN to work with. Check out Rspec coupled with Cucumber.
19 Aug, 2010, JohnnyStarr wrote in the 33rd comment:
Votes: 0
So Tyche, what do you think about my module mix-in approach?
Do you feel that by defining things in this component style has any downsides? Or feel that it isn't the ruby way?
19 Aug, 2010, Itansha wrote in the 34th comment:
Votes: 0
Ignoring the argument of to duck type or not to duck type, if you do go the route of raising exceptions for non-overridden methods, I suggest adding a helper method or two to streamline the process. For example, something along the lines of:

class MissingHook < Exception
end

class Module
def required_hooks(*hooks)
hooks.each do |hook|
class_eval "def #{hook}(*args); raise MissingHook, '\\'#{self}\\' requires that \\'#{hook}\\' be implemented.'; end"
end
end
end

module Consumes
required_hooks :eat, :drink
end

class Character
include Consumes

def eat(food)
puts "eating #{food}"
end
end

character = Character.new
character.eat 'meat' # => "eating meat"
character.drink 'water' # Exception raised: 'Consumes' requires that 'drink' be implemented.
19 Aug, 2010, JohnnyStarr wrote in the 35th comment:
Votes: 0
Cool stuff. I had anticipated designing a helper, but I didn't give much thought to how it would look.
Very cool. :smirk:

I think Ruby's meta-programming capabilities make it most appealing.
19 Aug, 2010, David Haley wrote in the 36th comment:
Votes: 0
It would be even better to do it at "compile" time, although I haven't looked at how you might do this in Ruby (it's doable in Python and Lua, so I'm assuming Ruby as well). I'd show you code, but it was done at work so I can't publish it…
19 Aug, 2010, JohnnyStarr wrote in the 37th comment:
Votes: 0
Ok, so, I figure that what would make sense is for the module not only to take care of the behavior, but
also to look out for the class it is mixed-in, to make sure that required components are also included. I have
created an Inventory helper that needs to be included in our Player object. But check out what happens here:

class Inventory
def initialize(s)
add_item(s)
end

def add_item(i)
puts "you have added a #{i} to your inventory."
end
end

module Carries
def self.included(base)
base.class_eval %Q{
@inventory = Inventory.new("Blade of Gondor")
attr_accessor :inventory
}
end
end

class Player; include Carries; end

p = Player.new
puts p.inventory

#OUTPUT:
# => you have added a Blade of Gondor to your inventory.
# => nil


What's weird about this, is that the inventory object initializes as shown, however, it seems that the inventory object
itself is still nil. Anyone know why? I realize that this is in a way multiple-inheritance, but it seems
that in Ruby that isn't so much of a bad thing.
19 Aug, 2010, Runter wrote in the 38th comment:
Votes: 0
My first instant is to say you're setting the instance variable on the class instead of the instance.
19 Aug, 2010, JohnnyStarr wrote in the 39th comment:
Votes: 0
Yes, that's true, but I've tried: "base.instance_eval()" also, and it doesn't work either.
Perhaps the problem, is that "base" is just the class type, and not the initialized object.

In fact, I'm starting to wonder if there is even an initialized object at this point.
I might have to do something like "def init_carries()" which would be called from the base objects "initialize()" method.
I just feel like there should be another way here.
19 Aug, 2010, Runter wrote in the 40th comment:
Votes: 0
Basically what you seem to want to do is initialize an inventory. Regardless of which convoluted ways can be thought up the obvious answer is putting the code in the Inventory initialize method.

If you just want players to initialize their inventory then put it on the Player class.
20.0/54