user_guide:extend:polymorphic

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
reference:polymorphic [2018/08/27 22:00] – [Type parameter deduction] gawrilowuser_guide:extend:polymorphic [2021/01/12 15:46] (current) – [Labels] gawrilow
Line 6: Line 6:
 Let's recall that a polymorphic function is introduced with the following header: Let's recall that a polymorphic function is introduced with the following header:
  
-category labels '':'' name ''<'' type parameters > ''['' typecheck ''] ('' signature '') : '' attributes+category label '':'' name ''<'' type parameters > ''['' typecheck ''] ('' signature '') : '' attributes
  
 //category// can be ''method'', ''function'', etc., as described in the [[rulefiles#functions|general syntax rules]]. //category// can be ''method'', ''function'', etc., as described in the [[rulefiles#functions|general syntax rules]].
  
-Name and signature are mandatory, while labels, type parameters, and attributes are optional.+Name and signature are mandatory, while label, type parameters, and attributes are optional.
  
 ===== Signature ===== ===== Signature =====
-The signature describes the number and types of arguments expected by an overloaded instance, as well as default values for optional arguments.  The syntax of the most primitive elements is borrowed from the standard perl //function prototypes//, enriched with further elements for [[reference:rulefiles#type_definitions|property types]] and "big" object types, [[reference:rulefiles#fuctions|option lists]] and other keyword arguments, etc.  The "standard" elements are encoded with one-symbol codes, they can be written in traditional style glued together, or in a more legible style with commas and white spaces in between.  Advanced elements must be separated with commas.+The signature describes the number and types of arguments expected by an overloaded instance, as well as default values for optional arguments.  The syntax of the most primitive elements is borrowed from the standard perl //function prototypes//, enriched with further elements for [[user_guide:extend:rulefiles#type_definitions|property types]] and "big" object types, [[user_guide:extend:rulefiles#fuctions|option lists]] and other keyword arguments, etc.  The "standard" elements are encoded with one-symbol codes, they can be written in traditional style glued together, or in a more legible style with commas and white spaces in between.  Advanced elements must be separated with commas.
  
 Signatures of pure perl functions and wrapped C++ functions share many common elements, but also have few differences.  Unless mentioned explicitly, the elements described below may be used in both cases.  C++ functions are recognized by the ''c++'' [[#attributes|attribute]]. Signatures of pure perl functions and wrapped C++ functions share many common elements, but also have few differences.  Unless mentioned explicitly, the elements described below may be used in both cases.  C++ functions are recognized by the ''c++'' [[#attributes|attribute]].
Line 28: Line 28:
   :: Denotes a single argument of a type being an instantiation of a parametrized type, or derived thereof.  If all parameters are concrete types, only arguments belonging to the resulting type instance will be accepted.  If some parameters are replaced with ''_'', i.e. //wildcards//, any matching type instances will be accepted.  Specifying all parameters as wildcards is equivalent to omitting the entire parameter list, that is, this function will accept any instance of the parametrized family.  Specifying an empty parameter list ''<>'' means assuming default values for all parameters, which eventually yields one concrete type instance.   :: Denotes a single argument of a type being an instantiation of a parametrized type, or derived thereof.  If all parameters are concrete types, only arguments belonging to the resulting type instance will be accepted.  If some parameters are replaced with ''_'', i.e. //wildcards//, any matching type instances will be accepted.  Specifying all parameters as wildcards is equivalent to omitting the entire parameter list, that is, this function will accept any instance of the parametrized family.  Specifying an empty parameter list ''<>'' means assuming default values for all parameters, which eventually yields one concrete type instance.
   ? ''type_upgrades_to< '' typename ''>''   ? ''type_upgrades_to< '' typename ''>''
-  :: Denotes a single argument which may either be of the given type or of type that can be upgraded to it, directly or transitively.+  :: Denotes a single argument of the given type or of another type that can be upgraded to it, directly or transitively.  For functions implemented in C++, the argument received by the function will be upgraded automatically by calling an appropriate constructor of the target type - just as a consequence of C++ type coercion rules.  Functions implemented in perl, however, will see the original value as passed by the caller.  They can use ''convert_to<TYPE>()'' to obtain an object of the desired type. 
 +  ? ''can_convert_to< '' typename ''>'' 
 +  :: Denotes a single argument of the given type or any other type accepted by its constructor.  Depending on the target type, this can include plain strings, scalars and anonymous lists.  The conversion, if needed, always takes place before entering the function, including ones implemented in pure perl.
   ? ''@''   ? ''@''
-  :: Denotes arbitrarily many (trailing) arguments of any types.  This element must be the last one among all arguments in the signature.+  :: Denotes arbitrarily many (trailing) arguments of any types.  This element must be the last one among all arguments in the signature.  This is only allowed with functions implemented in perl.  For C++ functions, an appropriate container type (Array, Vector, etc.) must be used.
   ? ''%''option_list   ? ''%''option_list
   :: Refers to an [[rulefiles#functions|option list]] defined in the rulefiles before.  Trailing argument pairs of the form ''%%keyword => value%%'' with keywords matching the keys of the option list are collected together in an anonymous hash map, which is passed to the function body by reference.   :: Refers to an [[rulefiles#functions|option list]] defined in the rulefiles before.  Trailing argument pairs of the form ''%%keyword => value%%'' with keywords matching the keys of the option list are collected together in an anonymous hash map, which is passed to the function body by reference.
Line 101: Line 103:
  
 ==== Typechecks ==== ==== Typechecks ====
-A type checking clause may be specified for functions with type parameters.  It can contain an expression performing arbitrary checks on the deduced or explicitly given type parameters, e.g. by calling a [[reference:rulefiles#typechecks|type checking function]].  Default values for type parameters, if applicable, are assigned prior to evaluation of the type checking expression.  The expression should return a boolean value signaling success or failure; it must not raise exceptions.  In the successful case, the function body is executed; otherwise, the function is discarded from candidates and the overload resolution continues.+A type checking clause may be specified for functions with type parameters.  It can contain an expression performing arbitrary checks on the deduced or explicitly given type parameters, e.g. by calling a [[user_guide:extend:rulefiles#typechecks|type checking function]].  Default values for type parameters, if applicable, are assigned prior to evaluation of the type checking expression.  The expression should return a boolean value signaling success or failure; it must not raise exceptions.  In the successful case, the function body is executed; otherwise, the function is discarded from candidates and the overload resolution continues.
  
 Besides performing pure checks, the type checking clause may upgrade the deduced parameter values by calling a meta-function ''type_upgrade<''T'','' other type''>'' This meta-function upgrades T to //other type// if it is allowed by upgrade relations and T has not been explicitly specified by the caller.  Even if the upgrade is not possible, this function succeeds and simply returns the unchanged type of T. Besides performing pure checks, the type checking clause may upgrade the deduced parameter values by calling a meta-function ''type_upgrade<''T'','' other type''>'' This meta-function upgrades T to //other type// if it is allowed by upgrade relations and T has not been explicitly specified by the caller.  Even if the upgrade is not possible, this function succeeds and simply returns the unchanged type of T.
Line 118: Line 120:
   :: Tells that the function returns an object which can be modified by assigning a value to it.  Primarily used with methods giving access to elements of some data container like a matrix or vector.   :: Tells that the function returns an object which can be modified by assigning a value to it.  Primarily used with methods giving access to elements of some data container like a matrix or vector.
   ? ''returns('' type '')''   ? ''returns('' type '')''
-  :: Tells that the function returns an object of the given type.  Usually the return value is automatically recognized by the auto-generated wrapper and hooked under an appropriately "blessed" perl reference.  This attribute should only be used in special cases where the automatic recognition does not work or must be overridden.  In particular, this attribute must be used with [[reference:cpp_type_binding#abstract_property_types|abstract property types]].+  :: Tells that the function returns an object of the given type.  Usually the return value is automatically recognized by the auto-generated wrapper and hooked under an appropriately "blessed" perl reference.  This attribute should only be used in special cases where the automatic recognition does not work or must be overridden.  In particular, this attribute must be used with [[user_guide:extend:cpp_type_binding#abstract_property_types|abstract property types]].
   ? ''returns(@)''   ? ''returns(@)''
   :: Tells that the function returns several values in a list context.  As usual in perl, when called in scalar context, the //last// value from the list will be taken for further processing.   :: Tells that the function returns several values in a list context.  As usual in perl, when called in scalar context, the //last// value from the list will be taken for further processing.
Line 144: Line 146:
  
 ===== Hybrid functions ===== ===== Hybrid functions =====
-Usually a function is either implemented in pure (polymake dialect of) perl or wrapped from the C++ side.  In the first case the instance body with the code is directly following the header, like in a standard perl subroutine, in the second case the list of [[#attributes|attributes]] is concluded by a semicolon.+Usually a function is either implemented in pure (polymake dialect of) perl or in pure C++.  In the first case the instance body with the code is directly following the header, like in a standard perl subroutine, in the second case the list of [[#attributes|attributes]] is concluded by a semicolon.
  
-Sometimes you might find more convenient to combine some preliminary checks or preparations on argument values with a proper call into C++ function, or even skip the latter call under certain circumstances.  Although such scenarios can surely be modeled by defining two functions, outer one written in perl, and the inner one as wrapped C++ function, this also can be written more compactly (and more efficiently) as a hybrid function.  Such a function has both the ''c++'' attribute //and// a body with perl code.  The perl body is called first; if it returns any value with an explicit ''return'' statement or raises an exception, the C++ function is not called at all; if the perl body runs to the end without executing any ''return''s, the control is passed to the wrapped C++ function.+Sometimes you might find more convenient to combine some preliminary checks or preparations on argument values with a proper call into C++ function, or even skip the latter call under certain circumstances.  Although such scenarios can surely be modeled by defining two functions, outer one written in perl, and the inner one as wrapped C++ function, this also can be written more succinctly (and more efficiently) as a hybrid function.  Such a function has both the ''c++'' attribute //and// a body with perl code.  The perl body is executed first; if it returns any value with an explicit ''return'' statement or raises an exception, the C++ function is not called at all; if the perl body runs to the end without executing any ''return''s, the control is passed to the wrapped C++ function.
  
 Usually a hybrid function looks like this: Usually a hybrid function looks like this:
Line 157: Line 159:
  
 ===== Labels ===== ===== Labels =====
-Labels allow to differentiate between several overloaded instances with identical signatures.  Without labels, occurrence of functions with compatible signatures would inevitably give rise to a fatal error.  (Recall that two signatures are //compatible// if they would match the same argument list shortened by all optional arguments).  With labelsthe instances with compatible signatures are bundled together in lists, which are consulted at the end of the overload resolution.  The actual function body to be executed is taken from the head of the candidate list.  If one of the labels is made preferred by executing a command ''prefer'' or ''prefer_now'', the corresponding instance is moved to the head of the list.  Otherwise the order of the instances is more or less randomthus it is unpredictable which instance is called in absence of any active preferences.+Labels allow to provide several alternative implementations for the same function or for a family of functions with compatible signatures.  The choice of the function to be called is governed by active preference lists (cf. user commands [[:user_guide:howto:shell_custom#preferences|prefer, prefer_now, show_preferences]]).  Firstall candidates with the label of the highest rank are considered according to usual overload resolution rules.  If none has matched the argument list, the candidates with the label of the next lower rank are consideredand so on.
  
-The application can also obtain the complete candidate list, ordered according to currently active preferences, by executing ''%%$list=Overload::resolve_labeled("%%//PACKAGE//%%", "%%//NAME//%%", %%//args//%%);%%''  The package name to search within can be replaced with special token ''%%__PACKAGE__%%'' designating the current package.+Labels are mandatory for //global methods// The overload resolution for global methods runs slightly differently from other functions.  The application first calls ''$method=Overload::Global:://NAME//(//args//%%...%%)'' to obtain the code reference pointing to the currently preferred method matching the given list of arguments.  Then it creates an object of the corresponding class using something like ''%%$object=method_owner($method)->new(...);%%'' or retrieves suitable object in whatever appropriate way, and finally calls the method, passing the obtained object as a leading argument: ''%%$method->($object, %%//args//%%...);%%''
  
-While assigning labels to functions is optionalfor one category of polymorphic functions labels are mandatory, namely for //global methods//.  The overload resolution for global methods runs slightly differently from the normal methods.  The application code first calls ''$method=Overload::Global:://NAME//(//args//)'' to obtain the code reference pointing to the currently preferred method matching the given list of arguments.  Then it creates an object of the corresponding class using something like ''%%$object=method_owner($method)->new(...);%%'' or retrieves a suitable object in whatever appropriate wayand finally calls the method, passing the obtained object as leading argument: ''%%$method->($object%%//args//%%);%%'' +Alternativelythe application can request the full list of candidate methods from ''Overload::resolve_global(//NAME//, [ //args//%%...%% ])'' the argument list must be passed by reference.  The result will be reference to a list of method referencesordered according to the current label ranking.
- +
-Note that the method selected in the first step is looked for in //all// packages defining global method instances with the given name.+
  
  • user_guide/extend/polymorphic.1535407248.txt.gz
  • Last modified: 2018/08/27 22:00
  • by gawrilow