UFCS for D

deadalnix deadalnix at gmail.com
Fri Mar 30 05:10:14 PDT 2012


Le 30/03/2012 01:34, Steven Schveighoffer a écrit :
> On Wed, 28 Mar 2012 21:53:57 -0400, Jesse Phillips
> <jessekphillips+D at gmail.com> wrote:
>
>> I won't be going out of my way to check this, but there is a mention
>> of adding the range primatives. This works, but it doesn't make the
>> class a range for any other module, so std.algorithms won't recogonise
>> it as a range.
>
> At first thought, I believed this should be fixable -- if not working
> already. Consider that std.algorithm doesn't include *your* module, yet
> you can pass types defined in your module into std.algorithm and it
> works just fine.
>
> But I realized after typing about 2 messages in response to this (and
> deleting them), you are right, there is a fundamental problem here.
> Because the template instantiation is based solely on the type. It does
> *not* include the type and whatever other modules you may have included
> that could define extension methods. I don't think it's an
> implementation issue, I think it's a design issue -- there simply is no
> way to do this.
>
> A counter case:
>
> module1.d:
>
> int foo(T)(T t)
> {
> return t.bar();
> }
>
> module2.d:
>
> struct S { int x;}
>
> module3.d:
>
> import module1, module2;
>
> int bar(S s) { return s.x * 2;}
>
> void baz1()
> {
> S s(2);
> assert(foo(s) == 4);
> }
>
> module4.d:
>
> import module1, module 2;
>
> int bar(S s) { return s.x * 3;}
>
> void baz2()
> {
> S s(2);
> assert(foo(s) == 6);
> }
>
> // and to drive the point further:
> module5.d:
> import module3, module4;
>
> void main()
> {
> baz1();
> baz2();
> }
>
> In order for the asserts to *both* pass, there has to be two different
> instantiations of foo!S, one for module3, and one for module4.
>
> So two possible sane rules:
> 1. A template instantiation can *only* use UFCS from functions defined
> in or imported from the module in which the template is defined. (i.e.
> the way it works now I think)
> or
> 2. A template instantiation can *only* use UFCS from functions defined
> in or imported from the module in which the template is defined, *and*
> from functions as defined or imported by the module that defines the
> type on which UFCS is being used. In other words, from my example above,
> only functions defined in or imported from module1.d and module2.d.
> Therefore, the bar extension defined in module3 and module4 cannot be
> called from module1.
>
> For builtin types (such as arrays or numbers), there wouldn't be a
> module that the type was defined. However, object.di is imported by
> everything, so extensions could be put in there.
>
> This kind of puts a damper on certain expectations for how UFCS could be
> used. But I don't see any other way (other than adding the current
> module into the instantiation somehow -- imagine the template bloat...).
>
> Even with this limitation, UFCS still allows a lot of cool things. One
> misleading suggestion from the article however, it's not very easy to
> create non-friend non-member functions using UFCS, considering that
> every function in a given module is a friend. In order to do this, you
> would need a helper module for each module that wants to define such
> non-friend functions. Given the above proof, the helper module would
> also have to be imported by the main module.
>
> -Steve

I would expect this not to work, because bar isn't defined in module1 
and template are supposed to use declaration scope, not instantiation 
scope (unless it is mixin template).


More information about the Digitalmars-d-announce mailing list