July 24, 2004
On Sat, 24 Jul 2004 15:32:51 +1000, Derek wrote:

> I must be using a different version of D, because the three issues you mention are not a problem in v0.95.
> 
> The first one, referring to extern C functions do not produce any error messages. In fact, it compiles and runs just fine.

I'll back Kris up on this one.  It is most definitely an issue.  The example may compile fine as is, and that's part of the problem! Nobody sees the error until much later. Just go try to call a FileConduit instance's close() or read( char[] dst ) from another module, class, main, or whatever. You should quickly find that these methods no longer exist due to the miraculous effects of privately importing (internal to the class) std.c.linux.linux "close" and "read." These imported functions completely hide the classes close and read methods with no hope of recovery. DMD doesn't even attempt to overload these methods. Instead it rudely ends with a compile error message grumbling confusingly about incorrect arguments. The hapless programmer, not realizing what the import is doing, looks back in the code and is thoroughly confused at trying to figure out why his method calls are not valid even though they match the signatures in the class perfectly.  This problem is definitely real.

July 24, 2004
On Sat, 24 Jul 2004 00:41:15 -0700, John Reimer wrote:

> On Sat, 24 Jul 2004 15:32:51 +1000, Derek wrote:
> 
>> I must be using a different version of D, because the three issues you mention are not a problem in v0.95.
>> 
>> The first one, referring to extern C functions do not produce any error messages. In fact, it compiles and runs just fine.
> 
> I'll back Kris up on this one.  It is most definitely an issue.  The example may compile fine as is, and that's part of the problem! Nobody sees the error until much later. Just go try to call a FileConduit instance's close() or read( char[] dst ) from another module, class, main, or whatever. You should quickly find that these methods no longer exist due to the miraculous effects of privately importing (internal to the class) std.c.linux.linux "close" and "read." These imported functions completely hide the classes close and read methods with no hope of recovery. DMD doesn't even attempt to overload these methods. Instead it rudely ends with a compile error message grumbling confusingly about incorrect arguments. The hapless programmer, not realizing what the import is doing, looks back in the code and is thoroughly confused at trying to figure out why his method calls are not valid even though they match the signatures in the class perfectly.  This problem is definitely real.

Before I wrote my original response to this thread, I wrote some test programs to try and understand what the issues were. I based my response on those test programs. As I've now had a number of people come back and tell me I'm dead wrong (and possibly a bit simple too), I guess I really do not understand the issues.

Anyhow, here are the three files I made to test the "extern C/private import" issue.

<file: test3.d>
extern (C)
{
int read (int, void*, int);
int close (int);
}
<end of file>

<file: test4.d>
class Conduit
{
    abstract void close ();
    abstract void read (char[] dst);
}
class FileConduit : Conduit
{
    private import test3;
    private int handle;
    void close ()
    {
       printf("FileConduit Close\n");
       test3.close (handle);
    }
    void read (char[] dst)
    {
        test3.read (handle, dst, dst.length);
    }
}
<end of file>

<file: test2.d>
import test4;
void main()
{
    FileConduit f = new FileConduit;

    f.close();
}
<end of file>

<compile and run results>
G:\temp>dmd test2 test4 test3
F:\DMD\BIN\..\..\dm\bin\link.exe test2+test4+test3,,,user32+kernel32/noi;

G:\temp>test2
FileConduit Close

G:\temp>

<end of run>

What haven't I understood?

-- 
Derek
Melbourne, Australia
July 24, 2004
"Derek" <derek@psyc.ward> wrote in message news:h0kf8z2x9zvu.tyujz7z737ln$.dlg@40tude.net...
> The second, using interfaces, is also correctly working here. By correct,
I
> mean that it fails in exactly the way you say it does, because that's what I was expecting it to do - fail.
>
> My understanding of an interface is that it is JUST a list of cuntions
that
> must be implemented in the class that you specified with the interface name.
>
> Here is the code in your example:
>
> <code>
>  interface IFoo
>  {
>   void foo ();
>  }
>
>  interface IBar
>  {
>   void bar ();
>  }
>
>  class Foo : IFoo
>  {
>   void foo ()
>   {
>   }
>  }
>
>  class Bar : Foo, IFoo, IBar
>  {
>   void bar()
>   {
>   }
>  }
> </code>
>
> The problem is with class Bar. Here you explictly say that it is derived from class Foo, and must implement interface IFoo and IBar. However, you have only got it implementing bar(). The foo() is implemented in Foo but not in Bar. You are obviously expecting implemented interfaces to be inherited. Now although the foo() function IS inherited by Bar, you have also said it must be *implemented* in Bar too, but you didn't implement
it.

