Le 30/03/2012 01:34, Steven Schveighoffer a écrit :
On Wed, 28 Mar 2012 21:53:57 -0400, Jesse Phillips
<[email protected]> 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).