<div dir="ltr">Reversing the subtyping solves <i>this problem</i>, but makes int() unusable outside of the foo module. If the foo module would return an int() value from an exported function, bar couldn't look into it, because int() is just a subtype of the opaque type ext(), and Dialyzer would (rightfully) give you a warning about peeking into an opaque type.<div><br></div><div>/Daniel</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 25 Feb 2020 at 11:51, Fernando Benavides <<a href="mailto:elbrujohalcon@gmail.com">elbrujohalcon@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif">Another way to make it work is to define your types like this…</div><div class="gmail_default"><font face="monospace"><br></font></div><div class="gmail_default"><font face="monospace">-opaque ext() :: atom().<br>-type int() :: ext().<br></font></div><div class="gmail_default"><font face="monospace">-opaque f() :: #f{f :: int()}.<br></font></div><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif"><br></div><div class="gmail_default"><span style="font-family:"trebuchet ms",sans-serif">In other words, reversing the subtyping by making int/0 a subtype of ext/0. Remember: </span><font face="monospace">::</font><font face="trebuchet ms, sans-serif"> does not mean "is equal to" it means "is a subtype of".</font></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Feb 25, 2020 at 11:43 AM Fernando Benavides <<a href="mailto:elbrujohalcon@gmail.com" target="_blank">elbrujohalcon@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif">I think there is a bug somewhere, but as you probably know the warning also goes away if you change this…</div><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif"><div style="font-family:Arial,Helvetica,sans-serif"><font face="monospace">-opaque f() :: #f{f :: int()}.</font></div></div><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif">…to this…</div><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif"><div style="font-family:Arial,Helvetica,sans-serif"><font face="monospace">-opaque f() :: #f{f :: ext()}.</font></div></div><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif"><br></div><div class="gmail_default" style="font-family:"trebuchet ms",sans-serif">And the thing is that, according to what I <i>think</i> dialyzer believes, all ext()s are int()s but not all int()s are ext()s. You can't pass an expression of type int() to a function that expects something with type ext(), because you're breaking opacity (in dialyzer's mind).</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Feb 25, 2020 at 11:13 AM Dániel Szoboszlay <<a href="mailto:dszoboszlay@gmail.com" target="_blank">dszoboszlay@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi,<div><br></div><div>I have a small example where Dialyzer gives a very weird warning because of some confusion over equal opaque and transparent types. Is this a bug in Dialyzer or is there actually some type error here that my naked eyes cannot see?</div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="monospace">-module(foo).</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">-record(f, {f}).</font></div><div><font face="monospace">-type   int() :: atom().</font></div><div><font face="monospace">-opaque ext() :: int().</font></div><div><font face="monospace">-opaque f() :: #f{f :: int()}.</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">-export([f/1]).</font></div><div><font face="monospace">-export_type([f/0, ext/0]).</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">-spec f(f()) -> ok.</font></div><div><font face="monospace">f(#f{f = F}) -></font></div><div><font face="monospace">  x(F).</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">-spec x(ext()) -> ok.</font></div><div><font face="monospace">x(_) -></font></div><div><font face="monospace">  ok.</font></div></blockquote><div><br></div><div>This module produces no Dialyzer warnings. However, a different module using its API does:</div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="monospace">-module(bar).</font></div><div><font face="monospace">-export([f/1]).</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">-spec f(foo:f()) -> ok.</font></div><div><font face="monospace">f(F) -></font></div><div><font face="monospace">  foo:f(F).</font></div></blockquote><div><br></div><div>This would generate the below warning (with OTP 22.2.3):</div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><font face="monospace">bar.erl:4: Invalid type specification for function bar:f/1. The success typing is </font></div><div><font face="monospace">          (foo:f()) -> 'ok'</font></div></blockquote><div><br></div><div>This warning doesn't make any sense: the type specification for bar:f/1 is the same as the success typing found by Dialyzer. The problem is actually caused by foo:x/1's type specification: it uses the opaque ext() type instead of the transparent int(). The two types are declared equal, so I'd assume they can be used interchangeably within the foo module. The fact that ext() is opaque should only matter in other modules. Yet, this construct somehow confuses Dialyzer.</div><div><br></div><div>To give some context for the curious: the purpose of the equivalent ext() and int() types is that this type shall be transparent within the application (there are multiple modules using it), but opaque to the outside world. So internally the application uses the int() type, but all API functions that the outside world shall rely on use ext() instead (and they are all in the same module that declares the opaque type, so it can safely look into ext()-s and "convert" them into int()-s).</div><div><br></div><div>/Daniel</div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><table border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td align="left" valign="bottom" width="107" style="line-height:0;vertical-align:bottom;padding-right:10px;padding-top:20px;padding-bottom:20px">
                <a href="https://about.me/elbrujohalcon?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=gmail_api&utm_content=thumb" style="text-decoration:none" target="_blank">
                    <img src="https://thumbs.about.me/thumbnail/users/e/l/b/elbrujohalcon_emailsig.jpg?_1498084031_146" alt="" width="105" height="70" style="margin: 0px; padding: 0px; display: block; border: 1px solid rgb(238, 238, 238);">
                </a>
            </td>
            <td align="left" valign="bottom" style="line-height:1.1;vertical-align:bottom;padding-top:20px;padding-bottom:20px">
                <img src="https://about.me/t/sig?u=elbrujohalcon" width="1" height="1" style="border: 0px; margin: 0px; padding: 0px; overflow: hidden;">
                <div style="font-size:18px;font-weight:bold;color:rgb(51,51,51);font-family:"Proxima Nova",Helvetica,Arial,sans-serif">Brujo Benavides</div>
                <a href="https://about.me/elbrujohalcon?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=gmail_api&utm_content=thumb" style="text-decoration:none;font-size:12px;color:rgb(43,130,173);font-family:"Proxima Nova",Helvetica,Arial,sans-serif" target="_blank">about.me/elbrujohalcon
                </a>
            </td>
        </tr>
    </tbody>
</table>
</div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><table border="0" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td align="left" valign="bottom" width="107" style="line-height:0;vertical-align:bottom;padding-right:10px;padding-top:20px;padding-bottom:20px">
                <a href="https://about.me/elbrujohalcon?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=gmail_api&utm_content=thumb" style="text-decoration:none" target="_blank">
                    <img src="https://thumbs.about.me/thumbnail/users/e/l/b/elbrujohalcon_emailsig.jpg?_1498084031_146" alt="" width="105" height="70" style="margin: 0px; padding: 0px; display: block; border: 1px solid rgb(238, 238, 238);">
                </a>
            </td>
            <td align="left" valign="bottom" style="line-height:1.1;vertical-align:bottom;padding-top:20px;padding-bottom:20px">
                <img src="https://about.me/t/sig?u=elbrujohalcon" width="1" height="1" style="border: 0px; margin: 0px; padding: 0px; overflow: hidden;">
                <div style="font-size:18px;font-weight:bold;color:rgb(51,51,51);font-family:"Proxima Nova",Helvetica,Arial,sans-serif">Brujo Benavides</div>
                <a href="https://about.me/elbrujohalcon?promo=email_sig&utm_source=product&utm_medium=email_sig&utm_campaign=gmail_api&utm_content=thumb" style="text-decoration:none;font-size:12px;color:rgb(43,130,173);font-family:"Proxima Nova",Helvetica,Arial,sans-serif" target="_blank">about.me/elbrujohalcon
                </a>
            </td>
        </tr>
    </tbody>
</table>
</div>
</blockquote></div>