I think the best way to think about these is that computed is mostly independent of optional vs. required.
The flag computed means that the provider may choose an arbitrary value (as long as it has the correct type) for that attribute. If computed is not set, then only the configuration can choose a value and the provider will honor it.
The presence of either optional or required signals that the configuration can provide a value for the attribute. In the case of required, the configuration must provide a value for the attribute. In the case of optional, if the attribute is not set in configuration then its value is null. optional and required are mutually-exclusive because their definitions conflict with one another.
The trickiest case is the one where both optional and computed appear together. That combines together the two situations above, meaning that the attribute can be chosen either by the configuration or by the provider, with the configuration taking precedence. Or to phrase it in a more user-oriented way: the provider can choose a default value to use if and only if there is no value set in the configuration.
In the interests of completeness, I’ll note also that required and computed conflict with one another because (given that configuration always takes priority over a provider’s defaults) there is no situation where a default value can ever be selected for a required attribute.
Perhaps the above will be easier to follow as a table of the valid combinations:
computed |
optional |
required |
Meaning |
| ✓ |
|
|
The value is always chosen by the provider. |
|
✓ |
|
The value is chosen by the configuration, or null if no value is set there. |
|
|
✓ |
The value is chosen by the configuration and must always be set there. |
| ✓ |
✓ |
|
The value is chosen by the configuration if set, or by the provider if not set. |
Looking at the JSON format documentation I can see that the comment attached to computed is not complete, because it only discusses the case where computed is used alone and doesn’t mention how it interacts with optional.
Another thing I want to note here, since I can see the potential for confusion, is that the terraform providers schema -json output is describing the schema in the terms Terraform Core understands, while the Terraform SDK (what the “extend” section of the documentation is discussing) is at a higher level of abstraction due to its own built-in validation behaviors and so while the concepts do overlap slightly, the extend documentation includes some details that do not apply to the terraform providers schema -json output.
Finally, some older provider features currently get a pass for exactly honoring the above requirements as an allowance for historical compatibility. That should phase out in the coming months as support for Terraform 0.11 in new provider releases comes to an end and the SDK can therefore use more modern behaviors throughout, but as I write this there are some situations you may encounter where a provider behaves as if it had set computed to true even though it actually did not.
For use-cases involving configuration generation those compatibility exceptions are usually not a problem since the values chosen by the provider are not involved in code-generation use-cases anyway. I point it out just in case you have different goals in your work where it might be significant that the final result of a Terraform action can potentially differ from the configuration even though computed wasn’t set.