Bug 155 - "std::ostream & os" parameters not Python friendly
: "std::ostream & os" parameters not Python friendly
Status: NEW
: ns-3
simulation core
: pre-release
: All All
: P3 minor
Assigned To:
:
:
:
:
  Show dependency treegraph
 
Reported: 2008-03-29 18:21 EDT by
Modified: 2009-04-03 11:42 EDT (History)


Attachments


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2008-03-29 18:21:47 EDT
In the Python bindings I'm working on
(http://code.nsnam.org/gjc/ns-3-pybindgen-notracing/), I am getting errors
like:

/home/gjc/projects/ns-3/ns-3-pybindgen-notracing/build/debug/ns3/csma-helper.h:68:
Warning: Parameter '::std::ostream & os' error (used in static void
ns3::CsmaHelper::EnableAscii(std::ostream & os, uint32_t nodeid, uint32_t
deviceid) [member function]): TypeLookupError('std::ostream &',)

So, std::ostream is not being wrapped, but the problem is that I am not
comfortable wrapping ostream in any form.  The main problem is passing as
reference and lack of reference counting.

Conceptually, I could create my own PyOStream C++ subclass of ostream, which
would redirect writes to a python file-like object.  But passing as reference
or pointer is dangerous because there is no guarantee that python object will
be kept alive for long.  Python users should not have to worry about life cycle
issues that much, and they are not used to it.

If these NS-3 APIs operated on a reference counted object instead (e.g.
Ptr<OStream>) things would be vastly safer to Python bindings... this
Ptr<OStream> could have "std::ostream& GetStdOStream ()" method.  That would be
fine as long as the std::ostream object life cycle management responsibility
shifts away from the Python bindings into the NS-3 core itself.
------- Comment #1 From 2008-03-30 12:29:44 EDT -------
(In reply to comment #0)
> In the Python bindings I'm working on
> (http://code.nsnam.org/gjc/ns-3-pybindgen-notracing/), I am getting errors
> like:
> 
> /home/gjc/projects/ns-3/ns-3-pybindgen-notracing/build/debug/ns3/csma-helper.h:68:
> Warning: Parameter '::std::ostream & os' error (used in static void
> ns3::CsmaHelper::EnableAscii(std::ostream & os, uint32_t nodeid, uint32_t
> deviceid) [member function]): TypeLookupError('std::ostream &',)
> 
> So, std::ostream is not being wrapped, but the problem is that I am not
> comfortable wrapping ostream in any form.  The main problem is passing as
> reference and lack of reference counting.
> 
> Conceptually, I could create my own PyOStream C++ subclass of ostream, which
> would redirect writes to a python file-like object.  But passing as reference
> or pointer is dangerous because there is no guarantee that python object will
> be kept alive for long.  Python users should not have to worry about life cycle
> issues that much, and they are not used to it.
> 
> If these NS-3 APIs operated on a reference counted object instead (e.g.
> Ptr<OStream>) things would be vastly safer to Python bindings... this
> Ptr<OStream> could have "std::ostream& GetStdOStream ()" method.  That would be
> fine as long as the std::ostream object life cycle management responsibility
> shifts away from the Python bindings into the NS-3 core itself.

Adding such a Ptr<Ostream> class in the public API looks horribly painful from
c++ and would kill the whole purpose of these helper methods which is to make
life easy to c++ programmers, so, I would be really annoyed to have to do this.

It would be nice to find a good solution for python though: how does python
handle formatted io to stdout and files ? Can you point me to a not-too-painful
introduction ? How does boost::python handle this case ?
------- Comment #2 From 2008-03-30 13:02:55 EDT -------
(In reply to comment #1)
[...]
> > If these NS-3 APIs operated on a reference counted object instead (e.g.
> > Ptr<OStream>) things would be vastly safer to Python bindings... this
> > Ptr<OStream> could have "std::ostream& GetStdOStream ()" method.  That would be
> > fine as long as the std::ostream object life cycle management responsibility
> > shifts away from the Python bindings into the NS-3 core itself.
> 
> Adding such a Ptr<Ostream> class in the public API looks horribly painful from
> c++ and would kill the whole purpose of these helper methods which is to make
> life easy to c++ programmers, so, I would be really annoyed to have to do this.

True, it would be kind of ugly for C++.  But if the API is an additional API,
beside the existing one, with documentation stating it is only used for
language bindings, it should be ok.

> 
> It would be nice to find a good solution for python though: how does python
> handle formatted io to stdout and files ? Can you point me to a not-too-painful
> introduction ? How does boost::python handle this case ?

In Python, formatted output (the print statement) works with file-like (using
the so called "duck typing") objects:
http://docs.python.org/lib/bltin-file-objects.html

It's not so much about formatted output; the issue is more about stream output
here.  I could provide a std::ostream subclass to ns-3, which used
std::ostringstream internally, and then flushed the string on every newline to
the a python file-like object, and things would work fine (though not very
efficient).  The thing I'm worried about is safe life cycle management.

I think a reasonable compromise would be to provide an API that received a file
name and created a file itself.  It would not support stdin/stdout tracing, but
other than that would be pretty good, and would not have to go through any
python code, so would be more efficient.
------- Comment #3 From 2008-06-09 13:55:48 EDT -------
P3 as it pertains Python bindings and fixing it can be done with incremental
API added alter, no need for API breakage.
------- Comment #4 From 2009-02-18 07:29:31 EDT -------
I have wrapped ofstream, so ascii tracing works.

However, it is notably not "reference counting safe" like python programmers
are used to, and if the ofstream object goes out of scope things could crash.
Example:

def configure_tracing():
  f = ns3.ofstream("foo.tr")
  ns3.YansWifiPhyHelper.EnableAsciiAll(f)
  # <-- f goes out of scope and is deleted

def main():
  #...
  configure_tracing()
  ns3.Simulator.Run() # <-- will crash


But, well, at least now ascii tracing works in python, it's better than nothing
:P