Robert Klemme wrote:
I'm writing a system simulator in ruby (think systemC). The snippet
below shows a typical invocation:
<snip/>
Notice that the Sim object (with all off its components) is passed to
the Simulation engine (sim) for execution. The Simulation engine uses
Kernel#ObjectSpace to find and schedule objects it needs to manage.
IMHO that is bad design. The Sim instance needs to know about all
objects that belong to it.
Hmmm. Certainly the Sim instance does contain all of the component objects and their connections. The actual simulation logic though (i.e. the dynamic manipulations of those objects in simulation time) IMHO needs to be relegated to a black box (the Simulation engine) that the user doesn't need to concern himself with.
And? There is no issue making the simulation a black box. But since you design the app you are free to design the interaction between the simulator and the simulation data.
The Sim object is the netlist that the user must write for each system model so it's syntax needs to be a clean as possible.
That can still be achieved, see my example.
As for efficiency:
1) it is probably (hopefully?) more efficient to use the system hook than to write a method to do the same thing but which confines the traversal to the Sim object passed to the engine, although I agree that the latter would be desirable from a purist OO standpoint.
2) efficiency isn't important here since it only occurs once, before the start of the simulation.
You should do that within your application
and not traverse all objects (of some kind). That is not very efficient
and has some problems of its own (threads, multiple Sim instances etc.).
That's a good point. I suppose its possible that there be more than one sim instance (although the thought hadn't occurred to me) whereby the user wants to model cooperation between two systems. I may have to write that method after all :>)
I want to be able to do:
@d1=Dflop.new
That's easily solved:
Base = Struct.new :owner, :name
class Sim
def initialize
@elements = {}
end
def create(name,cl,*args,&b)
x = cl.new(*args,&b)
x.owner = self
x.name = name
@elements[name] = x
end
# or
def create2(name)
x = yield
x.owner = self
x.name = name
@elements[name] = x
end
def some_other_method
create :d1, Dflop
create2(:d1) { Dflop.new }
end
end
I like the first approach (Thanks!) But I don't see where you've use the Base struct you created. I'm new to ruby (but not to Structs) so I'll have to do some digging here.
Your specific classes would of course have to inherit from Base. Alternatively you could define a module with both attribute accessors if you want to use inheritance for something else.
and then when the sim engine needs a human readable component name, it
somehow gets it from a system hook based on the object id.
Any help?
Yes, do this yourself. As has been pointed out, there are various
issues with the concept of "the name of an instance" notably that every
object can have any number (including zero) references pointing to it.
Sorry if I'm being dense here but I don't see the issue. Simply returning some sort of Enumeration (array, hash, linked list etc) with all or none would do the trick.
There are still issues: How then would you know which one is the one you wanted? And: what do you do about incomplete lists (i.e. instances referenced from Hash, Array, extension code etc.)?
If it's reasonable for the kernel to associate a unique id# with an object (and it is :>) then its also reasonable to associate a name (or names) upon assignment of that object to an instance variable.
IMHO no. Reason is that the overhead is significant. While you need the object id for various things (GC bookkeeping comes to mind) you do not need the names of all variables that refer an instance.
Further, such an association _must_ already exist (otherwise when I write @d1.some_method, the kernel wouldn't know which object I'm referencing). If the kernel has a hash of references, why can't we access it?
No, the information is not there: This is a _directed_ relationship, i.e. you can get from context and symbol to the instance but not back.
Programmers have fought C's (and therefore C++'s) lack of introspection (reflection) since the DoT. With a compiled language it is impossible (or at least very very hard) to do these kinds of things. It seems to me that Ruby should fully capitalize at every turn on the advantages interpretation brings
As always it's a tradeoff. Storing the kind of information in the interpreter is a) error prone (there are some references that do not have a symbol, i.e. inside an Array or in an extension), b) would place the burden on *all* applications not only those that really need it and c) can be easily built when needed (see my example). So the weight comes down on the "don't do" side.
Cheers
robert
···
On 24.03.2008 01:57, Jeff Patterson wrote:
On 23.03.2008 16:15, Jeff Patterson wrote: