Clarify documentation for implicit deps and default attr values

RELNOTES: None
PiperOrigin-RevId: 203466429
diff --git a/site/docs/skylark/rules.md b/site/docs/skylark/rules.md
index 4327199..85a1941 100644
--- a/site/docs/skylark/rules.md
+++ b/site/docs/skylark/rules.md
@@ -16,7 +16,7 @@
 Note that, from Bazel's perspective, `g++` and the standard C++ libraries are
 also inputs to this rule. As a rule writer, you must consider not only the
 user-provided inputs to a rule, but also all of the tools and libraries required
-to execute the actions (called _implicit dependencies_).
+to execute the actions.
 
 Before creating or modifying any rule, make sure you are familiar with the
 [evaluation model](concepts.md). You must understand the three phases of
@@ -111,17 +111,34 @@
 [constructor](lib/Label.html#Label). The repository, and possibly the path, will
 be resolved relative to the defined target.
 
-The following attributes are implicitly added to every rule: `deprecation`,
+If an attribute schema is defined in the rule but no value for that attribute is
+given when the rule is instantiated, then the rule implementation function will
+see a placeholder value in `ctx.attr`. The placeholder value depends on the type
+of attribute. If the schema specifies a `default` value, that value will be used
+instead of the placeholder. The schema may also specify `mandatory=True`, in
+which case it is illegal for the user to not give an explicit value. It is not
+useful for an attribute schema with `mandatory` to also have a `default`.
+
+The following attributes are automatically added to every rule: `deprecation`,
 `features`, `name`, `tags`, `testonly`, `visibility`. Test rules also have the
 following attributes: `args`, `flaky`, `local`, `shard_count`, `size`,
 `timeout`.
 
-### <a name="private-attributes"></a> Private Attributes
+### <a name="private-attributes"></a> Private Attributes and Implicit Dependencies
 
-Attribute names that start with an underscore (`_`) are private; users of the
-rule cannot set it when creating targets. Instead, it takes its value from the
-default given by the rule's declaration. This is used for creating *implicit
-dependencies*:
+A dependency attribute with a default value is called an *implicit dependency*.
+The name comes from the fact that it is a part of the target graph that the user
+does not specify in a BUILD file. Implicit dependencies are useful for
+hard-coding a relationship between a rule and a tool (such as a compiler), since
+most of the time a user is not interested in specifying what tool the rule uses.
+From the rule's point of view, the tool is still an input, just like any source
+file or other dependency.
+
+Sometimes we want to not only provide a default value, but prevent the user from
+overriding this default. To do this, you can make the attribute *private* by
+giving it a name that begins with an underscore (`_`). Private attributes must
+have default values. It generally only makes sense to use private attributes for
+implicit dependencies.
 
 ```python
 metal_binary = rule(
@@ -138,9 +155,14 @@
 ```
 
 In this example, every target of type `metal_binary` will have an implicit
-dependency on the target `//tools:metalc`. This allows the rule implementation
-to generate actions that invoke the compiler, without requiring users to know
-and specify the compiler's label.
+dependency on the compiler `//tools:metalc`. This allows `metal_binary`'s
+implementation function to generate actions that invoke the compiler, even
+though the user did not pass its label as an input. Since `_compiler` is a
+private attribute, we know for sure that `ctx.attr._compiler` will always point
+to `//tools:metalc` in all targets of this rule type. Alternatively, we could
+have named the attribute `compiler` without the underscore and kept the default
+value. This lets users substitute a different compiler if necessary, but
+requires no awareness of the compiler's label otherwise.
 
 ## Implementation function
 
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java
index 1da54ba..ee98e49 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java
@@ -96,7 +96,8 @@
 
   static final String DEFAULT_ARG = "default";
   // A trailing space is required because it's often prepended to other sentences
-  static final String DEFAULT_DOC = "The default value of the attribute. ";
+  static final String DEFAULT_DOC =
+      "A default value to use if no value for this attribute is given when instantiating the rule.";
 
   static final String DOC_ARG = "doc";
   static final String DOC_DOC =
@@ -112,7 +113,8 @@
   static final String FLAGS_DOC = "Deprecated, will be removed.";
 
   static final String MANDATORY_ARG = "mandatory";
-  static final String MANDATORY_DOC = "True if the value must be explicitly specified.";
+  static final String MANDATORY_DOC =
+      "If true, the value must be specified explicitly (even if it has a <code>default</code>).";
 
   static final String NON_EMPTY_ARG = "non_empty";
   static final String NON_EMPTY_DOC =
@@ -233,9 +235,17 @@
 
   @SkylarkCallable(
       name = "label",
-      doc =
-          "Creates a schema for a label attribute. This is a dependency attribute."
-              + DEPENDENCY_ATTR_TEXT,
+      doc = "Creates a schema for a label attribute. This is a dependency attribute."
+              + DEPENDENCY_ATTR_TEXT
+              + "<p>In addition to ordinary source files, this kind of attribute is often used to "
+              + "refer to a tool -- for example, a compiler. Such tools are considered to be "
+              + "dependencies, just like source files. To avoid requiring users to specify the "
+              + "tool's label every time they use the rule in their BUILD files, you can hard-code "
+              + "the label of a canonical tool as the <code>default</code> value of this "
+              + "attribute. If you also want to prevent users from overriding this default, you "
+              + "can make the attribute private by giving it a name that starts with an "
+              + "underscore. See the <a href='../rules.$DOC_EXT#private-attributes'>Rules</a> page "
+              + "for more information.",
       parameters = {
         @Param(
             name = DEFAULT_ARG,
@@ -359,8 +369,7 @@
 
   @SkylarkCallable(
       name = "string_list",
-      doc =
-          "Creates a schema for a list-of-strings attribute.",
+      doc = "Creates a schema for a list-of-strings attribute.",
       parameters = {
         @Param(
             name = MANDATORY_ARG,