EPICS Controls Argonne National Laboratory

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: Network Accessable Types
From: Marty Kraimer <[email protected]>
Cc: [email protected]
Date: Thu, 21 Jul 2005 07:00:34 -0500


Jeff Hill wrote:

The set of well defined types is:

Defining another size locked type space enum is not enough of course. You
will also need to define another set of typedefs with corresponding names.
Or anyways that is the typical approach. This was used for example with the
CA interfaces in R3.13 and R3.14 - i.e. DBR_DOUBLE corresponds to
dbr_double_t.
However, as I have mentioned before, my experience has been that programmers
become complacent - allowing their applications to become 32 bit
architecture dependent. They use the type code but generally neglect to use
the corresponding typedef - they learn that dbr_double_t is generally always
a C type "double" (on 32 bit systems), and so they just use "double". That's
what I observed with typical CA client applications. Use of interface
designs with "void *" pointers does not allow the compiler to detect such
inconsistencies.
I think the reason people did not use db_access.h definitions is because it is quite complicated and there is no documentation except comments in the header file

We all know by now that DA takes a different approach. DA knows the C data
type interfaced by the user and range checks / converts accordingly. The DA
design rationale is that the first priority is to know exactly what data
type the user might be actually using so that problems can be detected
during conversion.

At our SLAC meeting I mentioned that I felt that DA was lacking in
capabilities allowing the client application to learn the native type used
in the server for each property. At the recent ANL meeting I showed some
example code demonstrating an upgrade for DA allowing a sophisticated client
to learn the native type (see below for those who were not at the ANL
meeting). An important feature of this design is that there would be three
types of property catalogs; one for read/write access, one for read access,
and one for learning only the native type (in the absence of an instance of
the data). This organization, and some support templates, allows the user to
write the traverse and find functions only once, but use them in all three
of the situations described above (see below).

And the example was very complicated and what it delivered left something to be desired.
Only a C++ Guru would appreciate the example.

Most CA client applications in use today use type double for analog values
and assume that the IOC will not produce anything larger. We appear to live
quite comfortably within the range of a 64 bit floating point types. For
practical reasons, my guess is that as 128 bit floats start to be more
commonly available they will be used initially for their improved precision
and not so much for their additional range. I am also guessing that CPUs
supporting 128 bit floats in hardware will be introduced first at the client
side. As 64 bit architectures become commonplace, 32 bit compilers will
probably routinely support software implementations of 128 bit floats
accessed via type "long double". This will allow well written 32 bit clients
to interact predictably with 64 bit servers - they can switch to type "long
double" should the server specify via the network protocol that the native
type is a 128 bit float. On a 64 bit architectures less energetic
programmers will probably eventually use 128 bit floats for all analog
values.

What if the server has a native type that is too large to be expressed as a
C type with the compiler used to compile the client? Telling them that it is
a nadTypeFloat128 isn't going to make that situation better. What *will*
help is to allow them to continue using the largest possible floating point
variable but detect during assignment all numbers that are not expressible
in their choice of variable. Many, if not most of the numbers involved will
not be out of range. Well written clients will respond appropriately when an
out of range indication is received.

What if we would like to write a client application that will use the same
native type as the server? DA interfaced clients have no problems with that
situation because it will be easy to write a DA interfaced component that
traverses the propertyCatalog and creates (in a type differentiated
callback) an instance of a template supplying for the template argument a
type functionally identical (i.e. size locked identical) to the type used in
the server. In languages w/o templates we simply call a different factory
method for each type that is needed from the type differentiated callback.
Templates makes this type of code where the type varies, but the algorithm
doesn't quite easy to write and maintain. Programmers will also probably
quickly arrive at the conclusion that it is only necessary to inflate
templates for the promoted types (as was the conclusion when implementing
the DA support libraries). Promoting to larger types might appear initially
to some to be intrusive, but when one looks at what occurs under the hood in
the compiler it can be discovered that implicit promotion is already quite
commonplace in C and C++ object code.

Your argument seems to be that as support for 128 bit ints and floats appears then magically thibgs will continue to interoperate. This is too good to be true.

For network data well defined types should be supported and known by any code that accesses or provides network available data.

Finally, despite superior alternatives mentioned in the previous paragraph,
some users will insist on a data type code such as NadType (presumably for
use in a "C" myopic type code indexed jump table or switch statement). A
proliferation of such type code spaces is inevitable. Nevertheless, it will
be trivial to provide DataAccess support library components mapping to any
one of a number of type spaces. Will such support codes be sensitive to
architecture (as decided by the compiler)? You bet. So are all such mappings
such as "dbr_double_t" to "double". However, in practice we discover that
there are not that many mappings. Currently, with 32 bit systems we have
only one (one for each type code space that is).

And you will make the user do the following!!!

PropertyId propertyX;
PropertyId propertyY;
PropertyId propertyZ;
PropertyId propertyI;

struct MyContainer {
public:
   MyContainer ();
   PropertyManipulator::catalog_t & makeManipulator ();
   PropertyViewer::catalog_t & makeViewer () const;
   static PropertySurveyor::catalog_t & makeSurveyor ();
private:
   int x;
   float y;
   double z;
   char i;
   template < class VIEWER >
   static void traverse ( VIEWER & );
   template < class VIEWER >
   static bool find ( const PropertyId &, VIEWER & );
};

MyContainer::MyContainer () {
}

inline PropertyManipulator::catalog_t & MyContainer::makeManipulator ()
{
   return * new ClassCatalog < MyContainer, PropertyManipulator, traverse,
find > ( *this );
}

inline PropertyViewer::catalog_t & MyContainer::makeViewer () const
{
   return * new ClassCatalog < MyContainer, PropertyViewer, traverse, find
( *this );
}

inline PropertySurveyor::catalog_t & MyContainer::makeSurveyor ()
{
   return * new ClassCatalog < MyContainer, PropertySurveyor, traverse,
find > ();
}

template < class VIEWER >
inline void MyContainer :: traverse ( VIEWER & viewer )
{
   viewer.reveal ( propertyX, & MyContainer::x );
   viewer.reveal ( propertyY, & MyContainer::y );
   viewer.reveal ( propertyZ, & MyContainer::z );
   viewer.reveal ( propertyI, & MyContainer::i );
}

template < class VIEWER >
inline bool MyContainer::find ( const PropertyId & id, VIEWER & viewer ) {
   bool status = true;
   if ( id == propertyX ) {
   	viewer.reveal ( propertyX, & MyContainer::x );
   }
   else if ( id == propertyY ) {
   	viewer.reveal ( propertyY, & MyContainer::y );
   }
   else if ( id == propertyZ ) {
   	viewer.reveal ( propertyY, & MyContainer::z );
   }
   else if ( id == propertyI ) {
   	viewer.reveal ( propertyY, & MyContainer::i );
   }
   else {
       status = false;
   }
   return status;
}

void fred ()
{
   MyContainer mc;
   PropertyManipulator::catalog_t & catM = mc.makeManipulator ();
   PropertyViewer::catalog_t & catI = mc.makeViewer ();
   PropertySurveyor::catalog_t & catS = MyContainer::makeSurveyor ();
}





Replies:
Re: Network Accessable Types Andrew Johnson
References:
RE: Network Accessable Types Jeff Hill

Navigate by Date:
Prev: Re: Standard String Benjamin Franksen
Next: Re: Network Accessable Types Andrew Johnson
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: RE: Network Accessable Types Jeff Hill
Next: Re: Network Accessable Types Andrew Johnson
Index: 2002  2003  2004  <20052006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·