<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 12 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:Cambria;
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Cambria","serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-reply;
        font-family:"Calibri","sans-serif";
        color:#1F497D;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-US link=blue vlink=purple><div class=WordSection1><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>Yes, custom behaviors is definitely one of the primary use cases, though, for me , any time you have functions that take functions as arguments, it would be nice to be able to specify a function as having a certain type, rather than having to repeat yourself in the </span><span style='font-size:11.0pt;font-family:Consolas;color:#1F497D'>-spec</span><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'>.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:11.0pt;font-family:"Calibri","sans-serif";color:#1F497D'><o:p> </o:p></span></p><div style='border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in 4.0pt'><div><div style='border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in'><p class=MsoNormal><b><span style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'>From:</span></b><span style='font-size:10.0pt;font-family:"Tahoma","sans-serif"'> Tim Watson [mailto:watson.timothy@gmail.com] <br><b>Sent:</b> Tuesday, February 14, 2012 1:41 PM<br><b>To:</b> David Mercer<br><b>Cc:</b> erlang-questions@erlang.org<br><b>Subject:</b> Re: [erlang-questions] -spec Enhancement: -spec f :: ftype().<o:p></o:p></span></p></div></div><p class=MsoNormal><o:p> </o:p></p><div><p class=MsoNormal>On 14 February 2012 16:14, David Mercer <<a href="mailto:dmercer@gmail.com">dmercer@gmail.com</a>> wrote:<o:p></o:p></p><div><div><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>You know, I’ve always wished I could declare a function type (e.g., <span style='font-family:Consolas'>-type f() :: fun((arg_type1(), arg_type2()) -> return_type())</span>) and then declare a function as conforming to that spec (e.g., <span style='font-family:Consolas'>-spec f1 :: f()</span>), instead of having to repeat myself (i.e., <span style='font-family:Consolas'>-spec f1(arg_type1(), arg_type2()) -> return_type()</span>).  This helps when the function type is quite complicated and needs to be repeated often, and also when you have a function that takes a function with a certain spec, when you define the actual functions that can be passed to it.  What do y’all think?  Am I crazy?<o:p></o:p></p><p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'> <o:p></o:p></p></div></div></div><p class=MsoNormal><o:p> </o:p></p><div><div><p class=MsoNormal>I wonder if, combined with custom behaviours, that might be a step in the direction of being able to provide a consistent interface to modules that offer equivalent functionality (database connectivity, config file handling, logging, etc). I'm assuming that is the primary use case, although I have a feeling you have encountered other scenarios from what you've said.<o:p></o:p></p></div></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>I think it sounds quite handy, although presumably you'd want to export the type from a module somewhere, in which case it gets scoped to an application and it *could* get hairy trying to figure out the right place to put it. Pushing it down to the appropriate scope would then make it less appropriate to re-use across modules/components.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>For example, consider a concrete example specification:<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    -opaque dbms_connection() :: #dbms_connection_handle{}.  %% with some fields for vendor specific stuff<o:p></o:p></p></div><div><p class=MsoNormal>    -type dbms_connection_info() :: #dbms_connection_info{}.  %% with some fields for vendor specific stuff<o:p></o:p></p></div><div><p class=MsoNormal>    -type open_connection(connection_info()) -> dbms_connection() | {error, term()}.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Where should I export this from? Do I have some 'core' module (say, the primary or application callback module for the app/library) where I do this? <o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    %% in dbms.erl<o:p></o:p></p></div><div><p class=MsoNormal>    -include("dbms.hrl").<o:p></o:p></p></div><div><p class=MsoNormal>    -export_type([open_connection/1]).<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>And then presumably I'm going to use this in a few different places. It'd be fine, I suppose, to see something like<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    -spec open_connection() :: dbms:open_connection()<o:p></o:p></p></div><div><p class=MsoNormal>    open_connection(CInfo) -> .....<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>But then if I start to use that across multiple applications, does it still make sense?<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    -module(pgsql_connection).<o:p></o:p></p></div><div><p class=MsoNormal>    -spec open_connection() :: dbms:open_connection()<o:p></o:p></p></div><div><p class=MsoNormal>    open_connection(CInfo) -> .....<o:p></o:p></p></div><div><p class=MsoNormal>    <o:p></o:p></p></div><div><p class=MsoNormal>I suppose that reads ok, but why not just put it into a header file as a sepc and distribute that? If that's the case, I can have a library application carry the header and just use -spec instead. Any implementor can simply include the header and reference the spec:<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    %% in application/library dbms_api/include/dbms_api.hrl<o:p></o:p></p></div><div><div><p class=MsoNormal>    -opaque dbms_connection() :: #dbms_connection_handle{}.  %% with some fields for vendor specific stuff<o:p></o:p></p></div><div><p class=MsoNormal>    -type dbms_connection_info() :: #dbms_connection_info{}.  %% with some fields for vendor specific stuff<o:p></o:p></p></div><div><p class=MsoNormal>    -spec open_connection(connection_info()) -> dbms_connection() | {error, term()}.<o:p></o:p></p></div></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    %% in application dbms_pgsql/pgsql.erl<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    -include_lib("dbms_api/include/dbms_api.hrl").<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>    %% we 'inherit' the -spec from our library dependency on dbms_api<o:p></o:p></p></div><div><p class=MsoNormal>    open_connection(CInfo) -><o:p></o:p></p></div><div><p class=MsoNormal>        dbms_pgsql_connection:open(CInfo).<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>So here I'm not sure what the value is. If we're thinking about three or four functions that have the same signature in terms of input arguments and return type, but have different names, then Kostis correct me if I'm wrong but I think it'd be pretty tough to do something like that because the function name *is* part of the signature. <o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>You *could* experiment with this idea by writing a parse_transform that creates the -spec in response to a user defined annotation (<a href="https://github.com/hyperthunk/annotations">https://github.com/hyperthunk/annotations</a>) but I'm not sure if (a) the -type and -spec data will appear during the parse_transform execution or (b) how you export a -spec from a parse_transform, or if this (b) is even possible.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Another approach might be to write a build plugin (for rebar or whatever) that reads a bunch of metadata and generates the specs accordingly. Yet another approach might be to provide a hint to TypEr and let it generate the -specs for you. <o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div></div></div></body></html>