Please do not use 'auto' return types without thoroughly describing the interface

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Dec 25 22:48:39 UTC 2017


On Mon, Dec 25, 2017 at 04:26:52PM +0000, Piotr Klos via Digitalmars-d wrote:
> On Monday, 25 December 2017 at 03:23:33 UTC, Neia Neutuladh wrote:
> > If you have a function with a return type listed as `auto`, please
> > thoroughly describe what interface the return value provides.
> > 
> 
> I would just like to say that I strongly agree. Lack of documentation
> of template parameters and other unspecified types in interfaces, like
> auto return types is one of the primary reasons for people to turn
> away from template libraries and regard templates as obscure.

While I agree that all template parameters ought to be documented and
all auto return types thoroughly described, I disagree with explicit
naming of auto return types. The whole point of auto return types is to
return an *opaque* type that user code should not depend on, apart from
what the documentation says you can do with the type.  It's a matter of
encapsulation, i.e., "you can do X, Y, Z with the return value of this
function, everything else is none of your business". Or, in other words,
if your code can't possibly work without knowing the explicit type of
the return value, then you're doing something wrong (using the function
wrongly).

Ideally, you shouldn't even be able to create an instance of the type
yourself, hence the name Voldemort type (the type that can't be named)
though there is a valid use case for storing instances of such types in
aggregates like structs and classes. For the latter use case,
typeof(...) is your friend.

The idea behind this kind of coding style is to make your code as
generic as possible, i.e., it will work knowing only the bare minimum
about the data it's given, so it can handle a wider variety of data than
when types are hard-coded.  Naming explicit library types creates an
unnecessary dependency between user code and library implementation
details, and reduces encapsulation.


[...]
> > But look at std.regex.RegexMatch.front:
> > 
> > "Functionality for processing subsequent matches of global regexes
> > via range interface"
> > 
> > It has an example that mentions a `hit` property. Other parts of the
> > RegexMatch interface mention `pre` and `post` properties. What are
> > they?  It is a mystery!
> > 
> > Turns out that the return type is a Captures struct, and that could
> > be made explicit with little effort. (Such as
> > https://github.com/dlang/phobos/pull/5963.)
[...]

I strongly disagree with this kind of change.  The exact type does not
and should not need to be known by user code. It's an implementation
detail.  The whole idea is that user code shouldn't need to know what
the type is in order to be able to work with it.  This is part of the
encapsulation of the library type.  Making the type name visible to user
code means that future Phobos releases can no longer rename the type or
otherwise substitute it with something else without breaking user code.
This breaks encapsulation.  Making the type non-explicit in user code
means Phobos can transparently change the concrete type and user code
will still work as before after recompilation.

Even if you need to store the result in a struct member, you can use
typeof(...) to implicitly get the type needed to declare the member. In
this case, the typeof(...) will automatically adjust itself to whatever
the return type is when a future release of Phobos changes the
underlying implementation, so it keeps user code independent of Phobos
implementation details and preserves encapsulation.

Now granted, if the documentation is unclear about what exactly you can
do with the type, then the docs are at fault and need to be improved.
If what exactly can be done with .pre and .post isn't made clear, then
the docs need to be fixed.  But the declaration of such types ought to
remain internal to Phobos and opaque to user code.


T

-- 
This is a tpyo.


More information about the Digitalmars-d mailing list