C++11 mapping for IDL struct
Currently the CORBA IDL to C++ mapping maps an IDL struct to a C/C++ struct with fairly regular semantics.
The DDS C++ PSM however proposes a completely new mapping based on C++ classes and accessor methods and non-public state. This approach offers some advantages, especially to DDS implementers, to optimize state representation.
Consider for instance the following IDL construct:
// IDL struct A
{
string name;
long id;
};
typedef sequence ListOfA;
struct B
{
ListOfA a_list;
};
In the current C++ mapping this would be mapped on regular C/C++ structs and would allow code like:
// C++
B my_b = // get a B struct instance
const char* name_of_a = my_b.a_list[0].name;
...
my_b.a_list[0].id = 123;
while in the proposed DDS C++ PSM mapping this would change to:
What would be the preferred mapping?
My personal preference still slightly leans toward keeping the 'plain' C/C++ structs since I would advocate to keep a new C++0x mapping as close to language being mapped as possible.


Possibly using noexcept specification for move-ctor and swap
The move-ctor, move-assign, and the member swap functions could probably use a noexcept specification. noexcept move-ctor will help improve performance of std library algorithms such as std::vector::resize. Moreover, user-level classes can guarantee strong exception safety if generated classes have noexcept swap. Here is a much longer post on noexcept swap.
noexcept
Hi Sumant,
Thanks for the suggestion, we are going to have a look at this the next weeks. You can get the generated code we have now from our OSPortal website, it has a svn checkout option. Feel free to take the code and handcraft it to show your ideas.
Pass-by-value constructor
Here is a comment I sent Johnny (by email) a while ago. I'm not sure if he received it.
*************
Instead of two constructors for a struct (one with all const refs and other with all rvalue refs), have you considered using just one constructor that takes all its parameters by value? It would look like this for struct Simple:
Simple (uint8_t o,
int32_t l,
std::string s,
double d,
bool b,
char c)
: o_(o), l_(l), s_(std::move(s)), d_(d), b_(b), c_(c)
{
printf("pass-by-value parameter constructor\n");
}
Such a constructor checks rvalue-ness of each and every actual parameter *individually* and picks the right constructor at the call site. However, in your two constructor approach, all the actual parameters must be rvalue refs to kick in the rvalue-ref constructor of Sample. I did a simple test on your original code.
Simple s1(10, 20, "Test", 30.40, true, 'Z'); // Calls rvalue-ref ctor of Simple. All parameters are rvalues.
std::string name = "Test";
Simple s2(10, 20, name, 30.40, true, 'Z'); // Calls const lvalue-ref ctor of Simple. Name is an lvalue
uint8_t foo = 200;
Simple s3(foo, 20, "Test", 30.40, true, 'Z'); // Calls lvalue-ref ctor of Simple. Bad luck, "Test" copied twice.
I've a much better test than before available here: http://cpptruths.googlecode.com/svn/trunk/cpp0x/corba-simple.cpp
In the case of s3, even though "Test" leads to a std::string rvalue, an optimal constructor is not called just because foo is an lvalue.
With the constructor I've show above, floating points and doubles would be copied, I agree. But string s will never be copied more than once.
If Simple class had say 5 strings in it, each parameter could be optimized individually based on whether it is a rvalue or not.
There is a related article by Dave Abrahams: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
allow extensible custom (de)marshalling
It would be nice if there was a way to provide custom (de)marshalling in the new language mapping.
I wrote a reflective custom (de)marshaller to and from JSON to represent CORBA data structures as human readable string for storage in e.g. a database.
As reflective marshalling is slow(er) than generated marshalling it would be nice if the new language mapping had a way to generate custom marshalling where a trait like marshalling definition class could be passed to the generated marshalling code which defines how primitive types are marshalled and how complex types, unions and enums are composed.
This way the custom marshalling code would be both flexible and fast, as it won't have to dynamically interrogate the struct and flexible as it would use the custom traits to compose the final marshalling result.
I would expect the IDL compiler to still generate the hard coded CDR marshalling, as the custom marshalling may only be generated on user request to minimize the footprint if not used.
e.g. a struct like this:
// IDL
struct A
{
string name;
long id;
};
where name = "test" and value = 5 could be represented in JSON like this:
{"name":"test", "value:5"}
dds x-types
Hi Lothar,
I forgot that the DDS X-Types draft specification is proposing different data representations. They are currently proposed cdr and xml, but I think there is a FTF issue to also add JSON. This is something that is purely for DDS and we haven't been able to check out how this could impact CORBA.
Johnny
custom marshaling
Hi Lothar,
To my idea this feature goes broader than just the language mapping, it also impacts the CORBA specification. Because of that I don't think it is feasible to add a feature like this at this moment. Maybe you can file and issue at the OMG on the CORBA spec, hopefully someone is willing to perform the work to add this in the future.
Johnny
Re: custom marshaling
I don't think this affects CORBA in general unless other languages want the same feature.
It could IMHO be done solely in the language mapping, as the IDL compiler(s) for C++ would just generate this new feature when generating code for the new C++ mapping. And we already need new compilers for the new language mapping.
It could even be made an "officially" an optional feature, so that the IDL compiler vendors can choose to support it or not. But if they do, the API would be standardized through the language mapping. This would also allow to defer implementing the feature until enough resources are available.
No harm in discussing it to see if there's enough interest ;-)
Non-CORBA mapping
The point is that the C++0x mapping we're working on is still a CORBA C++0x language mapping. This means it has to conform to all aspects of the CORBA spec which includes the CORBA interoperability specs (which in turn includes the marshalled data representation).
What you are in fact requesting is an alternate application of IDL more like f.i. the use DDS makes of IDL.
As Mark Hayman pointed out in his excellent comment on the current feature article 'Why should you care ...' the new C++0x mapping is a step towards separating the direct ties between IDL and CORBA. If we can achieve that we could also separate the concerns with respect to the language mapping as it pertains to the user application representation (i.e. how are IDL data types represented to the application developer) and the backend representation (i.e. how is the data marshalled/processed/transported/...).
CORBA could than be defined as an IDL based technology with CORBA specific backend data representation/interoperability rules and your JSON solution could than be another IDL based solution specifying different backend data representation rules.
output stream operators for structs
It would be nice if the new language mapping defined output operators, so that one can (debug) print the (structured) content of the structs to an ostream.
This can be enabled as a orb vendor specific feature on TAO today, but it would be nice to have it as a standard language mapping feature to allow it's use in portable code.
ostream
This is also a feature I would like as it is very helpful for debugging and general logging of system information.
One thing I would add is that the stream operators be made friend functions of the generated class. Currently in TAO, the operators are free functions and are not friends, which causes problems for templated code in other logging frameworks (like log4cxx) such that the following code doesn't work:
LOG4CXX_DEBUG(logger_, "Received unexpected info: " << myInfo);
where myInfo is an instance of a C++ mapped IDL structure.
Trent Nadeau
Northrop Grumman Corp.
ostream
Hi Lothar and Trent,
We will have a look at this and see if this is something that could be made part of the language mapping. Trent, the TAO ostream code is vendor specific, we could extend it to make it working with log4cxx.
Johnny
struct example available
We extended the IDL C++0x examples on
osportal
with an example of an IDL struct and posted the generated client stub.
accessors for scalar members
For members which have a scalar type (or typedef thereof), I wonder about the & and && accessors. Wouldn't a single by-value setter/getter be enough?
scalar members
We want to keep the mapping as easy to use, but also as consistent as possible. The current IDL to C++ mapping is just one big list with exceptions to the default case. For the accessors, the & and && accessors don't do any harm and we would like to keep them as is.
Also, for example, the DDS instance handle is defined as native, some vendors define it as long, some as a struct, making a difference between a long and a struct in accessor and argument passing would mean that you can't easily switch between DDS vendors (as is currently the case with IDL to C++).
Move mutators
I think there should be a move mutator method for each field in the struct. This would be particularly useful for an IDL struct that has a very complex struct as a member since a copy for that set will no longer be required.
For example,
// IDL
struct Nested
{
double d;
VeryComplexType complexMember; // highly nested or large
};
// C++
class Nested
{
// ...
void complexMember(VeryComplexType && _complexMember);
};
This would allows users to do the following without creating any copies:
Nested myNested;
// calculate other fields and add to myNested using
// mutators possibly calling other functions to do so
// ...
// Create/get VeryComplexType instance
// Uses move assignment operator
VeryComplexType myComplex = createComplexType();
// Modify myComplex in some way
myNested.complexMember(std::move(myComplex));
doSomething(myNested);
Trent Nadeau
Northrop Grumman Corp.
move mutator
The move mutator has been added to the struct example in OSPortal. There is a svn readonly anonymous account which you can also use to get the latest copy of the example code
Move
That is easy to add, will do that tomorrow
Move methods
In the Test::Simple struct mapping in that example, I don't think the signatures of the move constructors/operators are correct. Rvalue references should almost always be passed as non-const since the move operation could change the right-hand side in order to make the right-hand side (temporary) act "as if" the temporary had been reverted to its default constructed state.
For example, if that struct had pointers/object references in its internal state, the move constructor/operator should set the temporary's to null so memory is not deleted twice.
Trent Nadeau
Northrop Grumman Corp.
move
You are right, an oversight from my side. I have addressed this in our IDL compiler and updated the example on OSportal
Accessors or Direct Access?
In other technologies, the use of accessors is advocated IMNSHO for two reasons:
So, in summary, I am sympathetic to wanting to be consistent with some later technologies, but I don't see any compelling reasons for the proposed change.
Victor Giddings
accessors
The are a few reasons why we think accessors are the way to go:
accessors
In fact, in the IDL to Ada mapping 1.3 we have a pragma that allows specifying a range on a typedef of numeric type, e.g.
// IDL
#pragma range percentage_t 0.0 .. 100.0
typedef float percentage_t;
If we have accessors then we can support this also in C++.
Example:
// IDL
struct mystruct {
percentage_t pcnt;
};
// C++ (roughly)
class mystruct {
public:
void pcnt(percentage_t value) {
if (value < 0.0 || value > 100.0) {
throw std::out_of_range("mystruct.pcnt value out of range");
}
_pcnt = value;
}
percentage_t pcnt() const {
return _pcnt;
}
private:
percentage_t _pcnt;
};
Oliver Kellogg
ada
Hi Oliver, I did attend a presentation regarding the language mapping from you in DC some years ago. I did remember that presentation but couldn't find it on the web. I emailed you some weeks ago but got the mail bounced back, could you mail me directly? I really would like to reread your presentation and get your feedback on the C++0x mapping.
Useful default constructors
The default constructor for the mapped class should initialize:
Note that if the mapped class uses different types for its internal state, calls on its accessors immediately after default construction should return values "as if" the above initialization had occurred.
Trent Nadeau
Northrop Grumman Corp.
arrays
I'm less sure about initializing arrays. While it would be wonderful to have them initialized, I can see how doing so could be a very expensive operation for large arrays and/or arrays of complex types.
Trent Nadeau
Northrop Grumman Corp.
Map it as class
The current idea is to map it to a class with accessor methods, but also with copy/move constructors and assignment operators.
properties
One thing that could be done is use pseudo-properties in C++ (see the C++ example at en.wikipedia.org/wiki/Property_%28programming%29). This would allow an interface identical to a struct but would still allow encapsulation and for complex behaviors to occur on access.
I'm going to try to put together an IDL mapping example that uses this concept to see if there's any interest. Hopefully, I can post it sometime tomorrow.
Trent Nadeau
Northrop Grumman Corp.
won't work
I just created a quick test, and this is going to be trouble than it's worth for complex types. Since the "." operator can't be overloaded, this makes calling methods on class-type fields (like size() on std::string or std::vector) impossible without delegating methods or having an explicitly called accessor method, which is exactly what I was trying to avoid.
Trent Nadeau
Northrop Grumman Corp.
std::swap<>
I would like to propose that for each IDL defined type we generate a specialization of std::swap<>
Adding a namespace-level swap overload
As per some of the luminaries of the C++ world, adding namespace-level swap overload is the right thing to do. Please see here: http://stackoverflow.com/questions/11562/how-to-overload-stdswap/2684544#2684544
Most C++ programmers use fully qualified standard library algorithms. So I guess it is worthwhile to have a specialization in std namespace also.
Keep it simple/intuitive
Personally I like bells and whistles, but most auto-generated code is really hard to read. So if the language mapping is anything but straight forward, it's really hard to figure out what the mapped interface looks like.
Google Protocol Buffers use functions
Google Protocol Buffers (GPB), a popular data-binding and serialization technology, uses member functions instead of direct member access. For more information visit: http://code.google.com/apis/protocolbuffers/docs/overview.html
With the member function approach, each setter function will probably need an overload that takes the parameter as an rvalue. Obviously it will double the number of setters. But they are anyways automatically generated. May be there is a way to have just N member function for N member fields by using pass-by-value parameters. (http://cpp-next.com/archive/2009/08/want-speed-pass-by-value) However, if the generated code is used with rvalue-unaware compiler, there will be significant hidden performance cost.
With the direct member access approach, as long as the member has an rvalue-aware assignment operator, copies from temporareis should be optimized away.
I tend to prefer member functions because they give freedom for state management. Particularly, copies and moves would be cheap only if implementations could use the pointer-to-impl (pimpl) idiom. For flat members, I think move is as expensive as copy.
-- Sumant (sumant@rti.com)
I would go for the plain
I would go for the plain C/C++ but with the std::string instead of the char*. Its much more intuitive.
C++x0 mapping for IDL struct
A while back I had occasion to look at the CORBA HP Enablers spec as well as the Extensible Transport Framework document. Some of the allocation and marshaling optimizations would be much easier to implement for C++ mapping types that have an actual constructor generated. Different constructors could be generated by the IDL compiler based on options, pragmas or annotations for allocation or transport. Since structs and arrays currently don't have constructors, I might lean towards generating everything possible as a class, out of consideration for folks who want to implement these optimizations. Just a thought...
Not POD structs
When you're saying "structs and arrays currently don't have constructors" I'm assuming you are referring to what the C++ spec describes as POD (plain old data) structs, i.e. fully compatible with C language structs.
I do not think the language mapping should hold back that far. We *are* talking about a C++ mapping so I think we can make use of that and possibly add constructors and/or implementation specific support methods. But let's keep the intent of the IDL struct as a data structure definition clear by keeping it a struct with public data members which can be accessed directly.