You're correct, it is deliberately designed to work this way. To get it to work the other way, just rewrite Bar as:

    class Bar : Foo, IBar



July 24, 2004
You describe it as "The latter is utter nonsense, and smacks of either an implementation-specific hack or a half-baked and headless C-style implementation of method hiding." However, consider the following C++ program:

--------------------------------------
C:\cbx>type foo.cpp

#include <stdio.h>

struct X { };

struct A
{
        int foo(void *p) { return 1; }
        int foo(struct X x) { return 2; }
};

struct B : A
{
//      using A::foo;
        int foo(int i) { return 3; }
};

void main()
{
    B b;
    X x;
    int i;

    i = b.foo((void*)0);
    printf("i = %d\n", i);
    i = b.foo(x);
    printf("i = %d\n", i);
    i = b.foo(1);
    printf("i = %d\n", i);
}

C:\cbx>sc foo
    i = b.foo((void*)0);
                      ^
foo.cpp(24) : Error: need explicit cast for function parameter 1 to get
from: void *
to  : int
    i = b.foo(x);
               ^
foo.cpp(26) : Error: need explicit cast for function parameter 1 to get
from: X
to  : int
--- errorlevel 1

C:\cbx>
-------------------------------------------
Now uncomment the 'using' declaration, and the program will compile successfully and produce the 1, 2, 3 output. Therefore, D uses overloading/hiding rules that are completely analogous to C++. I've read a lot of critiques of C++, and this has not been mentioned. Or perhaps my C++ compiler has an egregious fault in it, but I find it hard to believe it would have lasted this long with such a fundamental flaw <g>.


July 24, 2004
"some idiot" <fu@bar.org> wrote in message news:cdsd5t$u5$1@digitaldaemon.com...
> Attached is a small pdf noting three outstanding issues ~ each of which
has
> various bug reports stretching back into the old NG. Given that the v1.0 release is getting closer, it seemed appropriate to try getting some priority and/or traction.
>
> Such things might simply fall by the wayside otherwise.
>

External Names:
I can't seem to recreate that problem, but I have some thoughts on it. I
think importing in a class is like importing in a module. If there is a
symbol collision, you have to specify from which scope you want the symbol.
What comes to mind is this, which does not work:
   FileConduit fc = new FileConduit;
   fc.FileConduit.read("foo");
Although, I think if you don't have access (it's private, etc) to something
it should not cause a collision. I've been meaning to make a post on that.
A working solution is to wrap your imports in a struct or something, and
instead of std.linux.linux.read(), simply use mystruct.read().

Satisfying Interface Contracts:
From class.html#interface it says "A reimplemented interface must implement
all the interface functions, it does not inherit them from a super class." I
don't see why you're specifying to (re)implement IFoo without reimplementing
it. You can't specify a base class twice, why are you doing it for an
interface? It just so happens that specifying to implement an interface has
an added feature for reimplementing. In fact, when I tried it with a class,
the compiler crashed!

The Alias peek-a-boo Game:
I remember reading that it helps prevent the possibility of accidentally
calling the wrong function. Actually, I think there was a big long thread on
it, and I think people said they'd rather opt-into this danger using an
alias. However, there is a problem when trying to both override and alias
overload; I've been meaning to bug post it (wow I'm lazy ;).


July 24, 2004
Let me explain what is happening here.

In FileConduit, you have an import declaration, which brings a bunch of names into FileConduit's scope. How name lookup happens in a scope is a multi-stage process, each proceeding to the next if the name is not found in the current stage:

    1) look for a member with the name
    2) look in any imports *in this scope*
    3) if current scope is a class scope, recursively look in base classes
    4) repeat the process with the most enclosing scope

I think it would be very strange to have base class symbols override imports in the current scope, i.e. if imports were looked up in some other scope than the one in which they were imported.

The solution is straightforward. Move the import declaration outside of the class. Then it won't override base class names. There's no need whatsoever to refactor class heirarchies. By where you place the import declaration, you specify when the lookups for the names in the import happen.


July 24, 2004
> Before I wrote my original response to this thread, I wrote some test programs to try and understand what the issues were. I based my response on those test programs. As I've now had a number of people come back and tell me I'm dead wrong (and possibly a bit simple too), I guess I really do not understand the issues.

Ha! nobody would dare hint that you are simple.  That's a good one :-). Your point of view is appreciated. You obviously got some tough grit to wrangle on these issues against multiple opposing opinions.

In fact you've generated a good example that I'll have to think about. One problem is that the situation in mango still generates the compiler error that I'm referring too despite your example's apparent revelation of the problem's non-existence. So somehow, the slightly more complicated example does what yours is not doing.  Walter seems to have already described why this issue even comes up.  So I assume it's existence is formally accepted already (but the argument is that there is a good reason for it's existence, such that it's not an important issue).

