[Ns-developers] finalizing the ns-3 object model
craigdo at ee.washington.edu
Mon Jan 14 16:26:46 PST 2008
I'm afraid we're in for a bunch of long emails. I going to respond to this
thread in two goes. I think a lot of this stuff is, or will be, relatively
straightforward an non-controversial so maybe we can just converge on some
of the discussion fairly quickly:
1) Memory manglement -- we've settled on Ptr<T> and it works well.
2) Weak base class, etc. -- aggregation and interface discovery via QI or
some equivalent seems to work well.
3) Component Manager implementation is scary.
There are some relatively minor tweaks we can do to make our lives easier.
Mathieu's idea to (mostly) get rid of a redundant type in QI is a good idea.
I say do it. Moving SetInterfaceId (or some equivalent) out of the
hands/responsibility of the client is a good idea. I say do it.
Perhaps slightly more significant is the change from iid and cid to TypeId.
This seems like a good idea for several reasons:
1) Pretty much anything we can do to simplify the component manager
implementation is good.
2) In the Seattle meeting we decided that going down the road to a fully
componentized system was not what we wanted to do.
To expand on item two, we decided that imposing various types of system
Hungarian notation and interface/implementation separation would be too
draconian and could explode the topology of the source code if taken to a
final conclusion. We decided to leave this to the programmer's discretion.
So, given that we are really making no intentional distinction between
objects in their naming or source organization, it makes sense not to make a
distinction in their associated type identifiers (iid & cid) and creation
Now, I have some doubts that having a C++ object-based system with
aggregatable Objects, a method called QueryObject and the ability to make
some Objects be user-substitutable will be inherently clearer or even as
clear as having a C++ object-based system with aggregatable Interfaces, a
method called QueryInterface and the ability to make some Components be
user-substitutable; but I have a hard time getting worked up about it at
The bottom line is that I say go ahead and collapse iid and cid into TypeId
and clean out the component manager. We are already so far past the point
of a simple intuitive base system (we have to do a lot of hand holding of
new users already to get them up to speed) that I can't see that this is
really going to make much of a difference in the initial learning curve of
the system; but it will improve maintainability and understandability of the
very low-level code. So do it.
Note, however, that if we do this there will be really no indication any
more whether an object is intended to be used as a single aggregated public
interface, a substitutable interface public interface, a private object
implementing some local functionality, an object implementing a replaceable
group of interfaces (nee component), etc.
So, my remaining issue on this subject is how to make the programmers
intentions clear in a system which enables such easy and serious obfuscation
of such things. It is really worse than a regular C++ system with
inheritance, casts, etc. I've imagined myself a new user of ns-3 trying to
navigate such a system and I can see people being incredibly annoyed by
having to solve difficult coding *puzzles* at every turn. I've suggested a
number of ways to help convey intentions ranging from suggesting [gasp]
comments, to adding key words and type information into object creation
But it seems that if we are serious about suppressing the distinction
between objects, Objects, API/interface, Interfaces, and Objects and
Components from our code in favor of an ultimate flexibility, we are really
only left with comments as an answer to conveying a programmer's intentions
regarding objects (or I suppose we can just leave in the puzzles if we are
So please, really, ... I'm serious. If we drop all distinctions between
object types, researchers to come will appreciate it endlessly; and you will
appreciate it if you have to look at your code in five years if you do
something as simple as,
// Create a CraigsFastXxExtension object that refines the
// Ipv4Impl implementation of the Ipv4 public interface and
// enables FastXx processing of Xx requests. This code now
// provides and aggregates the Ipv4 interface to the Node.
Ptr<CraigsFastXxExtension> ipv4 = Create<CraigsFastXxExtension> (udp);
And really, really try not to do things like,
Ptr<CraigsFastXxExtension> impl = Create<CraigsFastXxExtension> (udp);
... ten or fifteen lines of code ...
When you look at this code, the fact that this is where the Ipv4 interface
is implemented and exported is *completely* hidden -- and this is pretty
much how it works now in internet node (where there is even something
completely unrelated to the Ipv4 interface named ipv4).
It will be really hard to deal with if the thing we are creating is actually
a "component" that creates and aggregates some number of interfaces that are
aggregated; and seriously bad if what we create is another component that
creates other components that create some number of interfaces, etc ...
But this is the flexibility we wanted and bought; and making it all
understandable and maintainable is the challenge we have.
So, finally, for those who've made it to here and have lost track,
- I like our current memory management solution;
- I like our interface aggregation, interface discovery solution to weak
base class, etc.;
- I'm find with collapsing iid and cid into TypeId;
- I'm fine with cleaning up that scary ComponentManager code.
We do need to pay attention to how easily and quickly obfuscated our code
can get, realize that it will be worse when we use just one kind of type,
think about those who come after us and actually begin to use those comment
doohickeys and keep them from going stale.
Topology/Configuration is a different story which I will address separately.
More information about the Ns-developers