1# Value Marks 2 3---- 4 5**Note:** Marks are an optional feature that will not be needed in most 6applications. If your application never uses this API then you don't need to 7worry about encountering marked values, and you can ignore this document. 8 9---- 10 11A `cty.Value` can optionally be _marked_, which causes it to carry around some 12additonal metadata along with its value. Marks are just normal Go values that 13are value to use as map keys, and are compared by equality. 14 15For example, an application might use marks to track the origin of a particular 16value in order to give better error messages, or to present the value in a 17different way in a UI. 18 19```go 20// Use a named type for all marks, for namespacing purposes. 21type fromConfigType int 22val fromConfig fromConfigType 23 24return val.Mark(fromConfig) 25``` 26 27```go 28if val.HasMark(fromConfig) { 29 // Maybe warn the user that the value is derived from configuration? 30 // Or whatever makes sense for the calling application. 31} 32``` 33 34When a value is marked, operation methods using that value will propagate the 35marks to any result values. That makes marks "infectious" in the sense that 36they propagate through operations and accumulate in the result automatically. 37 38However, marks cannot propagate automatically thruogh _integration_ methods, 39and so a calilng application is required to explicitly _unmark_ a value 40before using them: 41 42```go 43val, valMarks := val.Unmark() 44// ...then use integration methods with val, 45// eventually producing a result that propgates 46// the marks: 47return result.WithMarks(valMarks) 48``` 49 50## Marked Values in Sets 51 52Sets present an interesting problem for marks because marks do not contribute 53to equality of two values and thus it would be possible in principle to add 54the same value to a given set twice with different marks. 55 56To avoid the complexity of tracking superset marks on a per-element basis, 57`cty` instead makes a compromise: sets can never contain marked values, and 58if any marked values are passed to `cty.SetVal` then they will be automatically 59unmarked and the superset of all marks applied to the resulting set as a whole. 60 61This is lossy about exactly which elements contributed which marks, but is 62conservative in the sense that any access to elements in the set will encounter 63the superset marks as expected. 64 65## Marks Under Conversion 66 67The `cty/convert` package is aware of marks and will automatically propagate 68them through conversions. That includes nested values that are marked, which 69will be propagated to the corresponding nested value in the result if possible, 70or will be simplified to marks on a container where an exact propagation is not 71possible. 72 73## Marks as Function Arguments 74 75The `cty/function` package is aware of marks and will, by default, 76automatically unmark all function arguments prior to calling a function and 77propagate the argument marks to the result value so that most functions do 78not need to worry about handling marks. 79 80A function may opt in to handling marks itself for a particular parameter by 81setting `AllowMarks: true` on the definition of that parameter. If a function 82opts in, it is therefore responsible for correctly propagating any marks onto 83its result. 84 85A function's `Type` implementation will receive automatically-unmarked values 86unless `AllowMarks` is set, which means that return-type checking alone will 87disregard any marks unless `AllowMarks` is set. Because type checking does not 88return a value, there is no way for type checking alone to communicate which 89marks it encountered during its work. 90 91If you're using marks in a use-case around obscuring sensitive values, beware 92that type checking of some functions could extract information without 93preserving the sensitivity mark. For example, if a string marked as sensitive 94were passed as the first argument to the stdlib `JSONDecode` function then 95type-checking of that function will betray the object property names inside 96that value as part of the inferred result type. 97 98## Marks Under Serialization 99 100Marks cannot be represented in either the JSON nor the msgpack serializations 101of cty values, and so the `Marshal` functions for those will return errors 102if they encounter marked values. 103 104If you need to serialize values that might contain marks, you must explicitly 105unmark the whole data structure first (e.g. using `Value.UnmarkDeep`) and then 106decide what to do with those marks in order to ensure that if it makes sense 107to propagate them through the serialization then they will get represented 108somehow. 109