===== Writing C++ Clients ===== In polymake speak, a client is a function written in C++, devoted to a strictly confined task, like constructing a new polytope of some special kind, or performing some performance-critical operation like convex hull computation. Clients always belong to an application, the source code sitting in ''apps/APPNAME/src'' directory of the core system or of an extension. ==== Overall Structure ==== #include "polymake/client.h" #include "polymake/Matrix.h" #include "polymake/Rational.h" #include "polymake/list" ... namespace polymake { namespace APPNAME { function definitions glue declarations } } ''polymake/client.h'' is a mandatory header included in each client. It is followed by further headers, including, but not restricted to, the polymake template library, standard C++ library, and any involved third-party software. For the most popular STL container classes polymake offers small adornments (in form of traits classes) allowing for sharing the data between C++ and perl as well as formatted screen output; in this cases, a header file with ''polymake/'' prefix should be included. The namespaces are obligatory too; the name of the inner namespace must exactly match the application the client belongs to. //Glue declarations// are special macros described [[#connection_to_perl|below]]; their purpose is to make the perl part of polymake aware of the existence of the C++ function and to provide for conversion of arguments and results between the C++ and perl worlds. Auxiliary functions without direct connection to perl should be enclosed in an anonymous namespace nested within application namespace, to prevent potential clashes with other clients. If you have the feeling that some auxiliary functions may be useful in several clients, you should declare them in a separate header file, residing in the application subtree ''apps/APPNAME/include'', and include this header in all clients using it. Which client source file will harbor their definitions, doesn't matter from the technical point of view; choose it upon your taste. ==== Object Interface ==== Under Objects in this section the "big" polymake objects are meant, like Polytope or SimplicialComplex. They are represented by C++ class ''BigObject'', which is automatically defined if you include ''polymake/client.h''. The interface of ''BigObject'' looks practically identical to that of its perl brother ''[[scripting:start#Object|Object]]'', up to inevitable syntactical deviations. Wherever a string literal appears as a function argument in the examples below, a ''std::string'' instance may be used as well. === Construction === -- Creating an empty object: ? ''%%BigObject p("Polytope");%%'' :: with a type given literally ? ''%%BigObject p("Polytope", mlist());%%'' :: with a parametrized type depending on template parameters of the enclosing function or class ? ''%%BigObject p(q.type());%%'' :: with a same type as of another ''BigObject'' ? ''%%BigObject p(t);%%'' :: with a type given by an [[#ObjectType]] instance .. An empty object may be filled with properties one by one, using ''take'' methods described further. The initialization phase is completed as soon as one of the following happens: * ''give'' method is called, asking for a property not contained in the initial set * the object is returned by the C++ client back to its caller on the perl side .. After this, the object becomes //immutable//, that is, only properties declared as //mutable// may be changed and/or added. -- Creating an object in an //invalid// state: ? ''BigObject p{};'' :: The default constructor is primarily provided to enable arrays of Objects. The only allowed operations on an Object in invalid state is an assignment from another ''BigObject''. -- Creating a copy of another object: ? ''%%BigObject p=q.copy();%%'' :: as an exact copy less temporary properties ? ''%%BigObject p("Polytope", q);%%'' :: as a copy of the same or related type specified literally ? ''%%BigObject p(t, q);%%'' :: ... or given by an [[#ObjectType]] instance .. The object created this way is //immutable// from the very beginning. .. The source and target types in the converting copy constructor are called //related// if either one of them is derived from another, or both stem from the same parametrized type. If the target type is the ancestor of the source type, only properties being common to both types are copied, the rest is silently discarded. The same applies for augmented subobject types: only properties defined for the stand-alone object type are copied. Copying from one parametrized instance to another implies conversion of all properties whose types are dependent on the parameters being different between the target and the source. .. For example, let ''p'' be a ''Polytope'': * ''%%BigObject q("Polytope", p)%%'' will convert ''VERTICES'', ''FACETS'', and all other coordinate-related properties from ''Matrix'' into ''Matrix'', ''Vector'' into ''Vector'', etc. * ''%%BigObject g=p.give("GRAPH");%%''\\ ''%%BigObject q=g.copy();%%'' won't copy ''EDGE_DIRECTIONS'' because this property is only defined for a graph of a polytope but not for a stand-alone graph object. * ''%%BigObject q("PointConfiguration", p);%%'' is invalid, because the source and target types are unrelated. **Attention:** the standard copy constructor ''BigObject::Object(const BigObject&)'' and assignment operator ''BigObject::operator=(const BigObject&)'' are defined, but doesn't do what you would suppose at the first glance. They don't create any new objects nor change their values. Instead, they are working with smart references tied to the real perl-side objects (and therefore are very cheap). As usual in perl, the smart references are counted, so that the real object is destroyed only when the last reference goes out of scope. Be sure to use the ''copy'' method if you really need an new independent object. === File operations === A "big" object can be loaded from a data file and saved in a new data file: BigObject p=BigObject::load("filename"); BigObject q("type"); q.save("filename"); These operations are primarily used in standalone programs linked against the [[:callable|callable library]], because the C++ client functions called from the rulefiles and scripts usually get their objects as arguments. Please note that ''save'' should only be used for objects constructed from scratch, or when you want to store a copy of an object, because any object loaded from a data file is automatically saved during its destruction. === Name and description === These two attributes are mutable, they can be changed at any time. std::string n=p.name(); std::string txt=p.description(); p.set_name("name"); p.set_description(txt); p.set_description() << txt << ... ; p.append_description() << txt << ... ; Output operators consuming the description can digest everything printable or convertible to text. Strings containing non-ASCII characters must be encoded in UTF-8. When creating an empty object, the name can be specified as an optional trailing argument of any constructor: BigObject p("Polytope, "name"); === Type === ? ''%%BigObjectType t=p.type();%%'' :: retrieve the current type of the Object. The class [[#ObjectType]] is described further ? ''%%p.isa("TightSpan")%%'' ? ''%%p.isa(t)%%'' :: returns ''true'' if the Object kept in ''p'' has the type equal to or derived from the one specified literally or by an [[#ObjectType]] instance ? ''%%p.cast("TightSpan");%%'' ? ''%%p.cast(t);%%'' :: Change the type of the Object, returns ''*this''. .. The allowance for a type cast is more restricted than that for a copy constructor: only moving along the inheritance line is allowed. Casting to a basis type leads to the lost of properties defined for the original (derived) type only. A subobject can't be cast beyond the type declared for its property in the parent object. === Properties === ? ''%%p.exists("VERTEX_LABELS")%%'' :: returns ''true'' if the property exists; may apply shortcut rules ? ''%%if (p.lookup("VERTEX_LABELS") >> labels) ...%%'' :: assigns the property value to a variable and returns ''true'' if the property exists ? ''std::string n;'' ? ''%%p.lookup_with_property_name("VERTICES | POINTS", n) >> V%%'' :: as a side effect, the name of the property actually retrieved is stored in a string object ? ''%%Matrix V = p.give("VERTICES");%%'' ? ''%%p.give("VERTICES") >> V;%%'' :: retrieve the property value. If it does not exist yet, it will be created using production rules; if this is impossible, an exception ''undefined'' will be raised. ? ''%%p.give("VERTICES | POINTS") >> V;%%'' :: retrieve the value of one of the alternatives, whatever exists or is cheaper to compute ? ''%%p.give_with_property_name("VERTICES | POINTS", n) >> V;%%'' :: as a side effect, the name of the property actually retrieved is stored in a string object ? ''%%p.take("FACETS") << F;%%'' :: set the property value. Unless the property is declared as //mutable//, this operation is only allowed during the initialization phase and in production rules having this property among their declared targets. ? ''%%p.take("FACETS_THRU_VERTICES", temporary) << F;%%'' :: create a temporary property. It will survive until the end of the execution cycle. In the interactive mode, the cycle ends after the complete evaluation of the last input line; in scripting mode it is the termination of the script. ? ''%%p.remove("POINTS_IN_FACETS");%%'' :: remove a property. Unless the property is declared as //mutable//, it may be removed only if the Object contains enough other data to reconstruct it on later demand. A production rule may remove any property declared as its source. === Subobjects === A subobject is an Object attached to another (parent) Object as a property. The class ''BigObject'' is used for accessing subobjects as well as top-level Objects. ? ''%%BigObject g=p.give("GRAPH");%%'' :: retrieve a subobject by property name ? ''%%p.give("GRAPH.ADJACENCY") >> G;%%'' :: retrieve an atomic property through several layers of hierarchy. Intermediate subobjects (here: GRAPH) do not need to exist up front, they may be created by production rules. ? ''%%BigObject p=g.parent();%%'' :: navigate to the parent object ? ''%%if (p.valid()) ...%%'' :: for a top-level Object, ''parent()'' returns an object in an invalid state ? ''%%p.take("GRAPH") << g;%%'' :: attach a complete subobject at once. The passed subobject (here: ''g'') will be copied if one of the following conditions is met: * it already belongs to another top-level object * it is backed by an XML file * copy is requested explicitly: \\ ''%%p.take("GRAPH") << g.copy();%%'' .. Otherwise ''g'' will be hooked into the parent object as is, loosing its autonomous status. ? ''%%p.take("GRAPH.ADJACENCY") << G;%%'' :: set a property in a subobject ? ''%%p.remove("GRAPH.NODE_DEGREES");%%'' :: remove a property in a subobject === Multiple subobjects === Multiple subobjects require special methods capable of choosing the desired instance. -- adding and removing ? ''%%BigObject lp=p.add("LP");%%'' :: add a new, empty subobject, to be filled later by calling ''%%lp.take(...)%%'' ? ''%%BigObject lp=p.add("LP", temporary);%%'' :: add an empty subobject temporarily ? ''%%p.add("LP", lp);%%'' :: add a fully initialized subobject ? ''%%p.add("LP", lp, temporary);%%'' :: add it temporarily ? ''%%p.remove(lp);%%'' :: remove the specified instance of a subobject; please note the difference to ''%%remove("LP")%%'' which would remove //all// instances attached under the given property. -- retrieving ? ''%%polymake::Array lps = p.give_all("LP");%%'' :: all instances at once. The result will be empty if the requested property does not exist in the given object. Note that manipulating the array, for example, deleting some of its elements, would not affect the original objects. Thanks to smart pointers behind the scene they all will survive. But you should in general handle such an Array as ''const'', just in order to avoid confusions and surprises about "unexpected" behavior. ? ''%%BigObject lp=p.lookup("LP", "name");%%'' :: retrieve an instance by its name ? ''%%BigObject sd=p.lookup("SCHLEGEL_DIAGRAM", PolymakeOptions("FACET", 1));%%'' :: retrieve an instance with matching values of one or more properties; if nothing matching is found, returns an Object in invalid state. ? ''%%sd=p.give("SCHLEGEL_DIAGRAM", PolymakeOptions("FACET", 1));%%'' :: retrieve an existing instance or create a new one with the given property values if no matching instance exists yet ? ''%%sd=p.give("SCHLEGEL_DIAGRAM", PolymakeOptions("FACET", 1), temporary);%%'' :: ... a new instance is created temporarily ? ''%%sd=p.give("SCHLEGEL_DIAGRAM");%%'' :: retrieve an arbitrary instance or try to create one by applying production rules .. The in-line option list may be replaced by a ''perl::Hash'' created in advance: \\ ''%%perl::Hash props;%%'' \\ ''%%props["FACET"] << 1;%%'' \\ ''%%sd=p.give("SCHLEGEL_DIAGRAM", props);%%'' .. This form is useful if the number or combination of options may vary at the runtime. === Rule Schedules === ? ''%%BigObject::Schedule s=p.CallPolymakeMethod("get_schedule", "PROPERTY", ...);%%'' :: Determine the optimal sequence of production rules providing the given properties. Properties of subobjects are specified in the same dotted notations as in the ''give()'' call. The object created by this method can be used in the following operations: ? ''s.valid()'' :: Returns ''true'' if the rule sequence has been found. ? ''s.apply(q)'' :: Executes the production rules on the given Object. //q// may be the same as //p//, that is, the Object used to determine the sequence, or any other Object of the same type and with the same set of properties as //p// had before the call to ''get_schedule''. ? ''ListResult props=s.list_new_properties();'' :: Returns a list of names of all properties that would be created in the course of executing the rule sequence. Properties in subobjects are encoded in dotted notation. The list will be free of duplicates even if some production rules have common target properties. The order of names in the list is, however, absolutely random. :: Sometimes, when ''get_schedule'' is called on a subobject, the list might contain rules applicable to the parent object and further ancestors. In this case, the names of properties created there will be reported with a prefix ''parent.'' repeated as many times as many levels in the hierarchy they are sitting above the given subobject. === Attachments === Attachments are arbitrary data pieces stored together with the object. They are treated much like mutable properties, that is, they can be added, changed, and removed at any time. Each attachment is identified by its name, which is supposed to be a short string. ? ''%%p.attach("NAME") << data;%%'' ? ''%%p.take("NAME", attachment) << data;%%'' :: add or replace the named attachment ? ''%%if (p.get_attachment("NAME") >> data)%%'' :: retrieve the named attachment and assigns the value to a variable; returns FALSE if it does not exist ? ''%%p.remove_attachment("NAME");%%'' :: remove the named attachment You can store in attachments data items of primitive types like ''int'' or ''std::string'' as well as C++ classes declared on the perl side as admissible property types, like ''Matrix'', ''Set'', or ''std::list''. Instances of ''BigObject'' are **not** allowed as attachments. Clients called within production rules may not access any attachments. Allowing to do so would imply the non-deterministic behavior of rules, because attachments do not contribute to the Object's intrinsic state and can be changed by user. ==== ObjectType ==== The class ''BigObjectType'' is primarily used as a helper to construct ''BigObject'' instances, as shown in examples [[#Object_interface|above]]. There is not much what could else be done with this class. ? ''%%BigObjectType t("Polytope");%%'' :: construct a type specified literally ? ''%%BigObjectType t("Polytope", mlist());%%'' :: construct a type depending on template parameters of the enclosing function or class ? ''%%BigObjectType t = p.type();%%'' :: retrieve the current type of a ''BigObject'' ? ''t.name()'' :: get the type name as a ''std::string'', e.g. ''%%"Polytope"%%'' ? ''%%t.isa("Polytope")%%'' :: returns ''true'' if the type ''t'' is equal to the given type, belongs to the given parametrized family, or is derived thereof ? ''t.isa(t2)'' :: checks the derivation relation between two types ==== Calling Arbitrary Functions and Methods ==== The following constructions allow to call any function or `big' object method having a declared perl-side interface, that is, declared in some rule file as ''function'', ''method'', ''user_function'', or ''user_method'', regardless whether it's implemented in perl or C++. ? ''%%call_function("name", arguments...);%%'' :: call an application-scope function. .. Function name may be prefixed with ''application_name::'' if it belongs to another application not imported by the current one. ? ''%%call_function("name", mlist(), arguments...);%%'' :: call a function with explicit type parameters ? ''%%obj.call_method("name", arguments...);%%'' :: call a `big' object method === Variable argument lists === Optional (keyword) arguments, ubiquitous in ''VISUAL'' functions, can be either passed in-line: obj.call_method("VISUAL", OptionSet("FacetColor", "blue", "FacetTransparency", 0.5)); or prepared up front: BigOptionSet opts; opts["FacetColor"] << "blue"; opts["FacetTransparency"] << 0.5; opts["VertexLabels"] << Array(...); obj.call_method("VISUAL", opts); Any container object can be passed elementwise to a function using ''unroll'' wrapper: Array objects; call_function("name", ..., unroll(objects), ...); Finally, the argument list can be composed dynamically, providing arguments one by one: auto prep = prepare_call_function("name"); // or: obj.prepare_call_method("name"); prep << arg1; prep << arg2; ... prep(); === Consuming results === If the return value of ''call_function'' or ''call_method'' is not used, like in examples above, the function or method is executed in void context. If the return value is assigned to a single variable (or, more generally, an //lvalue//), the function is executed in scalar context: x = call_function(...); If the return value is assigned to more than one variable or to an unrolled container, the function is executed in list context: call_function(...) >> x >> y >> z; std::vector labels; call_function(...) >> unroll(labels); The number of values returned by the function does not need to exactly match the number of target variables; excess values are silently dropped, while excess variables stay unchanged. An unrolled container swallows all return values not consumed so far. Usually a function or method is designed to be called in one specific context. There are, however, functions whose behavior may change depending on the context. For example, all ''VISUAL'' methods called in void context launch a visualization tool and show the picture, but in scalar or list contexts they return some funny object which can be passed to other visualization functions. Calling a function in a "wrong" context does not always has dramatic consequences. The following table lists all possible cases of mismatch: * void function -> scalar context: no assignment is made to the target variable * void function -> list context: receives an empty list; when used in a chained ''%%>>%%'' operator, no target variable is changed * scalar function -> list context: receives a list with a single element * list function -> scalar context: the **last** element of the list is assigned to the target variable, the rest is discarded * scalar or list function -> void context: the results are discarded === Executing polymake scripts === The mechanism described above can be used to execute polymake scripts as well. Just call the ''%%"script"%%'' function, passing to it the script file name and optional arguments: call_function("script", "my_script_file", x, y, z); === Calling a C++ function over a cached pointer === The power and flexibility of ''call_function'' mechanism comes at price of run-time overhead. The arguments must be wrapped into perl objects, then unwrapped on the receiving side, the same for result value. The overload resolution algorithm including type deduction is run anew for every call. In many cases this overhead can be avoided by using a cached function pointer. The overload resolution and argument wrapping happen only once, at the first use, the cost of subsequent calls is exactly the same as calling a function via a pointer. The cached pointer definition must use the full C++ function signature, including exact const and reference specifications of all arguments and the return value. Usually such a pointer is defined as a local static variable of an inline function wrapping it, which assures the uniqueness and reusability across all clients: Result call_name(const Arg1& arg1, Arg2 arg2, ...) { static CachedFunctionPointer func_ptr("name"); return func_ptr(arg1, arg2, ...); } Using a cached pointer allows to call function templates without injecting their definition body in the caller source code, so that they can be defined in a different application or bundled extension. The function may also have several labeled alternative implementations selectable by preference lists. The cached pointer is automatically following the changes introduced by user commands [[:user_guide:howto:shell_custom#preferences|prefer, prefer_now, and reset_preference]]. There is, however, a restriction posed on the eligible functions: they must not have keyword arguments (OptionSet), arguments with default values or explicit type parameters. The reason for this restriction is that all this is processed in the perl layer which is bypassed when calling over a pointer. An example of use of a cached function pointer for an overloaded function is solve_LP in application polytope. ==== Miscellaneous functions ==== ? ''%%var = get_custom("name")%%'' :: Retrieve the value of a custom variable. The name must be fully qualified with the package name unless it's defined in the package of the same application as this code belongs to. If the custom variable is of an array or hash map type, the C++ local variable being assigned to must be of type ''ListResult'' resp. ''OptionSet''. ? ''%%var = get_custom("name", "key")%%'' :: Retrieve the value of an element of a custom hash map variable. ? ''%%save_data("filename", var, "description");%%'' :: Store an item of a data type known as a [[user_guide:extend:rulefiles#type_definitions|property type]] (not a "big" object!) in an XML file. The description string is optional. ? ''%%var = load_data("filename");%%'' :: Retrieve the data stored in an XML file created with ''save_data''. All retrieval functions, similar to ''Object::give()'', can also be used with an "input" ''%%operator >>%%'' : \\ ''%%get_custom("name") >> var;%%'' ? ''%%int d = get_debug_level();%%'' :: Get the current value of the global variable ''$DebugLevel'', which is initially set according to the occurrence of ''-d'' command-line options of ''polymake'' main script. A C++ client may decide to produce additional debugging output depending on this value. ==== Connection to perl ==== There are several macros helping to form the glue between C++ and perl worlds. The most important of them are four macros for functions: ''Function4perl'', ''FunctionTemplate4perl'', ''UserFunction4perl'', and ''UserFunctionTemplate4perl''. ''%%UserFunction...%%'' macros differ from the corresponding ''%%Function...%%'' macros by one additional **leading** argument, which must be a (very long) string literal with [[help_formatting|help text]], looking much like the comments in the rule files. The following example is the abridged help text from the client ''polytope::cube'' : "# @category Producing from scratch" "# Produce a //d//-dimensional cube." "# @param Int d the dimension" "# @return Polytope", Please note the comma after the very end of the string: it separates the help text from the following macro argument, which might also be a string literal in some cases. The behavior of functions declared with or without ''User'' prefix is exactly the same; the only difference is that user functions appear in the TAB completion lists, as well as in the interactive help and on the reference documentation pages, while the "bare" functions stay invisible to the user (but she can still call the latter from the interactive shell or from scripts, if she knows about them). All examples and explanations following below are equally applicable to both pairs of macros. ''Function4perl'' is used to bind regular C++ functions. It has two arguments: the first one is the address of the C++ function (like ''&cube''), the second one is a string defining the [[user_guide:extend:polymorphic#signature|perl-side signature]] much like it is done in the rulefiles. ''FunctionTemplate4perl'' is used to bind function templates. It has only one argument, namely the string containing the [[user_guide:extend:polymorphic#signature|signature]] and [[user_guide:extend:polymorphic#attributes|optional attributes]] describing the return value. The perl-side name specified in the signature must be identical to the C++ name. The perl-side arguments defined in the signature must match the parameters of the C++ function. The matching rules are, however, flexible and allow for quite elaborate mapping between the perl and C++ worlds. You are even allowed to map several perl signature to the same C++ function (by writing several ''Function'' macros with different signatures) or map one single perl signature to several C++ functions (by providing overloaded instances of the latter in your source code). Below you can find the matching rules for all possible elements of a signature: ? ''$'' :: The simple scalar designator swallows everything on the perl side. The corresponding parameter of the C++ function must be one of the following: * Elementary types ''bool'', ''int'', ''long'', ''double'', ''char'', and ''std::string'' * Container type like ''Set'', ''Vector'', or ''Array'', if you expect the caller to provide typeless anonymous arrays like ''[1,2,...]'' or string literals with suitable formatting like ''%%"{1 2}"%%'' for a ''Set''. * Multi-dimensional containers like ''Matrix'' under similar circumstances, i.e. when you expect arguments like nested anonymous arrays ''%%[[1,2],[3,4]]%%'' or multi-line strings. .. If the actual value passed from the perl side does not fit the C++ parameter type, an exception is raised. ? ''*'' :: The type wildcard swallows everything as well. It is only allowed in ''FunctionTemplate4perl''. The actual value passed from the perl side is analyzed during the call dispatch, where the appropriate C++ type declaration is constructed and used to generate the suitable wrapper source code. The corresponding parameter of the C++ function must be a free template type parameter. Alternatively, you may provide several specializations of the C++ function handling different cases. .. If the actual argument passed from the perl side does not have a corresponding C++ type or would lead to an ill-formed function template instantiation (e.g. because no matching C++ specialization exists), so that the compilation of the generated wrapper code fails, an exception is raised. ? PropertyType :: A regular property type declared in the rulefiles with the ''c++'' attribute (or a concrete instance of a parametrized type). This element swallows any object of that type or derived thereof. The corresponding parameter of the C++ function must be of the type declared in the ''c++'' attribute, possibly passed by a const reference. ? ParametrizedPropertyType :: A parametrized property type declared in the rulefiles with the ''c++'' attribute. This element swallows any object of any type instantiated from this parametrized type or derived thereof. It is only allowed in ''FunctionTemplate4perl''. The actual value passed from the perl side is analyzed like in the //wildcard// case, that is, for each new concrete type instance a new wrapper will be generated. The corresponding parameter of the C++ function must be one of the following: * a free template type parameter * the C++ class template as declared in the rulefiles, parametrized with free template type parameters * the class template of a generic family embracing the class declared in the rulefiles .. in all cases, possibly passed by a const reference. .. For example, the signature ''func(Matrix)'' matches any of the following C++ functions (return types do not matter here): \\ ''template int func(X);'' \\ ''template int func(const Matrix&);'' \\ ''template int func(const GenericMatrix&);'' ? ObjectType :: A `big' polymake object is always kept in a C++ object of class ''BigObject''. Both concrete types and parametrized types can be used: * ''int func(BigObject o);'' \\ ''%%Function4perl(func, "func(Polytope)");%%'' \\ any Polytope would match * ''int func(BigObject o);'' \\ ''%%Function4perl(func, "func(Polytope)");%%'' \\ only Polytope with Rational coordinates would match * ''template int func(BigObject o);'' \\ ''%%FunctionTemplate4perl("func(Polytope)");%%'' \\ any Polytope would match; the coordinate type will be included into the generated wrapper code as an explicit type parameter. ? ''&'' :: A signature element with this modifier must correspond to a parameter of the C++ function passed by a non-const reference. Trying to pass a write-protected object property to such a function will cause an exception. ? ''&&'' :: A signature element with this modifier must correspond to a "universal reference" parameter of the C++ function. The function may be instantiated with different reference types (const reference, non-const refernce, rvalue), depending on the data passed as an argument (write-protected object property or mutable value, value stored in a variable or a temporary value). .. Alternatively, there can be two distinct C++ functions, one with a const reference parameter, another one with a non-const reference parameter. ? ''&& const'' :: Like above, but mapping non-const non-temporary values to const references. ? '';'' :: Optional arguments must have default values, otherwise an exception will be raised by an attempt to initialize the C++ parameter with an ''undef'' value. The corresponding parameters of the C++ function themselves do not need to be declared with default values, because the C++ function will always be called with a full list of arguments. ? ''+'' :: An element with this modifier swallows a list of arbitrarily many objects of matching type. The corresponding argument of the C++ function must be an appropriate container like ''Set'', ''Array'', or ''std::vector''. \\ For "big" objects like ''Polytope'' the container type must be ''%%Array%%''. An attempt to use any other container will fail miserably. ? ''@'' :: This element swallows all trailing arguments of any //elementary// types, even of different ones. The corresponding argument of the C++ function must be a container. If the type of any of the trailing argument does not match the element type of this container (and can't be converted to it), an exception is raised. Don't define the C++ function with ellipsis parameter ''%%...%%'' ! ? ''%%{ option_key => default_value, ... }%%'' :: The keyword-value pairs are gathered in a hash map before the C++ function is called, the corresponding parameter must be of type ''BigOptionSet''. Options with ''undef'' default values are not stored in the OptionSet unless explicitly specified by the caller. Options with other default values are always be passed to the C++ function. ==== Injecting Rules into Clients ==== When an application is loaded, every client is processed like a mini-[[user_guide:extend:rulefiles|rulefile]], after all regular rulefiles. You can embed any perl code or special rules recognized by polymake directly into a client, using a macro InsertEmbeddedRule("rule text\n" "extending over several lines\n" "# including some comments\n"); In practice, only few use cases justify embedding into clients, because such rules are not easy to spot and every change would require a recompilation of the client library: * providing short pure perl overloaded function instances complementing the client functions defined in this client, e.g. convenience wrappers performing input and/or result transformations. * introducing [[user_guide:extend:rulefiles#credits_and_help|credit notes]] specific for this client * imposing restrictions on the use of this client like [[user_guide:extend:rulefiles#structuring_the_ruleset|REQUIRE_EXTENSION or REQUIRE_APPLICATION]]. Note that CREDIT and REQUIRE rules must precede the Function macros in the client source code in order to take effect on them. Please also keep in mind that the clients in an application are processed in an arbitrary order, thus no client should refer in its embedded rules on anything introduced in another client of the same application and extension. ==== Building and Debugging ==== As already mentioned at the very beginning, the client source code always resides in the application ''src'' directory. It can only be built together with other clients of its application or extension. Just run ''ninja -C build/Opt'' at the top directory of the polymake source tree resp. of the extension. Run ''ninja -C build/Debug'' if you are going to run it under the debugger. When your client is called for the first time, it might require a new wrapper for transforming the arguments from perl representation to C++ and the results in the opposite direction. This wrapper will be generated automatically, compiled on the fly, and loaded as a separate dynamic module. Unless you set the custom variable ''$Verbose::cpp'' to 1 or higher, you won't notice anything but some delay in execution. But, if your client is a function template, it will be really instantiated only now, so that some compiler errors might appear. To fix the errors, you don't need to leave the running polymake session in most cases! Just edit the sources of your client and repeat the call. You will only have to quit the session if you make any changes in the glue declarations like ''Function4perl''. When you quit the session later, after having fixed all compiler problems, the automatically created wrapper will be written into a separate source file, located in the subdirectory ''cpperl'' of the application. Next time polymake is started, it will recompile the client together with the wrapper once again while loading the application. If your extension is managed with source version control like git, remember to eventually commit all changes in the ''cpperl'' subdirectory. To debug a client, you must start the whole perl interpreter under gdb. Before you do this for the first time, you should store two useful settings in ''~/.gdbinit'': set breakpoint pending on set env POLYMAKE_BUILD_MODE=Debug The first one allows to set breaking points without having the binary code completely loaded into memory. This is important, because your client is compiled into a dynamic module which will be loaded together with its application. The second one provides loading dynamic modules compiled with debugging options (remember ''ninja -C build/Debug''!) Now you can start polymake as follows: gdb -args perl -S polymake If you are debugging a client compiled in the working copy of the polymake source tree, which is probably not contained in your PATH, then you should omit the option ''-S'' and specify the full path to ''/your/working/copy/perl/polymake'' instead. As soon as you see the ''(gdb)'' prompt, set a breakpoint in your client's code: b my_client.cc:123 The debugger will complain about unknown source file, but nevertheless will take note of the breakpoint. Set more breakpoints if needed. You can also set a breakpoint for events (check gdb manual). With the following command a breakpoint is set for the event that an exception is thrown: b __cxa_throw Then start the program with the usual ''run'' command. When the applications are loaded and the polymake prompt appears, trigger the execution of your client, either by calling it directly (if it is declared as a user function), or by executing a rule it's used in. polymake will stop at one of your breakpoints. The most popular data structures defined in the template library, like ''Matrix'', ''Set'', ''Array'', or ''Graph'', offer useful ''dump()'' methods when compiled with debugging support. They can be called right away from the gdb prompt: (gdb) call M.dump() The output goes to ''stderr'', thus be sure not to redirect it (polymake never does it on its own).