EPICS Home

Experimental Physics and Industrial Control System


 
2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: Standard String
From: "Jeff Hill" <[email protected]>
To: "'Andrew Johnson'" <[email protected]>, "'Marty Kraimer'" <[email protected]>
Cc: "'EPICS Core Talk'" <[email protected]>
Date: Mon, 18 Jul 2005 15:10:25 -0600
> but I will not accept a standard string class which is just 
> a pure virtual interface. I hope the above discussion shows why.

1) You are saying that if the implementation is created at runtime, and its
not on the stack then whoever called the factory to create it has to
remember to return it to the recycler when they are done using it, and its
nice to have a helper class so this is done automatically. That's all fine,
tasty, American apple pie, but my perception is that this argument about
lifetime management is completely orthogonal to discussions about interfaces
for manipulating the object.

2) Sure, classes that remember to destroy the object when we are done using
it are nice, and I definitely do use them. However, one has to put this in
perspective. No matter how many times you wrap it with auto destroying this
and that you still have the same responsibility. Users will sometimes want
to have a pointer to it, and therefore whoever called the factory to create
it has to remember to return it to the recycler when they are done using it.
Most "users" don't have a problem with that.

3) There is some extended discussion about assignment to the string, but
since assignment is possible through a pure virtual interface then I am
having problems determine the relevance of that thread of discussion.

4) You should certainly have freedom to use what works best to store a
string in a field in a record, and if users and databases have similar
requirements then perhaps the same implementation of a string should be used
by them also (by-the-users is a pretty general term). However, optimal
design will be to use a common pure virtual interface and allow many
different implementations. For example, if the string storage is a C "string
constant" then a very simple, and fast, implementation is better. With CA
the storage needs to be CA protocol buffers. I already have a library for
creating, destroying, and manipulating protocol buffers. My hope is that a
pure virtual string interface can be used to directly manipulate strings
residing in protocol buffers.

5) The important distinction is that storage management and implementation
can be and *should* be application specific (in this context database
storage specific). In contrast, important interfaces like dbPutField,
dbGetField, dbGetLink, and anything else that manipulates strings should use
an pure virtual interface so that A) these codes do not break if the string
implementation is changed, and B) codes like CA (and CA interfaced
applications) are free to manage string storage and implementation in a way
that is optimal for their situation.

6) Lastly (and of less significance), sorry to dredge up the past, but I
can't help but have a very clear memory of lashings I received at design
meetings for not following appropriate design methodology. During EPICS
R3.14 design the concerted opinion of the APS contingent was that the design
of epicsTimer was unacceptable unless it was changed to be pure virtual. To
be specific, the APS mandated that the design be changed so that an
epicsTimer must be created by calling a factory method returning a reference
to a pure virtual interface. I can't say that I didn't benefit from the
experience :-)

Jeff

