File 2421-Document-opaques.patch of Package erlang

From 3d75a9928a3c27b06eb313f926dee92c2a57a8d8 Mon Sep 17 00:00:00 2001
From: Maxwell Elliot Heiber <mheiber@fb.com>
Date: Sat, 18 Dec 2021 18:35:15 +0000
Subject: [PATCH 1/3] Document opaques

close  #5240
---
 system/doc/reference_manual/opaques.xml  | 69 ++++++++++++++++++++++++
 system/doc/reference_manual/typespec.xml |  1 +
 2 files changed, 70 insertions(+)
 create mode 100644 system/doc/reference_manual/opaques.xml

diff --git a/system/doc/reference_manual/opaques.xml b/system/doc/reference_manual/opaques.xml
new file mode 100644
index 0000000000..1514ab01cb
--- /dev/null
+++ b/system/doc/reference_manual/opaques.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+  <header>
+    <copyright>
+      <year>2021</year><year>2022</year>
+      <holder>Ericsson AB. All Rights Reserved.</holder>
+    </copyright>
+    <legalnotice>
+      Licensed under the Apache License, Version 2.0 (the "License");
+      you may not use this file except in compliance with the License.
+      You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+      Unless required by applicable law or agreed to in writing, software
+      distributed under the License is distributed on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      See the License for the specific language governing permissions and
+      limitations under the License.
+
+    </legalnotice>
+
+    <title>Types and Function Specifications</title>
+    <prepared>Max Heiber</prepared>
+    <docno></docno>
+    <date></date>
+    <rev></rev>
+    <file>opaques.xml</file>
+  </header>
+
+  <section>
+    <title>Opaque Type Aliases</title>
+    <p>The main use case for opacity in Erlang is to hide the implementation of a data type, enabling evolving the API while minimizing risk of breaking consumers. The runtime does not check opacity. Dialyzer provides some opacit-checking, but the rest is up to convention.
+    </p>
+    <p>
+This document explains what Erlang opacity is (and the trade-offs involved) via the example of OTP's `sets:set()` data type. This type *was* defined in `sets` module like this:
+    </p>
+
+        <pre>-opaque set(Element) :: #set{segs :: segs(Element)}.</pre>
+            OTP 24  changed the definition to the following, in <a href="https://github.com/erlang/otp/commit/e66941e8d7c47b973dff94c0308ea85a6be1958e">this commit</a>.
+        <pre>-opaque set(Element) :: #set{segs :: segs(Element)} | #{Element => ?VALUE}.</pre>
+<p>And this change was safer and more backwards-compatible than if the type had been defined with <pre>-type</pre> instead of <pre>-opaque</pre>. Here's why: when a module defines an <pre>-opaque</pre>, the contract is that only the defining module should rely on the definition of the type: no other modules should rely on the definition.</p>
+<p>This means that code that pattern-matched on <pre>set</pre> as a record/tuple technically broke the contract, and opted in to being potentially broken when the definition of <pre>set()</pre> changed. Before OTP 24, this code printed <pre>ok</pre>. In OTP 24 it may error:</p>
+    <pre>
+    Set = sets:new(),
+caseof
+    X when is_tuple(Set) -&gt;
+        io:format(&quot;ok&quot;)
+end.
+    </pre>
+<p><strong>When working with an opaque defined in another module, here are some recommendations:</strong></p>
+
+<list type="bulleted">
+<item>Don't examine the underlying type using pattern-matching, guards, or functions that reveal the type, such as <pre>tuple_size/1</pre>.</item>
+<item>Instead, use functions provided by the module for working with the type. For example, <pre>sets</pre> module provides <pre>sets:new/0</pre>, <pre>sets:add/2</pre>, <pre>sets:is_element/2</pre>, etc.</item>
+<item><pre>sets:set(a)</pre> is a subtype of <pre>sets:set(a | b)</pre> and not the other way around. Generally, you can rely on the property that <pre>the_opaque(T)</pre> is a subtype of <pre>the_opaque(U)</pre> when T is a subtype of U.</item>
+</list>
+<p><strong>When defining your own opaques, here are some recommendations:</strong></p>
+<list type="bulleted">
+<item>Since consumers are expected to not rely on the definition of the opaque type, you must provide functions for constructing and querying/deconstructing intances of your opaque type. For example, sets can be constructed with <pre>sets:new/0</pre>, <pre>sets:from_list/1</pre>, <pre>sets:add/2</pre>, queried with <pre>sets:is_element/2</pre>, and deconstructed with <pre>sets:to_list/1</pre>.</item>
+<item>Don't define an opaque with a type variable in parameter position. This breaks the normal and expected behavior that (for example) <pre>my_type(a)</pre> is a subtype of <pre>my_type(a | b)</pre></item>
+</list>
+<p>Note that opaques can be harder to work with for consumers, since the consumer is expected not to pattern-match and must instead use functions that the author of the opaque type provides to use instances of the type.</p>
+<p>Also, opacity in Erlang is skin-deep: the runtime does not enforce opacity-checking. So now that sets are implemented in terms of maps, an <pre>is_map</pre> check on a set <em>will</em> pass. The opacity rules are only enforced by convention and by additional tooling such as Dialyzer. And this enforcement is not total: For example, determined consumer of <pre>sets</pre> can still do things that reveal the structure of the set, such as by printing, serializing, or using a set as <pre>term()</pre> and then inspecting via functions like <pre>is_map</pre> or <pre>maps:get/2</pre>. And Dialyzer must make some <a href="https://github.com/erlang/otp/issues/5118">approximations</a>. Opacity checking has limitations, but is still a vital tool in scalable Erlang development.</p>
+
+  </section>
+</chapter>
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index a450f85742..c80d4f639d 100644
--- a/system/doc/reference_manual/typespec.xml
+++ b/system/doc/reference_manual/typespec.xml
@@ -405,6 +405,7 @@
       types are not accessible by other modules anyway - and is
       always to be exported.
     </p>
+    <p>Read more on <seealso marker="opaques">Opaques</seealso></p>
   </section>
 
   <section>
-- 
2.31.1

openSUSE Build Service is sponsored by