Bug 155 - "std::ostream & os" parameters not Python friendly
"std::ostream & os" parameters not Python friendly
Status: RESOLVED FIXED
Product: ns-3
Classification: Unclassified
Component: core
pre-release
All All
: P3 minor
Assigned To: Mathieu Lacage
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2008-03-29 18:21 EDT by Gustavo J. A. M. Carneiro
Modified: 2010-04-17 13:13 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Gustavo J. A. M. Carneiro 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 Mathieu Lacage 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 Gustavo J. A. M. Carneiro 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 Gustavo J. A. M. Carneiro 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 Gustavo J. A. M. Carneiro 2009-02-18 07:29:31 EST
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
Comment 5 Gustavo J. A. M. Carneiro 2010-04-17 13:13:14 EDT
Since we no longer use std::ofstream, instead use reference counted OutputStreamWrapper, the bug is fixed.