user_guide:extend:cpp_type_binding

This is an old revision of the document!


Property Type Binding to C++ Classes

Declaring a property type with c++ attribute means that the real value of each data instance of this type will be kept in a proper C++ object rather than as a bunch of perl primitive items like scalars or lists. The whole access to the data is then implemented by operator overloading, C++ method wrapping, and, in the case of C++ container types, by the standard perl technique of tied arrays and hash maps.

The first and main goal of preserving the C++ objects under the hood is to avoid performance lost: when a C++ client creates a “big” object property, e.g. a coordinate matrix, it is obviously born as a C++ object, a Matrix<Rational> or such. When the client terminates, this matrix has to be passed back to the perl world. It could be converted once to a pure perl representation, say, to a nested list of lists, but later, when another C++ client asks for this property, it will again want to fill it into its own Matrix<Rational> object, thus starting the next round of conversions. Having the original Matrix<Rational> preserved in the property eliminates the needs in any conversions at all: the client asking for a matrix gets the const reference to the original data and can work with it directly. Certainly, this mechanism applies not only for “big” object properties, but wherever the C++ objects are passed through the perl–C++ “membrane”, in particular, when catching the return value of a wrapped C++ function.

For experts in perl guts: the C++ objects are stored in the so called magic attachment. For C++ classes with container or composite (tuple) semantics the base perl type is an array (and the magic is an extension of that for tied arrays), for associative containers it is a hash map (dito for tied hash maps), otherwise it is a scalar. Actually, the value stored in the magic attachment is a copy of the (usually local) C++ object created by the client. It does not, however, constitute a serious performance problem, since the copy constructors of almost all voluminous data types in the Polymake Template Library merely clone a smart pointer. Using STL containers would yield completely different performance figures, but they are currently not bound to any property types in polymake.

A C++ object passed back to the perl side is preserved in the magic storage if and only if its class is made known to polymake by binding it or one of its ancestors (in the C++ class hierarchy) to a property type. Transient objects (e.g. MatrixMinor) can also be preserved if they belong to a generic family (in this example GenericMatrix) whose canonical representative is known to polymake (in this example either Matrix or SparseMatrix, depending on the provenience of the minor). However, when a transient C++ object is assigned to a property of a “big” object, the value stored in the magic will be of a persi

Note that derivation among property types (being declared in the rulefiles) does not interfere with underlying C++ classes. For example, the property type SparseMatrix is defined as derived from Matrix, which allows to save a lot of re-declarations of common methods like rows, cols, or minor, and also to describe any C++ function template accepting a GenericMatrix argument as accepting a Matrix on the perl side. But the corresponding C++ classes Matrix and SparseMatrix are completely independent. To the contrary, a property type derived from another one bound to a C++ class should be in its turn bound to a different C++ class, otherwise it will never be used, because all C++ clients will automatically map the underlying C++ class to the base property type.

name => "class_name"

Specifies the name of the C++ class. The class_name must be a valid C++ type expression, fully qualified with namespace names if needed. As an exception, the namespace polymake (for types from the Polymake Template Library) and the namespace of the current application polymake::APPNAME can be omitted.

If this attribute is omitted, the C++ class name is supposed to be identical to the name of the property type being defined and to be defined in the polymake namespace.

If the property type is defined as a parameterized type, the corresponding C++ type is supposed to a class template as well, having a congruent list of type parameters.

name => "class_name< type, … >"

Specifies the C++ type expression involving class templates, with the number or order of type parameters not exactly matching the property type definition. type can be either a constant type expression or a placeholder %N referring to the parameters of the property type, with N starting with 1.

name => \&sub

Specifies a subroutine synthesizing the C++ type expression. This form is used in especially complicated cases of parameterized type mapping. The subroutine is called with a list of C++ type names corresponding to the type parameters of the concrete instance; if the subroutine is declared as method, it will also get the property type descriptor as a leading argument.

builtin => "type_name"

Tells that the values of this property type are kept as plain perl entities (numbers, strings, anonymous references, …) without C++ objects lurking in the magic storage, but when such a value is passed to a C++ function, the glue code must be generated as to accept the specified C++ type. There is a very limited list of property types declared with this attribute, all of them residing in apps/common/rules/basic_types.

builtin => enum { name, … }

Introduces an enumeration type and named constants.

builtin => \&sub

Specifies a subroutine deciding for the given instance of a parameterized property type whether the values should be stored as plain perl entities or as C++ objects in the magic storage. The subroutine is called at the first occurrence of a concrete instance with the property type descriptor as a single argument.

special => "class_name"

Tells that this property type is of limited use and should not be equipped with constructors, overloaded operators, and other comforts. This attribute is used, for example, for pure type tags like Undirected or Symmetric.

include => [ "header file", … ]

Lists the header files to be included into the auto-generated glue code. For built-in types like int this list can be empty, otherwise it should contain at least the header file where the C++ class is defined. Further headers may be added automatically to the glue code for class templates depending on the parameters occurring in concrete instantiations.

default_constructor => 0

Suppresses automatic creation of standard constructors. Usually, all property types not declared with builtin or special attributes are automatically equipped with the following standard constructors:

  • default constructor: new Type()
  • parsing constructor: new Type("printable representation")
  • bulk constructor for containers: new Type([ value, … ])
  • structure constructor for composite types: new Type(init1, init2, …)

If the C++ class bound to it does not support the corresponding operation, for example, it is lacking the default constructor or the input operator >>, you should suppress the standard constructors and provide appropriate specializations of method construct in the type definition scope.

fields => [ "name", … ]

For a composite type, creates methods with given names accessing the members (aka fields of a structure). The order of the names must correspond to the order of type declarations in the specialization of pm::spec_object_traits<Type>::elements .

operators => "overloaded operators"

Defines overloaded operators and primitive functions for the property type as C++ function wrappers. The string value of this attribute is a white-space separated list of tokens of the following form:

op_symbol

A lone symbol of an operation like +, *=, bool, or "" (cf. the perl documentation `man overload` for the complete list) means that the corresponding operator is overloaded for the C++ class as well. The generated glue code will just contain the same operation symbol. Conversion to a boolean value is implemented via an explicit cast, conversion to a string via standard stream output operator << .

op_symbol:modifier

Modifies the argument passing to the operator. wary and int are allowed here.

@group
@group:modifier

A shortcut for a group of related operators. The groups are defined in the list %op_groups in the core perl module CPlusPlus.pm, the most important are @arith with four arithmetic operations and @compare with all possible comparison operations. Modifier, if any, applies to all operations in the group.

op_symbol( function header )

Maps the operator to a C++ function with given name and signature. Trailing attributes method, wary, lvalue can be specified if the function is implemented as a method of the C++ class.

Some property types are introduced solely for wrapping a vast bunch of unrelated C++ classes under a common perl interface. For example, all iterators have some common methods like dereferencing and validity check, but they don't belong to a single generic family nor are they derived from a common base class, so that no automatic type detection could help here. In such cases, an abstract property type is introduced as a parameterized type with a special wildcard symbol in lieu of a parameter list:

declare property_type Iterator<*> : c++;

Then all wrapped C++ functions returning an iterator must be explicitly declared as such:

function entire(*) : c++ : returns(Iterator<*>);

An abstract property type can't be used in definitions of “big” object properties, nor in constructor calls like new Iterator(…).

  • user_guide/extend/cpp_type_binding.1548432143.txt.gz
  • Last modified: 2019/01/25 16:02
  • by oroehrig