As for your example, I'll have to figure what's going on differently between mango and it.

Many pardons if I made out that this is an obvious case.  Obviously it's not as obvious as I obviously thought! ;-)

> Anyhow, here are the three files I made to test the "extern
C/private
> import" issue.
> 
> <file: test3.d>
> extern (C)
> {
> int read (int, void*, int);
> int close (int);
> }
> <end of file>
> 
> <file: test4.d>
> class Conduit
> {
>     abstract void close ();
>     abstract void read (char[] dst);
> }
> class FileConduit : Conduit
> {
>     private import test3;
>     private int handle;
>     void close ()
>     {
>        printf("FileConduit Close\n");
>        test3.close (handle);
>     }
>     void read (char[] dst)
>     {
>         test3.read (handle, dst, dst.length);
>     }
>     }
> <end of file>
> 
> <file: test2.d>
> import test4;
> void main()
> {
>     FileConduit f = new FileConduit;
> 
>     f.close();
> }
> <end of file>
> 
> <compile and run results>
> G:\temp>dmd test2 test4 test3
> F:\DMD\BIN\..\..\dm\bin\link.exe
> test2+test4+test3,,,user32+kernel32/noi;
> 
> G:\temp>test2
> FileConduit Close
> 
> G:\temp>
> 
> <end of run>
> 
> What haven't I understood?

July 24, 2004
In article <cdt9m6$puh$1@digitaldaemon.com>, Walter says...
>
> Therefore, D uses
>overloading/hiding rules that are completely analogous to C++. I've read a lot of critiques of C++, and this has not been mentioned. Or perhaps my C++ compiler has an egregious fault in it, but I find it hard to believe it would have lasted this long with such a fundamental flaw <g>.

Agreed.  The resolution rules might be complex but I think they make perfect sense once understood.  And I personally find the consistency with C++ to be a good thing.

Sean


July 24, 2004
In article <cdt9m6$puh$1@digitaldaemon.com>,
 "Walter" <newshound@digitalmars.com> wrote:

> You describe it as "The latter is utter nonsense, and smacks of either an implementation-specific hack or a half-baked and headless C-style implementation of method hiding." However, consider the following C++ program:
> 
> --------------------------------------
> C:\cbx>type foo.cpp
> 
> #include <stdio.h>
> 
> struct X { };
> 
> struct A
> {
>         int foo(void *p) { return 1; }
>         int foo(struct X x) { return 2; }
> };
> 
> struct B : A
> {
> //      using A::foo;
>         int foo(int i) { return 3; }
> };
> 
> void main()
> {
>     B b;
>     X x;
>     int i;
> 
>     i = b.foo((void*)0);
>     printf("i = %d\n", i);
>     i = b.foo(x);
>     printf("i = %d\n", i);
>     i = b.foo(1);
>     printf("i = %d\n", i);
> }
> 
> C:\cbx>sc foo
>     i = b.foo((void*)0);
>                       ^
> foo.cpp(24) : Error: need explicit cast for function parameter 1 to get
> from: void *
> to  : int
>     i = b.foo(x);
>                ^
> foo.cpp(26) : Error: need explicit cast for function parameter 1 to get
> from: X
> to  : int
> --- errorlevel 1
> 
> C:\cbx>
> -------------------------------------------
> Now uncomment the 'using' declaration, and the program will compile successfully and produce the 1, 2, 3 output. Therefore, D uses overloading/hiding rules that are completely analogous to C++. I've read a lot of critiques of C++, and this has not been mentioned. Or perhaps my C++ compiler has an egregious fault in it, but I find it hard to believe it would have lasted this long with such a fundamental flaw <g>.


I think his point has some validity to it.  Importing should have a method by which to NOT implicitly be included in the current namespace as well as the module namespace.

At least by my understanding of D imports he cannot do:

std.c.linux.linux.close(...) without first importing.

And by importing, he automatically gets close() in the current namespace.

If there is already a way to "include" the module without "importing" the namespace then his point is moot.  Otherwise I think there's something to this.
July 24, 2004
In article <schancel-23ED78.09265224072004@digitalmars.com>,
 Sha Chancellor <schancel@pacific.net> wrote:

> I think his point has some validity to it.  Importing should have a method by which to NOT implicitly be included in the current namespace as well as the module namespace.
> 
> At least by my understanding of D imports he cannot do:
> 
> std.c.linux.linux.close(...) without first importing.
> 
> And by importing, he automatically gets close() in the current namespace.
> 
> If there is already a way to "include" the module without "importing" the namespace then his point is moot.  Otherwise I think there's something to this.

Pardon my stupidity, I meant to respond to external name resolution.