D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 1023 - Struct implementing interfaces and struct member enumeration
Summary: Struct implementing interfaces and struct member enumeration
Status: RESOLVED WORKSFORME
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-03-04 14:47 UTC by Lars Ivar Igesund
Modified: 2018-05-15 13:30 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Lars Ivar Igesund 2007-03-04 14:47:07 UTC
Structs in D are very simple which is good, but in some cases they are just
too simple. In many cases you would want to handle struct instances as if
they were Object derivates, by calling methods on them, methods that
implement an interface. The most obvious example is toUtf8 (or toString).
As it is now, for instance in a formatter, if it detects that the input is
a struct, you have no way of figuring out whether the struct implements an
interface or not.

This is thus a request to make it possible to say that a struct implements
an interface and thus can be typeid'ed on other types (interfaces) than
those of the structs themselves. An enumeration of the methods of the
struct would also be nice.

I started a thread in the NG out of old habit, but I think this is the more correct place.
Comment 1 Lars Ivar Igesund 2007-03-04 15:04:37 UTC
I may add that a complete, flexible, extensible formatter like the one in .Net (which is lucky enough to only have to care about objects) is impossible without some interface support for structs in D.
Comment 2 Stewart Gordon 2007-03-05 09:13:14 UTC
I'm not sure what I think of this idea.  There are a few difficulties - some operations would have to check whether an interface reference references a struct or class object.  And so casting even to Object would have to have a bit of runtime overhead to validate it.

Moreover, I'm not sure if the necessary conversion of the struct from value semantics to reference semantics are likely to cause confusion for some/in some circumstances.