> -----Original Message-----
> From: Andrew Johnson [mailto:[email protected]]
> >
> > Jeff said that he wanted it to be an interface class.
> 
> Let's look at that idea, without worrying about what it actually looks
> like: Assume we have all agreed on a single API for a string class that
> I'll call 'StringInterface,' which is a pure interface class.
> 
> I can't instantiate an object of type StringInterface since it's a pure
> interface class, so in order to create and use a string in my code I
> would have to define a pointer to a StringInterface, and call a factory
> routine or use some other means to create a concrete object of my chosen
> derived class.
> 
>      StringInterface *pstring = StringFactory(...);
> 
> However because I'm using a pointer, I must remember to release that
> object (assume for now that just means deleting it) after I've finished
> with it in order to avoid leaking memory when my pstring goes out of
scope:
> 
>      delete pstring;
> 
> Since I'm a well-educated C++ programmer who understands the RAII idiom
> (Resource Acquisition Is Initialization), I know how to solve the
> potential memory leak issue: wrap the pointer inside another class which
> has a destructor that will delete the string for me.
> 
> I could use the standard C++ auto_ptr template to wrap and manage a
> StringInterface pointer, but I don't want the destructive assignment
> behaviour that it would give me.
> 
> I decide to create a new class implementing StringInterface that
> contains and manages a StringInterface pointer for me.  It will release
> the object automatically in its destructor, so no memory leaks.  That
> class will look something like this:
> 
> class SafeString public StringInterface {
> private: // Data
>      StringInterface *psi;
> public: // Methods
>      SafeString(StringInterface *concrete = 0) :
>          psi(concrete) {}
>      ~SafeString()
>      {
>          if (psi) delete psi;
>      }
>      SetStringInterface(StringInterface *concrete)
>      {
>          if (psi) delete psi;
>          psi = concrete;
>      }
>      // For every method in StringInterface, define
>      returnType method(...)
>      {
>          if (!psi) throw(something...);
>          psi->method(...);
>      }
> private: // Not implemented:
>      SafeString(const SafeString& rhs);
>      SafeString& operator=(const SafeString& rhs);
> };
> 
> I can now create an instance of a SafeString and know that I can't leak
> memory by forgetting to delete the pointer:
> 
>      SafeString greeting(StringFactory(...));
> 
> SafeString isn't a pure interface class since it contains data, but the
> only behaviour it actually defines for itself is the ability to manage
> that pointer for me.  I haven't sacrificed any flexibilty on the part of
> the underlying implementation of StringInterface since I forward all the
> StringInterface methods to the real implementation, I have just made it
> safer to use the StringInterface API.
> 
> I'd like to make my SafeString slightly easier to use in a couple of
> very common cases:
> 
> 1. Suppose there's an implementation of StringInterface available
> through the StringFactory that takes a C++ 'const char *' literal and
> makes it accessible using the StringInterface methods.  I decide to add
> a constructor to my SafeString class that explicitly creates one of
> those kinds of strings when given a 'const char *':
> 
>      SafeString(const char *pstr) :
>          psi(StringFactory(..., pstr)) {}
> 
> I can now write code like this:
> 
>      SafeString greeting("Hello, world!");
> 
> which is the same as writing this:
> 
>      SafeString greeting = "Hello, world!";
> 
> 
> 2. I can't assign anything to a SafeString at the moment.  I declared
> the self-assignment operator private in the class definition above in
> order to prevent the compiler from creating one for me that would have
> just copied the psi pointer, which is definitely the wrong thing to do.
>   Assuming that StringInterface can manipulate a mutable string it must
> provide some way to copy one string to another.  I'll change my class to
> add an assigment operator using that method:
> 
>      SafeString& operator=(const StringInterface& rhs)
>      {
>          if (!psi) throw(something...);
>          // Assuming StringInterface::assign(const StringInterface &)
>          psi->assign(rhs);
>      }
> 
> This now means I can write this:
> 
>      SafeString greeting = "Hello";
>      SafeString reply = StringFactory(...); // something mutable
>      reply = greeting;
> 
> Note that there's no copy constructor for SafeString, so I definitely
> can't write this:
> 
>     SafeString greeting = "Hello";
>     SafeString reply = greeting; // Link error, not implemented
> 
> The copy constructor for reply would have no way to tell what kind of
> string I want it to instantiate.  If StringInterface provided a clone()
> method I could implement a copy constructor to clone the StringInterface
> object that it's copying, but if it doesn't then the above code will
> always have to give a link error.  For the purposes of the current
> argument I don't really care about that, but it's something to bear in
> mind.
> 
> 
> Ok, so I've now defined a class that implements and uses our agreed
> StringInterface API.  It's exactly the same size as a StringInterface
> pointer, but my class is safe from memory leaks and is more friendly to
> users.  Which should we encourage EPICS V4 users to develop with -
> StringInterface pointers, or my SafeString class?
> 
> Now please compare SafeString to the overall shape of the definition of
> EpicsString as found in the Wiki page "V4 Design: epicsTypes" at
> http://www.aps.anl.gov/epics/wiki/index.php/V4_Design:_epicsTypes#epicsStr
> ing
> 
> 
> I would be happy to discuss changes to (or even a complete replacement
> for) the EpicsBuffer interface which EpicsString was based on, and
> changes to the methods of EpicsString itself.  We can talk about whether
> an EpicsString IS an EpicsBuffer, HAS an EpicsBuffer or even
> IS-IMPLEMENTED-IN-TERMS-OF an EpicsBuffer (EffC++), but I will not
> accept a standard string class which is just a pure virtual interface.
> I hope the above discussion shows why.
> 
> 
> Jeff, I'll be commenting on your reply in a separate message.
> 
> - Andrew
> 
> PS: Why aren't we discussing this on core-talk?
> --
> Podiabombastic: The tendency to shoot oneself in the foot.



Replies:
Re: Standard String Marty Kraimer

Navigate by Date:
Prev: RE: [Fwd: RE: Standard String] Jeff Hill
Next: Re: Standard String Marty Kraimer
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: [Fwd: Re: Standard String] Marty Kraimer
Next: Re: Standard String Marty Kraimer
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024