Thread overview
toHash() and Interfaces
May 05, 2011
Nrgyzer
May 06, 2011
Nrgyzer
May 11, 2011
Stewart Gordon
May 05, 2011
Hey guys,

I'm trying to call toHash() in a class which receives an interface class as input param. But I always get "Error: no property 'toHash' for type...".

My code looks like:

module iFBlock;

private {
   import std.stream;
}

interface IFBlock {
   public {
      void write(Stream);
   }
}

module myFile;

private {
   import iFBlock;
}

class MyFile {
   private {
       IFBlock[hash_t] pBlocks;
   }
   public {
       void addBlock(IFBlock b) {
           pBlocks[b.toHash()] = b;
       }
   }
}

Is there any chance to get the hash of the FBlock-interface?

Thanks in advance!
May 06, 2011
On Thu, 05 May 2011 17:03:51 -0400, Nrgyzer <nrgyzer@gmail.com> wrote:

> Hey guys,
>
> I'm trying to call toHash() in a class which receives an interface
> class as input param. But I always get "Error: no property 'toHash'
> for type...".
>
> My code looks like:
>
> module iFBlock;
>
> private {
>    import std.stream;
> }
>
> interface IFBlock {
>    public {
>       void write(Stream);
>    }
> }
>
> module myFile;
>
> private {
>    import iFBlock;
> }
>
> class MyFile {
>    private {
>        IFBlock[hash_t] pBlocks;
>    }
>    public {
>        void addBlock(IFBlock b) {
>            pBlocks[b.toHash()] = b;
>        }
>    }
> }
>
> Is there any chance to get the hash of the FBlock-interface?

(cast(Object)b).toHash()

D has this horrible notion that any interface can be for a COM object, even though COM interfaces can only inherit from IUnknown (known statically).  Therefore, interfaces that don't inherit from IUnknown are not considered Objects, even though they could and should be.

So you have to manually cast an interface to Object in order to call an Object function.

-Steve
May 06, 2011
== Auszug aus Steven Schveighoffer (schveiguy@yahoo.com)'s Artikel
> On Thu, 05 May 2011 17:03:51 -0400, Nrgyzer <nrgyzer@gmail.com>
wrote:
> > Hey guys,
> >
> > I'm trying to call toHash() in a class which receives an interface class as input param. But I always get "Error: no property
'toHash'
> > for type...".
> >
> > My code looks like:
> >
> > module iFBlock;
> >
> > private {
> >    import std.stream;
> > }
> >
> > interface IFBlock {
> >    public {
> >       void write(Stream);
> >    }
> > }
> >
> > module myFile;
> >
> > private {
> >    import iFBlock;
> > }
> >
> > class MyFile {
> >    private {
> >        IFBlock[hash_t] pBlocks;
> >    }
> >    public {
> >        void addBlock(IFBlock b) {
> >            pBlocks[b.toHash()] = b;
> >        }
> >    }
> > }
> >
> > Is there any chance to get the hash of the FBlock-interface?
> (cast(Object)b).toHash()
> D has this horrible notion that any interface can be for a COM
object,
> even though COM interfaces can only inherit from IUnknown (known statically).  Therefore, interfaces that don't inherit from
IUnknown are
> not considered Objects, even though they could and should be. So you have to manually cast an interface to Object in order to
call an
> Object function.
> -Steve

Ah, okay - a bit dirty solution, but it works, thanks!
May 11, 2011
On 06/05/2011 13:02, Steven Schveighoffer wrote:
<snip>
> D has this horrible notion that any interface can be for a COM object, even though COM
> interfaces can only inherit from IUnknown (known statically). Therefore, interfaces that
> don't inherit from IUnknown are not considered Objects, even though they could and should be.

Firstly, IUnknown is defined in the Phobos files, not a language built-in.  There might be multiple IUnknowns, defined in different modules (e.g. because some set of bindings has its own copy).  How should the compiler identify the IUnknown to use?  By name?  By the signatures of functions specified within it?  By fully qualified name?

Secondly, I guess it's perfectly possible for some other system, besides COM, to create non-D objects that implement D interfaces.

> So you have to manually cast an interface to Object in order to call an Object function.

Which you can do, if you are certain that the object will always be a D object.  I guess the whole point is to protect you from those cases where you can't be sure.

Stewart.
May 16, 2011
On Wed, 11 May 2011 19:43:03 -0400, Stewart Gordon <smjg_1998@yahoo.com> wrote:

> On 06/05/2011 13:02, Steven Schveighoffer wrote:
> <snip>
>> D has this horrible notion that any interface can be for a COM object, even though COM
>> interfaces can only inherit from IUnknown (known statically). Therefore, interfaces that
>> don't inherit from IUnknown are not considered Objects, even though they could and should be.
>
> Firstly, IUnknown is defined in the Phobos files, not a language built-in.  There might be multiple IUnknowns, defined in different modules (e.g. because some set of bindings has its own copy).  How should the compiler identify the IUnknown to use?  By name?  By the signatures of functions specified within it?  By fully qualified name?

No, the compiler treats it specially, COM interfaces and classes have a different layout than D objects, so the compiler has to generate different code if the class implements an interface which inherits from std.c.windows.com.IUnknown.

From the spec:

A COM interface is defined as one that derives from the interface std.c.windows.com.IUnknown. A COM interface differs from a regular D interface in that:

* It derives from the interface std.c.windows.com.IUnknown.
* It cannot be the argument of a DeleteExpression.
* References cannot be upcast to the enclosing class object, nor can they be downcast to a derived interface. To accomplish this, an appropriate QueryInterface() would have to be implemented for that interface in standard COM fashion.
* Classes derived from COM interfaces are COM classes.
* The default linkage for member functions of COM classes is extern(System).
* The first member of the vtbl[] is not the pointer to the InterfaceInfo, but the first virtual function pointer.


----------------

There is nothing here that makes it seem like this is undetectable at compile time.

IMO:
* cast(Object)someComInterface => compiler error
* Object o = someComInterface => compiler error
* Object o = someNormalInterface => success

Is all doable without incurring any problems.

> Secondly, I guess it's perfectly possible for some other system, besides COM, to create non-D objects that implement D interfaces.

But none of these exist today.  All cases of 'alternative' interfaces have alternative layouts and statically detectable triggers (such as IUnknown) that would allow us to statically allow or disallow implicit casting to Object.  If we simply make a rule right now that alternative layouts have to be typed with some modifier (like extern(C++) for example) we can have implicit casting to object and get rid of all these ridiculous problems.

>> So you have to manually cast an interface to Object in order to call an Object function.
>
> Which you can do, if you are certain that the object will always be a D object.  I guess the whole point is to protect you from those cases where you can't be sure.

The compiler can always be sure, it just isn't programmed to know it yet...

-Steve