1# `cty` Functions system 2 3Core `cty` is primarily concerned with types and values, with behavior 4delegated to the calling application. However, writing functions that operate 5on `cty.Value` is expected to be a common enough case for it to be worth 6factoring out into a shared package, so 7[the `function` package](https://godoc.org/github.com/zclconf/go-cty/cty/function) 8serves that need. 9 10The shared function abstraction is intended to help applications provide the 11expected behavior in handling `cty` complexities such as unknown values and 12dynamic types. The infrastructure in this package can do basic type checking 13automatically, allowing applications to focus on the logic unique to each 14function. 15 16## Function Specifications 17 18Functions are defined by calling applications via `FunctionSpec` instances. 19These describe the parameters the function accepts, the return value it would 20produce given a set of parameters, and the actual implementation of the 21function. 22 23The return type is defined by a function, allowing the definition of generic 24functions whose return type depends on the given argument types or values. 25 26### Function Parameters 27 28Functions can have both fixed parameters and variadic arguments. Each fixed 29parameter has its own separate specification, while the variadic arguments 30together share a single parameter specification, meaning that they must 31all be of the same type. 32 33[`Parameter`](https://godoc.org/github.com/zclconf/go-cty/cty/function#Parameter) 34represents the description of a parameter. The `Params` member of 35`FunctionSpec` is a slice of positional parameters, while `VarParam` is 36a pointer to the description of the variadic arguments, if supported. 37 38Parameters have the following fields: 39 40* `Name` is not used directly by this package but is intended to be useful 41 in generating documentation based on function specifications. 42* `Type` is a type specification that a given argument must _conform_ to. 43 (see the `TestConformance` method of `cty.Type` for information on 44 what exactly that means.) 45* `AllowNull` can be set to `true` to permit the caller to provide null values. 46 If not set, passing a null is treated as an immediate error and the 47 implementation function is not called at all. 48* `AllowUnknown` can be set to `true` if the implementation function is 49 prepared to handle unknown values. If not set, calls with an unknown argument 50 will immediately return an unknown value of the function's return type, 51 and the implementation function is not called at all. 52* `AllowDynamicType` can be set to `true` to allow not-yet-typed values to be 53 passed. If not set, calls with a dynamic argument will immediately return 54 `cty.DynamicVal`, and neither the type-checking function nor the 55 implementation function will be called. 56 57Since dynamic values are themselves unknown, `AllowUnknown` and 58`AllowDynamicType` must be set together to permit `cty.DynamicVal` to be 59passed as an argument to the implementation function, but setting 60`AllowDynamicType` _without_ setting `AllowUnknown` has the special effect 61of allowing dynamic values to be passed into the type checking function 62_without_ also passing them to the implementation function, allowing a more 63specific return type to be specified even if the input type isn't 64known. 65 66### Return Type 67 68A function returns a single value when called. The return type function, 69specified via the `Type` field in `FunctionSpec`, defines the type this 70value will have for the given arguments. 71 72The arguments are passed to the type function as _values_ rather than as 73types, though in many cases they will be unknown values for which the only 74useful operation is to call the `Type()` method on them. Unknown values 75can be passed to the type function regardless of how the `AllowUnknown` 76flag is set on the associated parameter specification. 77 78If `AllowDynamicType` is set on a parameter specification, a corresponding 79argument may be `cty.DynamicVal`. The return type function can then handle 80this how it wishes. If the parameter _itself_ is typed as 81`cty.DynamicPseudoType` then the corresponding argument may be a value of 82_any_ type. These behaviors together allow the return type function to behave 83as a full-fledged _type checking_ function, returning an error if the caller's 84supplied types do not conform to some requirements that are not simple enough 85to be expressed via the parameter specifications alone. 86 87Returning `cty.DynamicPseudoType` from the type checking function signals that 88the function is not able to determine its return type from the given 89information. Hopefully -- but not necessarily -- the function _implementation_ 90will produce a value of a known type once the argument values are themselves 91known. 92 93Calling applications may elect to pass _known_ values for type checking, which 94then allows for functions whose return type depends on argument _values_. 95This is a relatively-rare situation, but one key example is a hypothetical 96JSON decoding function, which takes a string value for the JSON structure to 97decode. If given `cty.Unknown(cty.String)` as an argument, this function would 98need to specify its return type as `cty.DynamicPseudoType`, but if given 99a _known_ string it could infer an appropriate return type from that string. 100 101### Function Implementation 102 103The `Impl` field in `FunctionSpec` is used to specify the function's 104implementation as a Go function pointer. 105 106The implementation function takes a slice of `cty.Value` representing the 107call arguments and the `cty.Type` that was returned from the return type 108function. It must then either produce a value conforming to that given type 109or return an error. 110 111A function implementer can write any arbitrary Go code into the implementation 112of a function, but `cty` functions are intended to behave as pure functions, 113so side-effects should be avoided unless the function is specialized for a 114particular calling application that is able to accept such side-effects. 115 116If any of the given arguments are unknown and their corresponding parameter 117specifications _permit_ unknowns, the function implementation must handle 118this situation, normally by immediately returning an unknown value of the 119required return type. A function should _not_ return unknown values unless 120at least one of the arguments is unknown, since to do otherwise would 121violate the `cty` guarantee that a caller can avoid dealing with the 122complexity of unknown values by never passing any in. 123 124## The `cty` Standard Library 125 126The set of operations provided directly on `cty.Value` is intended to cover 127the basic operators of a simple expression language, but there are several 128higher-level operations that can be implemented in terms of `cty` values, 129such as string manipulations, standard mathematical functions, etc. 130 131[The standard library](https://godoc.org/github.com/zclconf/go-cty/cty/function/stdlib) 132contains a set of `cty` functions that are intended to be generally useful. 133For the convenience of calling applications, each function is provided both 134as a first-class Go function _and_ as a `Function` instance; the former 135could be useful for Go code dealing directly with `cty.Value` instances, 136while the latter is likely more useful for exposing functions into a 137language interpreter. 138 139The standard library also includes some functions that are just thin wrappers 140around the operations on `cty.Value`. These are somewhat redundant, but 141exposing them as functions has the advantage that their operands can be 142described as function parameters and so automatic type checking and error 143handling is possible, whereas the `cty.Value` operations prefer to `panic` 144when given invalid input. 145 146