www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 7802] New: UFCS functions get lost when type is transmitted to template

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802

           Summary: UFCS functions get lost when type is transmitted to
                    template
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: bugzilla digitalmars.com



23:10:11 PDT ---
a.d
-------------
void foo(T)(T t) {
    t.func();
}
-------------

test.d
-------------
class C { }
void func(C c) { }
void test(C c) {
    foo(c);
-------------

This fails to compile because a.d doesn't know about test.func(C c), and so
does not find it when attempting to resolve t.func() using UFCS.

The solution is to:

If func() is not found as a member function of t, then look in the template
instantiation scope for a func(t). If found, use that as the UFCS function, and
then mark the template instantiation as LOCAL to the instantiation context.
This will ensure that the mangled name of the instantiation will not conflict
with other instantiations of foo(T) with other func(T) functions.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 30 2012
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802




23:12:06 PDT ---
More details:

http://forum.dlang.org/post/op.wbyg2ywyeav7ka localhost.localdomain

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 30 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802


timon.gehr gmx.ch changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |timon.gehr gmx.ch



What happens if there is an UFCS match both in the instantiation scope and the
template declaration scope?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 31 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802


dawg dawgfoto.de changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |dawg dawgfoto.de



That smells like a very hacky special case. Picking
up symbols from the instantiation scope is very ambivalent.

I'd argue that importing test in class C should fix the UFCS behavior,
but it currently doesn't because func is found as a member of C.

class C { import test; }

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Mar 31 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802


deadalnix <deadalnix gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |deadalnix gmail.com



As mentioned in the newsgroup, templates instantiation and UFCS are 2
orthogonal problems and must be treated as such.

The function can be passed as template parameter, the module name to import as
a string (and imported via mixin("import " ~ moduleName); ) or whatever.

Before trying to solve that problem, we'd better be sure this is a problem.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 01 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802


Steven Schveighoffer <schveiguy yahoo.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy yahoo.com



07:30:43 PDT ---
I would suggest instead of using the instantiation scope, use the scope of the
defined type.  Then the notion of "LOCAL" templates is not needed.

For example, if struct S is defined in foo.d, and you instantiate template
function func in bar.d:

void func(T)(T t)
{
   t.baz();
}

and baz is not a member function, look it up from two scopes -- the template
definition scope (i.e. bar.d) and the scope where S is defined (i.e. foo.d). 
This means S's API, including UFCS, is identical no matter where you use it
from.  Prefer type definition scope over template definition scope, to keep the
type's API intact.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 04 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802




look it up from two scopes -- the template definition scope (i.e. bar.d) and
the scope where S is defined (i.e. foo.d).
I thought this too, although the need to extend unknown types at the template scope will be limited. There is one important use-case where this fails though. Extending library types so that they fit a library template, e.g. to use std.stream.Stream with std.algorithm.find I need to modify phobos. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 04 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802




11:33:27 PDT ---

look it up from two scopes -- the template definition scope (i.e. bar.d) and
the scope where S is defined (i.e. foo.d).
I thought this too, although the need to extend unknown types at the template scope will be limited.
Templates already introduce a large level of binary incompatibility. This proposal of LOCAL templates will make it even worse, to the point where possibly no binary compatibility will be feasible as long as UFCS is involved. consider that I could import some module that declares a UFCS method foo. Then I call a template function that uses this method. In another module, I also import the same module for foo, call the same template, which generates the exact same code for the exact same function, but now has TWO identical instantiations based on the instantiating module's name.
 There is one important use-case where this fails though.
 Extending library types so that they fit a library template, e.g.
 to use std.stream.Stream with std.algorithm.find I need to modify
 phobos.
You can do this probably with alias this. But one thing I am concerned about is how a type can arbitrarily take on different API depending on the modules you import. It makes things confusing and unexpected. I'd rather have the type define what API it takes, along with the template, who is obviously free to extend any types it wants. My main concern with UFCS is about the use case where we have an existing method m, which I want to move outside the class or struct (for whatever reason). Both Walter's and my proposals should cover this case, but mine I think does it without adding unnecessary bloat or complexity to the name mangling system. My proposal is also a subset of Walter's. That is, we could *still* go the LOCAL template route later without breaking existing code. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 04 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802




There is two different situations around template instantiations and UFCS.
See following example.

--- kernel.d ---
struct S { int val; }
 property int foo(ref S s) { return s.val; }

--- extra.d ---
import kernel;
 property int bar(ref S s) { return s.val * 2; }

--- util.d ---
auto testfoo(T)(T t) { return t.foo; }
auto testbar(T)(T t) { return t.bar; }

--- test.d ---
import kernel, extra, util;
void main()
{
    auto s = S(1);
    assert(s.foo == 1); //   mod.foo(s), OK
    assert(s.bar == 2); // extra.bar(s), OK

    assert(testfoo(s) == 1);    // cannot instantiate
    assert(testbar(s) == 2);    // cannot instantiate
}

Walter's suggestion supports both testfoo and testbar, but I'm afraid that it
causes code bloating.
Steven's suggestion supports testfoo, but cannot support testbar.

I think Steven's way and the case of testfoo is similar to C++ ADL. But in D, a
namespace associated with a module is not opened, so unintended name lookup
isn't in there.

But, the case of testbar requires making relations between kernel and extra
modules in test.d module. For now I have no idea about it.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Apr 05 2012
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7802




04:53:22 PDT ---

 Walter's suggestion supports both testfoo and testbar, but I'm afraid that it
 causes code bloating.
 Steven's suggestion supports testfoo, but cannot support testbar.
What about a compromise? testfoo will be compiled without the LOCAL moniker, but testbar will compile with it. In other words, implement both ideas. In any case, you will be probably doing the same underlying work for both solutions to determine what scope is necessary to do a symbol lookup. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Apr 05 2012