1# Converting between `cty` types
2
3[The `convert` package](https://godoc.org/github.com/zclconf/go-cty/cty/convert)
4provides a standard set of type conversion routines for moving between
5types in the `cty` type system.
6
7_Conversion_ in this context means taking a given value and producing a
8new value of a different type that, in some sense, contains the same
9information. For example, the number `5` can be converted to a string as
10`"5"`.
11
12Specific conversion operations are represented by type `Conversion`, which
13is a function type that takes a single value as input and returns a value
14or an error.
15
16## "Safe" and "Unsafe" conversions
17
18The `convert` package broadly organizes its supported conversions into two
19types.
20
21"Safe" conversions are ones where all values of the source type can
22be represented in the target type, and thus the conversion is guaranteed to
23succeed for any value of the source type.
24
25"Unsafe" conversions, on the other hand, are able to convert only a subset
26of values of the source type. Values outside of that subset will cause the
27conversion function to return an error.
28
29Converting from number to string is safe because an unambiguous string
30representation can be created for any number. The converse is _unsafe_,
31because while a string like `"2.5"` can be converted to a number, a string
32like `"bananas"` cannot.
33
34The calling application must choose whether to attempt unsafe conversions,
35depending on whether it is willing to tolerate conversions returning errors
36even though they ostensibly passed type checking. Operations that have both
37safe and unsafe modes come in couplets, with the unsafe version's name
38having the suffix `Unsafe`.
39
40## Getting a Conversion
41
42To find out if a conversion is available between two types, an application can
43call either `GetConversion` or `GetConversionUnsafe`. These functions return
44a valid `Conversion` if one is available, or `nil` if not.
45
46Note that there are no conversions from a type to itself. Callers should check
47if two types are equal before attempting to obtain a conversion between them.
48
49As usual, `cty.DynamicPseudoType` serves as a special-case placeholder. It is
50used in two ways, depending on whether it appears in the source or the
51destination type:
52
53* When a source type is dynamic, a special unsafe conversion is available that
54  takes any value and passes it through verbatim if it matches the destination
55  type, or returns an error if it does not. This can be used as part of handling
56  dynamic values during a type-checking procedure, with the generated
57  conversion serving as a run-time type check.
58
59* When a _destination_ type is dynamic, a simple passthrough conversion is
60  generated that does not transform the source value at all. This is supported
61  so that a destination type can behave similarly to a type description used
62  for a conformance check, thus allowing this package to be used to attempt
63  to _make_ a type conformant, rather than merely check whether it already
64  is.
65
66## Converting a Value
67
68A value can be converted by passing it as the argument to any conversion whose
69source type matches the value's type. If the conversion is an unsafe one, the
70conversion function may return an error, in which case the returned value is
71invalid and must not be used.
72
73As a convenience, the `Convert` function takes a value and a target type and
74returns a converted value if a conversion is available. This is equivalent
75to testing for an unsafe conversion for the value's type and then immediately
76calling any discovered conversion. An error is returned if a conversion is not
77available.
78
79## Type Unification
80
81A related idea to type _conversion_ is type _unification_. While conversion
82is concerned with going from a specific source type to a specific target type,
83unification is instead concerned with finding a single type that several other
84types can be converted to, without any specific preference as to what the
85final type is.
86
87A good example of this would be to take a set of values provided to initialize
88a list and choose a single type that all of those values can be
89converted to, which then decides the element type of the final list.
90
91The `Unify` and `UnifyUnsafe` functions are used for type unification. They
92both take as input a slice of types and then return, if possible, a single
93target type along with a slice of conversions corresponding to each
94of the input types.
95
96Since many type pairs support type conversions in both directions, the unify
97functions must apply a preference for which direction to follow given such a
98pair of types. These functions prefer safe conversions over unsafe ones
99(assuming that `UnifyUnsafe` was called), and prefer lossless conversions
100over potentially-lossy ones.
101
102Type unification is a potentially-expensive operation, depending on the
103complexity of the passed types and whether they are mutually conformant.
104
105## Conversion Charts
106
107The foundation of the available conversions is the matrix of conversions
108between the primitive types. String is the most general type, since the
109other two primitive types have safe conversions to string. The full
110matrix for primitive types is as follows:
111
112|         | string | number | boolean |
113|---------|:------:|:------:|:-------:|
114| string  |   n/a  | unsafe |  unsafe |
115| number  |  safe  |   n/a  |   none  |
116| boolean |  safe  |  none  |   n/a   |
117
118The conversions for compound types are then derived from the above foundation.
119For example, a list of numbers can convert to a list of strings
120because a number can convert to a string.
121
122The compound type kinds themselves have some available conversions, though:
123
124|        |  tuple | object | list |   map  |     set    |
125|--------|:------:|:------:|:----:|:------:|:----------:|
126| tuple  |   n/a  |  none  | safe |  none  | safe+lossy |
127| object |  none  |   n/a  | none |  safe  |    none    |
128| list   | unsafe |  none  |  n/a |  none  | safe+lossy |
129| map    |  none  | unsafe | none |   n/a  |    none    |
130| set    | unsafe |  none  | safe |  none  |     n/a    |
131
132Conversions between compound kinds, as shown above, are possible only
133if their respective elements/attributes also have conversions available.
134
135The conversions from structural types to collection types rely on
136type unification to identify a single element type for the final collection,
137and so conversion is possible only if unification is possible.
138
139## Conversion between Object Types
140
141There are some special considerations for conversion between distinct object
142types that do not apply to conversion between types of other kinds.
143
144For object types, `convert` implements _structural typing_ behaviors, where
145the target type is considered to be a description of a set of attributes the
146final result should have. There are two important additional concerns that
147result from this design intent:
148
149* If the input type has additional attributes that are not mentioned at all
150  in the target type, those additional attributes are silently discarded
151  during conversion, leading to a new object value that has a subset of the
152  attributes of the input value, and whose type therefore conforms to the
153  target type constraint.
154
155* If any of the attributes of the target type are marked as optional using
156  the **currently-experimental** `cty.ObjectWithOptionalAttrs` constructor,
157  type conversion will tolerate those attributes being absent in the given
158  type, and the resulting value will include appropriately-typed null value
159  placeholders as the values of those omitted attributes.
160
161    This behavior is subject to change even in future minor versions of the
162    `cty` module, so that we can try it out with experimental versions of
163    calling applications and adjust the details of the behavior if needed.
164    Hopefully this mechanism will be stabilized in a future release, if those
165    downstream experiments are successful.
166