(In reply to comment #0)
> I started a thread in the NG out of old habit, but I think this is the more
> correct place.

Actually, it was once said that feature requests shouldn't be posted on this particular Bugzilla, but the policy seems to have faded away lately.  I'm not sure.
Comment 3 Lars Ivar Igesund 2007-03-05 09:27:35 UTC
(In reply to comment #2)
> I'm not sure what I think of this idea.  There are a few difficulties - some
> operations would have to check whether an interface reference references a
> struct or class object.  And so casting even to Object would have to have a bit
> of runtime overhead to validate it.
> 
> Moreover, I'm not sure if the necessary conversion of the struct from value
> semantics to reference semantics are likely to cause confusion for some/in some
> circumstances.

There will certainly be technical difficulties, and as such the second request, enumeration of the methods, would be the half-assed, easy way to do it (all necessary information in the typeinfo, but for a larger interface you may have to check for a long list of methods before you know that the correct interface is implemented).

I would be happy for the functionality to ask whether a struct is of type foo, using typeid, not necessarily pass it along as type foo. It would probably cause some inconsistency somewhere in the system though as "struct MyType : IFoo { }" probably would make people expect that they could pass an instance to "void bar(IFoo foo);".

> 
> (In reply to comment #0)
> > I started a thread in the NG out of old habit, but I think this is the more
> > correct place.
> 
> Actually, it was once said that feature requests shouldn't be posted on this
> particular Bugzilla, but the policy seems to have faded away lately.  I'm not
> sure.
> 

Yes, there was a discussion about that, at which point most references to Bug were changed to Issue.
Comment 4 FeepingCreature 2007-03-08 03:35:22 UTC
d-bugmail@puremagic.com schrieb:
> http://d.puremagic.com/issues/show_bug.cgi?id=1023
> 
>            Summary: Struct implementing interfaces and struct member
>                     enumeration
>            Product: D
>            Version: unspecified
>           Platform: All
>         OS/Version: All
>             Status: NEW
>           Severity: enhancement
>           Priority: P2
>          Component: DMD
>         AssignedTo: bugzilla@digitalmars.com
>         ReportedBy: larsivar@igesund.net
> 
> 
> Structs in D are very simple which is good, but in some cases they are just
> too simple. In many cases you would want to handle struct instances as if
> they were Object derivates, by calling methods on them, methods that
> implement an interface. The most obvious example is toUtf8 (or toString).
> As it is now, for instance in a formatter, if it detects that the input is
> a struct, you have no way of figuring out whether the struct implements an
> interface or not.
> 
> This is thus a request to make it possible to say that a struct implements
> an interface and thus can be typeid'ed on other types (interfaces) than
> those of the structs themselves. An enumeration of the methods of the
> struct would also be nice.
> 
> I started a thread in the NG out of old habit, but I think this is the more
> correct place.
> 
> 
Consider the following code.

import std.stdio, std.traits;

struct a { void test() { } }
struct b { void Test() { } }
struct c { int Test() { return 0; } }

void test(T)() {
   T t=void;
   static if (is(typeof(t.Test)==function)) {
     writefln(T.mangleof, " has Test, returns ", typeid(ReturnType!(t.Test)));
   }
   else writefln(T.mangleof, " lacks Test");
}

void main() {
   test!(a); test!(b); test!(c);
}

Thus, we can check if a struct implements a series of functions, and check their return values and the parameters they take.
Does that come close to what you need?
   greetings --downs

Comment 5 FeepingCreature 2007-03-08 03:45:12 UTC
Downs schrieb:
> d-bugmail@puremagic.com schrieb:
>> http://d.puremagic.com/issues/show_bug.cgi?id=1023
>>
>>            Summary: Struct implementing interfaces and struct member
>>                     enumeration
>>            Product: D
>>            Version: unspecified
>>           Platform: All
>>         OS/Version: All
>>             Status: NEW
>>           Severity: enhancement
>>           Priority: P2
>>          Component: DMD
>>         AssignedTo: bugzilla@digitalmars.com
>>         ReportedBy: larsivar@igesund.net
>>
>>
>> Structs in D are very simple which is good, but in some cases they are 
>> just
>> too simple. In many cases you would want to handle struct instances as if
>> they were Object derivates, by calling methods on them, methods that
>> implement an interface. The most obvious example is toUtf8 (or toString).
>> As it is now, for instance in a formatter, if it detects that the 
>> input is
>> a struct, you have no way of figuring out whether the struct 
>> implements an
>> interface or not.
>>
>> This is thus a request to make it possible to say that a struct 
>> implements
>> an interface and thus can be typeid'ed on other types (interfaces) than
>> those of the structs themselves. An enumeration of the methods of the
>> struct would also be nice.
>>
>> I started a thread in the NG out of old habit, but I think this is the 
>> more
>> correct place.
>>
>>
> Consider the following code.
> 
> import std.stdio, std.traits;
> 
> struct a { void test() { } }
> struct b { void Test() { } }
> struct c { int Test() { return 0; } }
> 
> void test(T)() {
>   T t=void;
>   static if (is(typeof(t.Test)==function)) {
>     writefln(T.mangleof, " has Test, returns ", 
> typeid(ReturnType!(t.Test)));
>   }
>   else writefln(T.mangleof, " lacks Test");
> }
> 
> void main() {
>   test!(a); test!(b); test!(c);
> }
> 
> Thus, we can check if a struct implements a series of functions, and 
> check their return values and the parameters they take.
> Does that come close to what you need?
>   greetings --downs

Nevermind, I see what he means.
And I agree, more typeinfo for structs would be a good thing, especially for using with the new mixin syntax.

Comment 6 Austin Hastings 2010-10-22 01:49:18 UTC
I'd like to bump this request, and maybe make it a little more specific. What I'm looking for is essentially a "duck interface" - that is, "this type supports these methods, carry on." Except that I want strong enforcement - "you told me that you would support these methods, but you don't. Error."

Adding 'static interface' might be the way to differentiate between class-interface and struct-interface. This is by analogy with the behavior of static in a nested-function context (has no 'this', etc.).

In my case, struct is the right mechanism for speed and stack allocation, while the interface is nice to provide a single point to document and to have the compiler verify. If I've forgotten one of the eleventy-seven possible specializations, I want the compiler to tell me.

So for example, if an interface is declared "static interface" or "duck interface" or whatever, then getting a reference to it is impossible, because it makes no promises about the underlying type. It could be a class, it could be a struct, it could be an enum.
 
However, you could mix in duck interfaces anywhere, and the compiler verify them. And similarly, you could use them to annotate symbols, but that might need a little syntactic sugar:

static interface Duck;
class Base;
class Derived : Base, Duck;

struct Mallard : Duck;

auto obj = new Derived(); 
obj.quack();

auto s = Mallard();
s.quack();
Comment 7 Trass3r 2011-12-13 11:56:26 UTC
(In reply to comment #6)
> Adding 'static interface' might be the way to differentiate between
> class-interface and struct-interface.
..
> In my case, struct is the right mechanism for speed and stack allocation, while
> the interface is nice to provide a single point to document and to have the
> compiler verify.

Exactly!
Phobos circumvents the problem by using lots of templates in constraints:
template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    {
        R r = void;       // can define a range object
        if (r.empty) {}   // can test for empty
        r.popFront();     // can invoke popFront()
        auto h = r.front; // can get the front of the range
    }));
}

While this works fine, it does have some disadvantages.
It adds lots of overhead cause all of that code must be evaluated with errors gagged, mustn't alter the AST and whatever. Also there are a lot of bugs introduced by that here in bugzilla.
Furthermore there are no useful error messages with template constraints, so you don't even know what exactly went wrong when you implemented the interface.

> So for example, if an interface is declared "static interface" or "duck
> interface" or whatever, then getting a reference to it is impossible, because
> it makes no promises about the underlying type.

Yep, but one would need them as parameters. Maybe
foo(Bla b)
with Bla being a static interface could be shorthand for a compiler internal equivalent of the currently used, ugly
foo(Blub)(Blub b) if (conformsToBlaStructure!Blub)

OTOH, how to express if you want a struct conforming to multiple structural interfaces?
Comment 8 Dmitry Olshansky 2018-05-15 13:30:08 UTC
> An enumeration of the methods of the
struct would also be nice.

__trait(getMembers, ...)

Far as duck typing goes, this may produce a DIP on compile-time interfaces (a-la concepts).

And we have had good library solutions that check all of boxes for a long time now, see:
https://github.com/atilaneves/concepts

Which has `models` UDA to check if struct follows interface statically.