Re: How to get an IP address from network interfaces
On Fri, Apr 22, 2022 at 03:46:01PM +, IGotD- via Digitalmars-d-learn wrote: > On Friday, 22 April 2022 at 12:58:24 UTC, H. S. Teoh wrote: > > > > Why would you not want to use OS APIs? > > > > 1. Portability Usually when portability matters, you already have specific OSes that you're targeting, and probably already have your own OS compatibility abstraction for them. If not, just make one, that translates whatever internal API suits your code into per-OS calls. D often makes this a lot less painful than it could otherwise be. > 2. Language APIs are usually much better to use that the OS APIs, like > Berkeley sockets for example. Depends on how the language API was designed. :-D Some APIs are truly nightmarish to use, some are nice but incur a performance overhead. I don't mind getting as close to OS API level as I can for performance, then abstracting that layer into a nicer higher-level API that suits my program's current needs. T -- Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".
Re: How to get an IP address from network interfaces
On Friday, 22 April 2022 at 12:58:24 UTC, H. S. Teoh wrote: Why would you not want to use OS APIs? 1. Portability 2. Language APIs are usually much better to use that the OS APIs, like Berkeley sockets for example.
Re: How to get an IP address from network interfaces
On Fri, Apr 22, 2022 at 09:26:13AM +, IGotD- via Digitalmars-d-learn wrote: > On Thursday, 21 April 2022 at 07:20:30 UTC, dangbinghoo wrote: > > > > [... Berkley sockets network code ...] > > > > It really makes me sad when I see this. D has some native networking > API but unfortunately you have go to the OS API to have this basic > functionality. D should really expand its own API so that we don't > have to use OS APIs. [...] Why would you not want to use OS APIs? T -- Indifference will certainly be the downfall of mankind, but who cares? -- Miquel van Smoorenburg
Re: How to get an IP address from network interfaces
On Thursday, 21 April 2022 at 07:20:30 UTC, dangbinghoo wrote: [... Berkley sockets network code ...] It really makes me sad when I see this. D has some native networking API but unfortunately you have go to the OS API to have this basic functionality. D should really expand its own API so that we don't have to use OS APIs.
Re: How to get an IP address from network interfaces
On Friday, 22 April 2022 at 05:28:52 UTC, dangbinghoo wrote: On Thursday, 21 April 2022 at 07:38:04 UTC, Alexander Zhirov wrote: [...] ```d struct ifreq { private union ifr_ifrn_ { char[IFNAMSIZ] ifrn_name; /* if name, e.g. "en0" */ } ifr_ifrn_ ifr_ifrn; [...] it's actually POSIX C API binding for D. you should get similar code in C when searching StackOverflow. the only thing to do this is just to look at /usr/include/dlang for POSIX API already complete binding from the official. if something is missing, you just do-it-yourself in your code.
Re: How to get an IP address from network interfaces
On Thursday, 21 April 2022 at 07:38:04 UTC, Alexander Zhirov wrote: On Thursday, 21 April 2022 at 07:20:30 UTC, dangbinghoo wrote: On Thursday, 21 April 2022 at 07:04:18 UTC, Alexander Zhirov wrote: I want to get the IP address of the network interface. There is both a wireless interface and a wired one. Is it possible, knowing the name of the network interface, to get its IP address? ```d import core.sys.posix.sys.ioctl; import core.sys.posix.arpa.inet; import core.stdc.string; import core.stdc.stdio; import core.stdc.errno; import core.sys.posix.stdio; import core.sys.posix.unistd; string ip; int get(string if_name) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { fprintf(stderr, "Create socket failed!errno=%d", errno); return -1; } ifreq ifr; uint nIP, nNetmask, nBroadIP; strcpy(ifr.ifr_name.ptr, std.string.toStringz(if_name)); try { if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { return -2; } } catch (Exception e) { writeln("Error operation on netif " ~ if_name); return -2; } memcpy(macaddr.ptr, cast(char *)ifr.ifr_hwaddr.sa_data.ptr, 6); if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { nIP = 0; } else { nIP = *cast(uint*)(&ifr.ifr_broadaddr.sa_data[2]); ip = fromStringz(inet_ntoa(*cast(in_addr*)&nIP)).idup; } } ``` Gives a lot of errors when compiling ```d app.d(19): Error: function `std.stdio.makeGlobal!"core.stdc.stdio.stderr".makeGlobal` at /usr/include/dlang/dmd/std/stdio.d(5198) conflicts with variable `core.stdc.stdio.stderr` at /usr/include/dlang/dmd/core/stdc/stdio.d(927) app.d(19): Error: function `core.stdc.stdio.fprintf(shared(_IO_FILE)* stream, scope const(char*) format, scope const ...)` is not callable using argument types `(void, string, int)` app.d(19):cannot pass argument `makeGlobal(StdFileHandle _iob)()` of type `void` to parameter `shared(_IO_FILE)* stream` app.d(23): Error: undefined identifier `ifreq` app.d(26): Error: undefined identifier `string` in package `std` app.d(39): Error: undefined identifier `macaddr` app.d(48): Error: undefined identifier `fromStringz` ``` ```d struct ifreq { private union ifr_ifrn_ { char[IFNAMSIZ] ifrn_name; /* if name, e.g. "en0" */ } ifr_ifrn_ ifr_ifrn; private union ifr_ifru_ { sockaddr ifru_addr; sockaddr ifru_dstaddr; sockaddr ifru_broadaddr; sockaddr ifru_netmask; sockaddr ifru_hwaddr; short ifru_flags; int ifru_ivalue; int ifru_mtu; ifmap ifru_map; byte[IFNAMSIZ] ifru_slave; /* Just fits the size */ byte[IFNAMSIZ] ifru_newname; byte * ifru_data; } ifr_ifru_ ifr_ifru; // NOTE: alias will not work : alias ifr_ifrn.ifrn_name ifr_name; @property ref ifr_name() { return ifr_ifrn.ifrn_name; } /* interface name */ @property ref ifr_hwaddr() { return ifr_ifru.ifru_hwaddr; } /* MAC address */ @property ref ifr_addr() { return ifr_ifru.ifru_addr; } /* address */ @property ref ifr_dstaddr() { return ifr_ifru.ifru_dstaddr; } /* other end of p-p lnk */ @property ref ifr_broadaddr() { return ifr_ifru.ifru_broadaddr; } /* broadcast address */ @property ref ifr_netmask() { return ifr_ifru.ifru_netmask; } /* interface net mask */ @property ref ifr_flags() { return ifr_ifru.ifru_flags; } /* flags */ @property ref ifr_metric() { return ifr_ifru.ifru_ivalue; } /* metric */ @property ref ifr_mtu() { return ifr_ifru.ifru_mtu; } /* mtu */ @property ref ifr_map() { return ifr_ifru.ifru_map; } /* device map */ @property ref ifr_slave() { return ifr_ifru.ifru_slave; } /* slave device */ @property ref ifr_data() { return ifr_ifru.ifru_data; } /* for use by interface */ @property ref ifr_ifindex() { return ifr_ifru.ifru_ivalue; } /* interface index */ @property ref ifr_bandwidth() { return ifr_ifru.ifru_ivalue; } /* link bandwidth */ @property ref ifr_qlen() { return ifr_ifru.ifru_ivalue; } /* queue length */ @property ref ifr_newname() { return ifr_ifru.ifru_newname; } /* New name */ } ```
Re: How to get an IP address from network interfaces
On Thursday, 21 April 2022 at 07:20:30 UTC, dangbinghoo wrote: On Thursday, 21 April 2022 at 07:04:18 UTC, Alexander Zhirov wrote: I want to get the IP address of the network interface. There is both a wireless interface and a wired one. Is it possible, knowing the name of the network interface, to get its IP address? ```d import core.sys.posix.sys.ioctl; import core.sys.posix.arpa.inet; import core.stdc.string; import core.stdc.stdio; import core.stdc.errno; import core.sys.posix.stdio; import core.sys.posix.unistd; string ip; int get(string if_name) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { fprintf(stderr, "Create socket failed!errno=%d", errno); return -1; } ifreq ifr; uint nIP, nNetmask, nBroadIP; strcpy(ifr.ifr_name.ptr, std.string.toStringz(if_name)); try { if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { return -2; } } catch (Exception e) { writeln("Error operation on netif " ~ if_name); return -2; } memcpy(macaddr.ptr, cast(char *)ifr.ifr_hwaddr.sa_data.ptr, 6); if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { nIP = 0; } else { nIP = *cast(uint*)(&ifr.ifr_broadaddr.sa_data[2]); ip = fromStringz(inet_ntoa(*cast(in_addr*)&nIP)).idup; } } ``` Gives a lot of errors when compiling ```d app.d(19): Error: function `std.stdio.makeGlobal!"core.stdc.stdio.stderr".makeGlobal` at /usr/include/dlang/dmd/std/stdio.d(5198) conflicts with variable `core.stdc.stdio.stderr` at /usr/include/dlang/dmd/core/stdc/stdio.d(927) app.d(19): Error: function `core.stdc.stdio.fprintf(shared(_IO_FILE)* stream, scope const(char*) format, scope const ...)` is not callable using argument types `(void, string, int)` app.d(19):cannot pass argument `makeGlobal(StdFileHandle _iob)()` of type `void` to parameter `shared(_IO_FILE)* stream` app.d(23): Error: undefined identifier `ifreq` app.d(26): Error: undefined identifier `string` in package `std` app.d(39): Error: undefined identifier `macaddr` app.d(48): Error: undefined identifier `fromStringz` ```
Re: How to get an IP address from network interfaces
On Thursday, 21 April 2022 at 07:20:30 UTC, dangbinghoo wrote: On Thursday, 21 April 2022 at 07:04:18 UTC, Alexander Zhirov wrote: I want to get the IP address of the network interface. There is both a wireless interface and a wired one. Is it possible, knowing the name of the network interface, to get its IP address? ```d import core.sys.posix.sys.ioctl; import core.sys.posix.arpa.inet; import core.stdc.string; import core.stdc.stdio; import core.stdc.errno; import core.sys.posix.stdio; import core.sys.posix.unistd; string ip; int get(string if_name) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { fprintf(stderr, "Create socket failed!errno=%d", errno); return -1; } ifreq ifr; uint nIP, nNetmask, nBroadIP; strcpy(ifr.ifr_name.ptr, std.string.toStringz(if_name)); try { if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { return -2; } } catch (Exception e) { writeln("Error operation on netif " ~ if_name); return -2; } memcpy(macaddr.ptr, cast(char *)ifr.ifr_hwaddr.sa_data.ptr, 6); if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { nIP = 0; } else { nIP = *cast(uint*)(&ifr.ifr_broadaddr.sa_data[2]); ip = fromStringz(inet_ntoa(*cast(in_addr*)&nIP)).idup; } } ``` PS: ```d //handle binding to net/if.h struct ifmap { c_ulong mem_start; c_ulong mem_end; ushort base_addr; ubyte irq; ubyte dma; ubyte port; /* 3 bytes spare */ } struct ifreq { private union ifr_ifrn_ { char[IFNAMSIZ] ifrn_name; /* if name, e.g. "en0" */ } ifr_ifrn_ ifr_ifrn; private union ifr_ifru_ { sockaddr ifru_addr; sockaddr ifru_dstaddr; sockaddr ifru_broadaddr; sockaddr ifru_netmask; sockaddr ifru_hwaddr; short ifru_flags; int ifru_ivalue; int ifru_mtu; ifmap ifru_map; byte[IFNAMSIZ] ifru_slave; /* Just fits the size */ byte[IFNAMSIZ] ifru_newname; byte * ifru_data; } ifr_ifru_ ifr_ifru; // NOTE: alias will not work : alias ifr_ifrn.ifrn_name ifr_name; @property ref ifr_name() { return ifr_ifrn.ifrn_name; } /* interface name */ @property ref ifr_hwaddr() { return ifr_ifru.ifru_hwaddr; } /* MAC address */ @property ref ifr_addr() { return ifr_ifru.ifru_addr; } /* address */ @property ref ifr_dstaddr() { return ifr_ifru.ifru_dstaddr; } /* other end of p-p lnk */ @property ref ifr_broadaddr() { return ifr_ifru.ifru_broadaddr; } /* broadcast address */ @property ref ifr_netmask() { return ifr_ifru.ifru_netmask; } /* interface net mask */ @property ref ifr_flags() { return ifr_ifru.ifru_flags; } /* flags */ @property ref ifr_metric() { return ifr_ifru.ifru_ivalue; } /* metric */ @property ref ifr_mtu() { return ifr_ifru.ifru_mtu; } /* mtu */ @property ref ifr_map() { return ifr_ifru.ifru_map; } /* device map */ @property ref ifr_slave() { return ifr_ifru.ifru_slave; } /* slave device */ @property ref ifr_data() { return ifr_ifru.ifru_data; } /* for use by interface */ @property ref ifr_ifindex() { return ifr_ifru.ifru_ivalue; } /* interface index */ @property ref ifr_bandwidth() { return ifr_ifru.ifru_ivalue; } /* link bandwidth */ @property ref ifr_qlen() { return ifr_ifru.ifru_ivalue; } /* queue length */ @property ref ifr_newname() { return ifr_ifru.ifru_newname; } /* New name */ } ```
Re: How to get an IP address from network interfaces
On Thursday, 21 April 2022 at 07:04:18 UTC, Alexander Zhirov wrote: I want to get the IP address of the network interface. There is both a wireless interface and a wired one. Is it possible, knowing the name of the network interface, to get its IP address? ```d import core.sys.posix.sys.ioctl; import core.sys.posix.arpa.inet; import core.stdc.string; import core.stdc.stdio; import core.stdc.errno; import core.sys.posix.stdio; import core.sys.posix.unistd; string ip; int get(string if_name) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { fprintf(stderr, "Create socket failed!errno=%d", errno); return -1; } ifreq ifr; uint nIP, nNetmask, nBroadIP; strcpy(ifr.ifr_name.ptr, std.string.toStringz(if_name)); try { if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { return -2; } } catch (Exception e) { writeln("Error operation on netif " ~ if_name); return -2; } memcpy(macaddr.ptr, cast(char *)ifr.ifr_hwaddr.sa_data.ptr, 6); if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { nIP = 0; } else { nIP = *cast(uint*)(&ifr.ifr_broadaddr.sa_data[2]); ip = fromStringz(inet_ntoa(*cast(in_addr*)&nIP)).idup; } } ```
How to get an IP address from network interfaces
I want to get the IP address of the network interface. There is both a wireless interface and a wired one. Is it possible, knowing the name of the network interface, to get its IP address?
Re: abstract classes and interfaces
On 9/27/21 9:30 AM, kyle wrote: That'd be great. Long live Beefconf. I miss it way too often. Gotta have some beet ready for the next BeetConf. :p Ali
Re: abstract classes and interfaces
On Monday, 27 September 2021 at 16:23:49 UTC, Adam D Ruppe wrote: On Monday, 27 September 2021 at 16:20:59 UTC, Steven Schveighoffer wrote: That's a regression. In 2.092.1, it reports: aye known bug here https://issues.dlang.org/show_bug.cgi?id=21321 maybe once dmd can compile C code we'll fix it so it compiles D code correctly again. Stop roasting Walter and co. lol XD
Re: abstract classes and interfaces
On Monday, 27 September 2021 at 16:23:49 UTC, Adam D Ruppe wrote: On Monday, 27 September 2021 at 16:20:59 UTC, Steven Schveighoffer wrote: That's a regression. In 2.092.1, it reports: aye known bug here https://issues.dlang.org/show_bug.cgi?id=21321 maybe once dmd can compile C code we'll fix it so it compiles D code correctly again. That'd be great. Long live Beefconf.
Re: abstract classes and interfaces
On Monday, 27 September 2021 at 16:20:59 UTC, Steven Schveighoffer wrote: That's a regression. In 2.092.1, it reports: aye known bug here https://issues.dlang.org/show_bug.cgi?id=21321 maybe once dmd can compile C code we'll fix it so it compiles D code correctly again.
Re: abstract classes and interfaces
On Monday, 27 September 2021 at 16:11:31 UTC, kyle wrote: DMD compiles this providing no notice... What is the version of your DMD?
Re: abstract classes and interfaces
On 9/27/21 12:11 PM, kyle wrote: I'm attempting Markdown for the first time so forgive me if that doesn't go well. Consider the following: ```d interface A { bool broken(); } abstract class B : A { } class C : B { } void main() { import std.stdio; C test = new C(); writeln(test); } ``` DMD compiles this providing no notice that either B or C do not implement interface A. Is this how things are supposed to work? Thanks. That's a regression. In 2.092.1, it reports: ``` onlineapp.d(11): Error: class `onlineapp.C` interface function `bool broken()` is not implemented onlineapp.d(11): Error: class `onlineapp.C` interface function `bool broken()` is not implemented ``` As of 2.093, it no longer errors. -Steve
abstract classes and interfaces
I'm attempting Markdown for the first time so forgive me if that doesn't go well. Consider the following: ```d interface A { bool broken(); } abstract class B : A { } class C : B { } void main() { import std.stdio; C test = new C(); writeln(test); } ``` DMD compiles this providing no notice that either B or C do not implement interface A. Is this how things are supposed to work? Thanks.
Re: Storing interfaces as void[]
On Saturday, 13 March 2021 at 15:44:53 UTC, frame wrote: Maybe I don't get this right but why you don't just use the void[] as it is? void[] mem = [i]; //... return (cast(T[]) mem)[0]; This is how I exchange variable data between DLLs. That works, and is more elegant than the OP's solution. (And, I didn't know you could do it that way, so thanks for sharing!) However, it still adds an unnecessary second level of indirection for interfaces and classes. The simplest and most efficient solution is actually this: auto indirect = cast(void*) i; // i is of type I. // ... return cast(I) indirect; Where `is(I : T*, T) || is(I == interface) || is(I == class)`. The constraint enforces that all types should be accessed through exactly one level of indirection, allowing the same code to handle both reference types and value types with maximum efficiency.
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 17:37:43 UTC, David Zhang wrote: I want to store interfaces as untyped void[], then cast them back to the interface at a later time. However, it appears to produce garbage values on get(). Is this even possible, and if so, what is happening here? The alternative would be a struct { CheckedPtr self; api_fns } e.g. void register(I)(I i) { auto mem = new void[](I.sizeof); memcpy(mem.ptr, cast(void*) i, I.sizeof); // CheckedPtr includes a hash of fullyQualifiedName map[i.get_name()] = CheckedPtr!I(mem.ptr); } I get(I)() { // basically cast(I) p return map[I.get_name()].as!I(); } Maybe I don't get this right but why you don't just use the void[] as it is? void[] mem = [i]; //... return (cast(T[]) mem)[0]; This is how I exchange variable data between DLLs.
Re: Storing interfaces as void[]
On Saturday, 13 March 2021 at 00:36:37 UTC, David Zhang wrote: On Friday, 12 March 2021 at 22:18:59 UTC, tsbockman wrote: You can use TypeInfo references as the keys for the struct types, too. It's better than hashes because the TypeInfo is already being generated anyway, and is guaranteed to be unique, unlike your hashes which could theoretically collide. Makes sense. Using TypeInfo never occurred to me. I assume they are generated for COM classes as well? I'm not sure about that; you should test it yourself. I know that runtime type information support is incomplete for some non-`extern(D)` types - for example: https://issues.dlang.org/show_bug.cgi?id=21690 You can always fall back to fully qualified names for non-`extern(D)` stuff if you have to. But you should protect against hash collisions somehow, if you go that route. Here's a hybrid approach that is immune to hash collisions and works across DLL boundaries, but can almost always verify equality with a single pointer comparison: /// struct TypeKey { private: const(void)* ptr; size_t length; this(const(TypeInfo) typeInfo) const pure @trusted nothrow @nogc { ptr = cast(const(void)*) typeInfo; length = 0u; } this(string fqn) immutable pure @trusted nothrow { /* We need to allocate a block of size_t to ensure proper alignment for the first chunk, which is the hash code of the fqn string: */ size_t[] chunks = new size_t[1 + (fqn.length + (size_t.sizeof - 1)) / size_t.sizeof]; chunks[0] = hashOf(fqn); (cast(char*) chunks.ptr)[size_t.sizeof .. size_t.sizeof + fqn.length] = fqn; ptr = cast(immutable(void)*) chunks.ptr; length = fqn.length; } @property const(TypeInfo) typeInfo() const pure @trusted nothrow @nogc in(length == 0u) { return cast(const(TypeInfo)) ptr; } @property size_t fqnHash() const pure @trusted nothrow @nogc in(length != 0u) { return *cast(const(size_t)*) ptr; } @property string fqn() const pure @trusted nothrow @nogc in(length != 0u) { const fqnPtr = cast(immutable(char)*) (this.ptr + size_t.sizeof); return fqnPtr[0 .. length]; } public: string toString() const @safe { return (length == 0u)? typeInfo.toString() : fqn; } size_t toHash() const @safe nothrow { return (length == 0u)? typeInfo.toHash : fqnHash; } bool opEquals(TypeKey that) const @trusted { if(this.ptr is that.ptr) return true; if(this.length != that.length) return false; if(length == 0u) return (this.typeInfo == that.typeInfo); if(this.fqnHash != that.fqnHash) return false; return (this.fqn == that.fqn); } } template typeKeyOf(Indirect) if(is(Indirect : T*, T) // Support structs, static arrays, etc. || is(Indirect == interface) || is(Indirect == class)) { static if(is(Indirect : T*, T) || (__traits(getLinkage, Indirect) == "D")) { @property const(TypeKey) typeKeyOf() pure @safe nothrow @nogc { return const(TypeKey)(typeid(Indirect)); } } else { /* For FQN-based keys, ideally the whole process should share a single copy of the heap allocated fqn and its hash, so we'll use a global. No synchronization is necessary post construction, since it is immutable: */ private immutable TypeKey masterKey; shared static this() { // With some bit-twiddling, this could be done at compile time, if needed: import std.traits : fullyQualifiedName; masterKey = immutable(TypeKey)(fullyQualifiedName!Indirect); } @property immutable(TypeKey) typeKeyOf() @safe nothrow @nogc { assert(masterKey.ptr !is null); return masterKey; } } } @safe unittest { static extern(C++) class X { } static extern(C++) class Y { } assert(typeKeyOf!(int*) == typeKeyOf!(int*)); assert(typeKeyOf!(int*) != typeKeyOf!(float*)); assert(typeKeyOf!X == typeKeyOf!X); assert(typeKeyOf!X != typeKeyOf!Y); assert(typeKeyOf!X != typeKeyOf!(int*)); assert(typeKeyOf!(float*) != typeKeyOf!Y); } /// The lowering is something like this: ... Makes sense, I always thought of them as existing in separate places. Yeah, there are multiple reasonable ways of supporting interfaces in a language, each with their own trade-offs. But, this is the one used by D at the moment. So much head-bashing, and it's over. Thanks, tsbockman, Imperatorn. You're very welcome!
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 22:18:59 UTC, tsbockman wrote: Why do you think you need a `void[]` slice? I think `void*` pointers are sufficient. This handles all normal data types, as long as they are allocated on the GC heap: I wanted to have the registry own the structs' memory, though using new makes more sense on second thought. Your example templated implementation makes so much sense, though it doesn't work in this case. Thanks for the idea though. Aye, I'm using hashes. The idea is to support either D interfaces or structs with arbitrary content. You can use TypeInfo references as the keys for the struct types, too. It's better than hashes because the TypeInfo is already being generated anyway, and is guaranteed to be unique, unlike your hashes which could theoretically collide. Makes sense. Using TypeInfo never occurred to me. I assume they are generated for COM classes as well? `I` is *not* the type of an interface instance, it is the type of a reference to an instance of the interface. So `I i` is a reference to the instance, which itself holds a reference to the implementation, like a reference to a delegate (pointer to (ctx, fn))? No. What you are calling "the implementation" is the same thing as "the instance". `I i` is a reference into the interior of the implementing class instance, offset such that it points at the virtual function table pointer for that interface. The lowering is something like this: interface I { ... } class C : I { ... } struct C_Instance { void* __vtblForC; // ... other junk void* __vtblForI; // ... explicit and inherited class fields, if any. } C c = new C; // Works like `C_Instance* c = new C_Instance;` I i = c; // Works like `void** i = (C_Instance.__vtblForI.offsetof + cast(void*) c);` Makes sense, I always thought of them as existing in separate places. So much head-bashing, and it's over. Thanks, tsbockman, Imperatorn.
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 19:24:17 UTC, David Zhang wrote: On Friday, 12 March 2021 at 18:50:26 UTC, tsbockman wrote: The idea is to implement a service locator s.t. code like this is possible: ... I don't really need to copy or move the class instances here, just be able to read, assign, and replace references to them in the same place that I read, assign, and replace void[]'s of structs. Why do you think you need a `void[]` slice? I think `void*` pointers are sufficient. This handles all normal data types, as long as they are allocated on the GC heap: /* NOTE: It might be wiser to make this a `final class` instead of a `struct` to get reference semantics: */ struct Registry { private void*[TypeInfo] map; /// Return true if the registry was updated, false if not. bool put(bool overwrite = true, Indirect)(Indirect i) @trusted if(is(Indirect : T*, T) // Support structs, static arrays, etc. || is(Indirect == interface) || is(Indirect == class)) { auto key = typeid(Indirect), value = cast(void*) i; bool updated; if(value is null) updated = map.remove(key); else { static if(overwrite) { updated = true; map[key] = value; } else updated = (map.require(key, value) is value); } return updated; } alias put(Indirect) = put!(true, Indirect); bool remove(Indirect)() @trusted if(is(Indirect : T*, T) // Support structs, static arrays, etc. || is(Indirect == interface) || is(Indirect == class)) { return map.remove(typeid(Indirect)); } /** Returns a reference (for interfaces and classes) or a pointer (for everything else) if the type has been registered, and null otherwise. **/ Indirect get(Indirect)() @trusted if(is(Indirect : T*, T) // Support structs, static arrays, etc. || is(Indirect == interface) || is(Indirect == class)) { return cast(Indirect) map.get(typeid(Indirect), null); } } @safe unittest { static interface I { char c() const pure @safe nothrow @nogc; } static class C : I { private char _c; this(char c) inout pure @safe nothrow @nogc { this._c = c; } override char c() const pure @safe nothrow @nogc { return _c; } } static struct S { char c = 'S'; this(char c) inout pure @safe nothrow @nogc { this.c = c; } } Registry registry; assert( registry.put!false(new C('1'))); assert( registry.put!I(new C('2'))); assert( registry.put(new S('$'))); assert(!registry.put!false(new C('3'))); // Optionally protect existing entries. assert(registry.get!(I).c == '2'); assert(registry.get!(C).c == '1'); assert(registry.remove!I); assert(registry.get!I is null); assert(registry.get!C !is null); assert(registry.get!(S*).c == '$'); assert(registry.get!(int*) is null); } NOTE: If you only need one Registry instance in per thread, then you probably don't need the associative array at all; instead just use a template like this: template registered(Indirect) if(is(Indirect : T*, T) // Support structs, static arrays, etc. || is(Indirect == interface) || is(Indirect == class)) { /* This uses thread local storage (TLS). Sharing across the entire process is possible too, but would require synchronization of the registered objects, not just this reference/pointer: */ private Indirect indirect = null; /// Return true if the registry was updated, false if not. bool put(bool overwrite = true)(Indirect i) @safe { bool updated = (indirect !is i); static if(overwrite) { indirect = i; } else { updated &= (indirect is null); if(updated) indirect = i; } return updated; } bool remove() @safe { bool updated = (indirect !is null); indirect = null; return updated; } /** Returns a reference (for interfaces and classes) or a pointer (for everything else) if the type has been registered, and null otherwise. **/ Indirect get() @safe { return indirect; } } @safe unittest { static interface I { char c() const pure @safe nothrow @nogc; } static class C : I { private char _c; this(char c) inout pure @safe nothrow @nogc { this._c = c; } override char c() const pure @safe nothrow @nogc { return _c; } } static struct S { char c = 'S'; this(char c) inout pure @safe nothrow @nogc { this.c = c; } } assert( regist
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 18:14:12 UTC, Imperatorn wrote: On Friday, 12 March 2021 at 17:57:06 UTC, David Zhang wrote: On Friday, 12 March 2021 at 17:46:22 UTC, Imperatorn wrote: On Friday, 12 March 2021 at 17:37:43 UTC, David Zhang wrote: [...] Have you tried using Variant or jsvar (https://code.dlang.org/packages/arsd-official%3Ajsvar)? 🤔 It doesn't appear to support interfaces, see opAssign at line 682. It occurs to me that I.sizeof == 8 which is just enough for the vtbl, but not enough for an implementation ptr. Maybe it's a pointer to a {self, vtbl} pair? SomeClass.sizeof == 16, which is enough storage for both... Did you try Variant? Seems to work for me It seems a bit overkill for this. I also want to be able to track memory usage here, and Variant doesn't appear able to store arbitrary-sized structs without untrackable allocations. The idea has merit, but doesn't give me the control I desire :)
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 18:50:26 UTC, tsbockman wrote: The idea is to implement a service locator s.t. code like this is possible: // struct (I didn't mention this in the top post, my mistake) auto log = Logger() api_registry.register!Logger(log); // class/interface auto input = new InputReplay(recorded_input); api_registry.register!InputStream(input); // // somewhere else // // interface auto input = api_registry.get!InputStream(); // do something with input. // struct* api_registry.get!Logger().info(...); // // and additionally // auto input = new KeyboardInput(...); api_registry.replace!InputStream(input); /* Fully qualified names can be *very* long because of templates, so it can be wasteful to store and compare them at runtime. Let's use `TypeInfo` instead: */ Aye, I'm using hashes. The idea is to support either D interfaces or structs with arbitrary content. `I` is *not* the type of an interface instance, it is the type of a reference to an instance of the interface. So `I i` is a reference to the instance, which itself holds a reference to the implementation, like a reference to a delegate (pointer to (ctx, fn))? Thus cast(void*) produces something like *(ctx, fn). I don't mind that. I just want to store that reference as void[], be able to replace with with some other reference to another implementation as void[], then retrieve that as a reference intact. I don't really need to copy or move the class instances here, just be able to read, assign, and replace references to them in the same place that I read, assign, and replace void[]'s of structs.
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 18:50:26 UTC, tsbockman wrote: /* This will return `null` if the value isn't really a reference to an instance of a subtype of `I`, or if the key isn't in the map yet. If you don't care about the latter case, it can be shortened to just `cast(I) map[I.stringof]`. */ Oops, that last bit should say `cast(I) map[typeid(I)]`.
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 17:37:43 UTC, David Zhang wrote: I want to store interfaces as untyped void[], then cast them back to the interface at a later time. Assuming these interfaces are actual D `interface`s, declared with the keyword and using the default `extern(D)` linkage, you're way over-complicating things. All `extern(D)` `class`es are sub-types of `object.Object`, and have type information accessible through the implicit virtual function table pointer `__vptr` that can be used to perform safe dynamic casts: /* Fully qualified names can be *very* long because of templates, so it can be wasteful to store and compare them at runtime. Let's use `TypeInfo` instead: */ Object[TypeInfo] map; void register(I)(I i) if(is(I == interface)) // This wouldn't work right with value types like structs. { /* The garbage collector will keep the instance referenced by `i` alive for us as long as necessary. So, there is no need to copy the instance unless we want to be able to mutate it elsewhere without affecting the instance refrenced by `map`. */ /* `typeid(i)` will compile, but probably doesn't do what you want: you need to retrieve the value using the same key you put it in with, and below that has to be `typeid(I)`: */ map[typeid(I)] = cast(Object) i; } I get(I)() if(is(I == interface)) // This wouldn't work right with value types like structs. { /* This will return `null` if the value isn't really a reference to an instance of a subtype of `I`, or if the key isn't in the map yet. If you don't care about the latter case, it can be shortened to just `cast(I) map[I.stringof]`. */ auto valuePtr = (typeid(I) in map); return (valuePtr is null)? null : cast(I) *valuePtr; } Many variations on this are possible, depending on exactly what you're really trying to accomplish. This is my best guess as to what you're after, though, without seeing the context for the code you posted. However, it appears to produce garbage values on get(). Is this even possible, and if so, what is happening here? The alternative would be a struct { CheckedPtr self; api_fns } e.g. void register(I)(I i) { auto mem = new void[](I.sizeof); memcpy(mem.ptr, cast(void*) i, I.sizeof); // CheckedPtr includes a hash of fullyQualifiedName map[i.get_name()] = CheckedPtr!I(mem.ptr); } I get(I)() { // basically cast(I) p return map[I.get_name()].as!I(); } Your code confuses two levels of indirection (because D makes this super confusing); that is why it doesn't do what you want. `cast(void*) i` is an untyped pointer to some class instance, while `I.sizeof` is the size of *the pointer itself*, NOT the instance it points to. `I` is *not* the type of an interface instance, it is the type of a reference to an instance of the interface. (A reference is a pointer that sometimes automatically dereferences itself.) So, I.sizeof is always (void*).sizeof, the size of a pointer. The types of class and interface instances cannot be named or referenced in D, but `__traits(classInstanceSize, C)` will get you the size of an instance of class `C`. Getting the size of an interface instance isn't really a sensible thing to do, since the whole point of interfaces is that you don't need to know about the implementing type to work with them. Regardless, copying or moving the memory of a class instances directly is generally a bad idea, for various reasons.
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 17:57:06 UTC, David Zhang wrote: On Friday, 12 March 2021 at 17:46:22 UTC, Imperatorn wrote: On Friday, 12 March 2021 at 17:37:43 UTC, David Zhang wrote: [...] Have you tried using Variant or jsvar (https://code.dlang.org/packages/arsd-official%3Ajsvar)? 🤔 It doesn't appear to support interfaces, see opAssign at line 682. It occurs to me that I.sizeof == 8 which is just enough for the vtbl, but not enough for an implementation ptr. Maybe it's a pointer to a {self, vtbl} pair? SomeClass.sizeof == 16, which is enough storage for both... Did you try Variant? Seems to work for me
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 17:46:22 UTC, Imperatorn wrote: On Friday, 12 March 2021 at 17:37:43 UTC, David Zhang wrote: I want to store interfaces as untyped void[], then cast them back to the interface at a later time. However, it appears to produce garbage values on get(). Is this even possible, and if so, what is happening here? The alternative would be a struct { CheckedPtr self; api_fns } e.g. void register(I)(I i) { auto mem = new void[](I.sizeof); memcpy(mem.ptr, cast(void*) i, I.sizeof); // CheckedPtr includes a hash of fullyQualifiedName map[i.get_name()] = CheckedPtr!I(mem.ptr); } I get(I)() { // basically cast(I) p return map[I.get_name()].as!I(); } Have you tried using Variant or jsvar (https://code.dlang.org/packages/arsd-official%3Ajsvar)? 🤔 It doesn't appear to support interfaces, see opAssign at line 682. It occurs to me that I.sizeof == 8 which is just enough for the vtbl, but not enough for an implementation ptr. Maybe it's a pointer to a {self, vtbl} pair? SomeClass.sizeof == 16, which is enough storage for both...
Re: Storing interfaces as void[]
On Friday, 12 March 2021 at 17:37:43 UTC, David Zhang wrote: I want to store interfaces as untyped void[], then cast them back to the interface at a later time. However, it appears to produce garbage values on get(). Is this even possible, and if so, what is happening here? The alternative would be a struct { CheckedPtr self; api_fns } e.g. void register(I)(I i) { auto mem = new void[](I.sizeof); memcpy(mem.ptr, cast(void*) i, I.sizeof); // CheckedPtr includes a hash of fullyQualifiedName map[i.get_name()] = CheckedPtr!I(mem.ptr); } I get(I)() { // basically cast(I) p return map[I.get_name()].as!I(); } Have you tried using Variant or jsvar (https://code.dlang.org/packages/arsd-official%3Ajsvar)? 🤔
Storing interfaces as void[]
I want to store interfaces as untyped void[], then cast them back to the interface at a later time. However, it appears to produce garbage values on get(). Is this even possible, and if so, what is happening here? The alternative would be a struct { CheckedPtr self; api_fns } e.g. void register(I)(I i) { auto mem = new void[](I.sizeof); memcpy(mem.ptr, cast(void*) i, I.sizeof); // CheckedPtr includes a hash of fullyQualifiedName map[i.get_name()] = CheckedPtr!I(mem.ptr); } I get(I)() { // basically cast(I) p return map[I.get_name()].as!I(); }
Re: this T / variadic template and interfaces
On Tuesday, 27 October 2020 at 11:30:53 UTC, frame wrote: On Tuesday, 27 October 2020 at 10:41:06 UTC, Jacob Carlborg wrote: if (_arguments[i] == typeid(ubyte[])) { auto foo = va_arg!(ubyte[])(_argptr); } The same is working with variadic template. I am missing something? Never mind, I was squeezing the argument list through a delegate but the actual method - thus the pointer was 0.
Re: this T / variadic template and interfaces
On Tuesday, 27 October 2020 at 10:41:06 UTC, Jacob Carlborg wrote: On Tuesday, 27 October 2020 at 09:40:33 UTC, frame wrote: Hmm, a question of design. Is there also a convenient way to pass the arguments to a template or get a Variant[] from it? Convenient, no not that I know of. You can use a type safe variadic function that takes Variant, if you want to end up with Variant[] anyway. It depends on how you want the API to look like. Here are some examples: void foo(...); void bar(Variant[] args ...); foo(3, "foo", 'a'); // pass in the arguments as is bar(Variant(3), Variant("foo"), Variant('a')); // need to wrap each argument in Variant The advantage of using the type safe variadic function is that all the arguments are bundle into one array, make it easier to work with. -- /Jacob Carlborg I tried the (...) thing - I ran into access violation by passing a slice like: if (_arguments[i] == typeid(ubyte[])) { auto foo = va_arg!(ubyte[])(_argptr); } The same is working with variadic template. I am missing something?
Re: this T / variadic template and interfaces
On Tuesday, 27 October 2020 at 09:40:33 UTC, frame wrote: Hmm, a question of design. Is there also a convenient way to pass the arguments to a template or get a Variant[] from it? Convenient, no not that I know of. You can use a type safe variadic function that takes Variant, if you want to end up with Variant[] anyway. It depends on how you want the API to look like. Here are some examples: void foo(...); void bar(Variant[] args ...); foo(3, "foo", 'a'); // pass in the arguments as is bar(Variant(3), Variant("foo"), Variant('a')); // need to wrap each argument in Variant The advantage of using the type safe variadic function is that all the arguments are bundle into one array, make it easier to work with. -- /Jacob Carlborg
Re: this T / variadic template and interfaces
On Monday, 26 October 2020 at 13:02:33 UTC, Jacob Carlborg wrote: On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote: Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible. As Simen mentioned, templates cannot be virtual. But you don't need to use a template, you can use a regular variadic method [1]. It's a bit more clunky to work with than template variadic functions. Or if all the arguments will be of the same type, you can use type safe variadic functions [2], which are easier to work with. [1] https://dlang.org/spec/function.html#d_style_variadic_functions [2] https://dlang.org/spec/function.html#typesafe_variadic_functions -- /Jacob Carlborg Hmm, a question of design. Is there also a convenient way to pass the arguments to a template or get a Variant[] from it?
Re: this T / variadic template and interfaces
On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote: Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible. As Simen mentioned, templates cannot be virtual. But you don't need to use a template, you can use a regular variadic method [1]. It's a bit more clunky to work with than template variadic functions. Or if all the arguments will be of the same type, you can use type safe variadic functions [2], which are easier to work with. [1] https://dlang.org/spec/function.html#d_style_variadic_functions [2] https://dlang.org/spec/function.html#typesafe_variadic_functions -- /Jacob Carlborg
Re: this T / variadic template and interfaces
On Monday, 26 October 2020 at 11:48:48 UTC, Simen Kjærås wrote: This makes sense if you consider that the user of the interface has no knowledge of the types that implement it, and vice versa: the implementing class has no idea which instantiations to make, and the user has no idea which implementing classes to create instantiations for. Templates require that the user have full knowledge of the templates to be instantiated. There are some workarounds of sorts, but they depend heavily on what you're trying to achieve. Can you use an array of std.variant.Variant, for instance? -- Simen Yes, the user/coder does not know of other types by any chance. The interface must be used. Well I guess I let the interface do the variadic stuff and pass the argument as Variant[] to the wrapper in a new interface method. Thanks.
Re: this T / variadic template and interfaces
On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote: Did not find this topic: I have an interface and some wrapper classes that use it. The wrapper's methods should accept variadic arguments. The runtime should only work with the interface, trying casting to a wrapper is not an option, because it's a plugin design. - defining a variadic template in wrapper does not work, because we are working with the interface only and compiler complains method is not callable with argument X - defining a variadic template without body in interface causes linker errors, which makes sense somehow - defining a variadic template with body in interface could work if the compiler would get the right "this" type but sadly, "this" refers to interface and also "this T" refers to interface too. Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible. Templates can't be virtual, so even if they can be defined in an interface, you can't override them in a class that implements said interface - the implementation needs to be in the interface itself. This makes sense if you consider that the user of the interface has no knowledge of the types that implement it, and vice versa: the implementing class has no idea which instantiations to make, and the user has no idea which implementing classes to create instantiations for. Templates require that the user have full knowledge of the templates to be instantiated. There are some workarounds of sorts, but they depend heavily on what you're trying to achieve. Can you use an array of std.variant.Variant, for instance? -- Simen
this T / variadic template and interfaces
Did not find this topic: I have an interface and some wrapper classes that use it. The wrapper's methods should accept variadic arguments. The runtime should only work with the interface, trying casting to a wrapper is not an option, because it's a plugin design. - defining a variadic template in wrapper does not work, because we are working with the interface only and compiler complains method is not callable with argument X - defining a variadic template without body in interface causes linker errors, which makes sense somehow - defining a variadic template with body in interface could work if the compiler would get the right "this" type but sadly, "this" refers to interface and also "this T" refers to interface too. Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible.
Re: Interfaces and templates
On 09/20/2019 12:02 PM, JN wrote: > import std.stdio; > > interface IWriter > { > void write(U)(U x); > } > > class Foo : IWriter > { > void write(U)(U x, int y) > { > writeln(x); > } > } > > > > void main() > { > } > > Does this code make sense? No. Function templates cannot be virtual functions. There are at least two reasons that I can think of: 1) Function templates are not functions but their templates; only their instances would be functions 2) Related to that, languages like D that use virtual function pointer tables for dynamic dispatch cannot know how large that table should be; so, they cannot compile for an infinite number of entries in that table > If so, why doesn't it throw an error about > unimplemented write (or incorrectly implemented) method? Foo.write hides IWriter.write (see "name hiding"). Name hiding is not an error. When you call write on the Foo interface it takes two parameters: auto i = new Foo(); i.write(1, 2);// Compiles When you call write on the IWriter interface it takes one parameter but there is no definition for it so you get a linker error: IWriter i = new Foo(); i.write(1);// LINKER ERROR Ali
Re: Interfaces and templates
On Friday, 20 September 2019 at 19:02:11 UTC, JN wrote: If so, why doesn't it throw an error about unimplemented write (or incorrectly implemented) method? because you never used it. templates don't get checked by the compiler until they are used...
Interfaces and templates
import std.stdio; interface IWriter { void write(U)(U x); } class Foo : IWriter { void write(U)(U x, int y) { writeln(x); } } void main() { } Does this code make sense? If so, why doesn't it throw an error about unimplemented write (or incorrectly implemented) method?
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 08:20:46 UTC, John Colvin wrote: On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO. The way I look at it: an interface is a guarantee. By saying interface A { void foo()} class B: A {} class C: A {} void bar(A a) {} you guarantee that every class that implements interface A has a function foo and and bar can be called with anything that implements interface A. This is completely unrelated to inheritance. An abstract class is an implementation, most likely a base class. By saying abstract class A {void foo()} class B: A {} class C: B {} void bar(A a) {} you express that you want bar to be called with any subclass of A. e.g. a bitmap button inherits from button which inherits from abstract class widget and implements the signal/slot interfaces. Another pattern is design by introspection. An interface defines what something _is_, by introspection defines what something _CanDo_. That's to say: I don't care if foo is actually (or inherits from) an InputRange as long as it behaves like it.
Re: Abstract classes vs interfaces, casting from void*
On Sunday, 11 August 2019 at 20:32:14 UTC, John Colvin wrote: As I see this, everything you wrote is correct. :) But you compared abstractness with interface usage, initially. So... I would say, interfaces are more like the abstract method case without any function body. But then, you will have to use "override" all across the inherited classes. Ok. So that means the difference is pretty subtle, give or take a few extra keywords. Which leaves multiple inheritance as the only significant difference? From my perspective it looks like there are two massively overlapping features with some quite arbitrary feeling restrictions and differences. E.g. why can I not inherit from multiple 100% abstract empty classes? Wouldn't that be the same as inheriting from multiple interfaces? The overlap is there, but it is not so massive, I would say. If you inherit from abstract classes, then you do not plan to keep them empty. So, the overlap you are speaking about is exactly as large as the amount of "100% abstract empty classes". And for these, the approach to keep the interface as a separate interface seems more convenient, as Adam said. In the end, by forcing an explicit override, some semantic is also implied.
Re: Abstract classes vs interfaces, casting from void*
On Sunday, August 11, 2019 2:32:14 PM MDT John Colvin via Digitalmars-d- learn wrote: > On Sunday, 11 August 2019 at 20:15:34 UTC, Alex wrote: > > As I see this, everything you wrote is correct. :) > > > > But you compared abstractness with interface usage, initially. > > So... I would say, interfaces are more like the abstract method > > case without any function body. But then, you will have to use > > "override" all across the inherited classes. > > Ok. So that means the difference is pretty subtle, give or take a > few extra keywords. > > Which leaves multiple inheritance as the only significant > difference? > > From my perspective it looks like there are two massively > overlapping features with some quite arbitrary feeling > restrictions and differences. E.g. why can I not inherit from > multiple 100% abstract empty classes? Wouldn't that be the same > as inheriting from multiple interfaces? Well, as things stand, _no_ class is 100% abstract, because they all derive from Object, and Object has virtual functions on it with implementations, whereas an interface _is_ 100% abstract. Maybe once we have ProtoObject, it could be argued for allowing 100% abstract classes to be treated as interfaces, but right now, that wouldn't be possible, and even with ProtoObject, it arguably wouldn't be worth the extra complication, since if you really intend to have a 100% abstract class, that's what interfaces are for. There's also the weird complications that come with D's COM support, since that uses interfaces but gets treated differently from how classes are normally treated, and I don't know how that affects the implementation of interfaces. If we'd had ProtoObject from the get-go, I wonder if it would have just been better to implement COM interfaces as being derived from a specific class that's derived from ProtoObject instead of mucking up interfaces the way that we currently hove, but I don't know. I haven't ever actually used D's COM support, so I don't fully understand it. For the most, D's interfaces and abstract classes follow what you get in Java and C# (though the weirdness with COM is unique to D as is the ability to have final functions with an implementation). Basically, it seems like what we got with interfaces and abstract classes was copied from Java and then tweaked. I suspect that the separation between interfaces and abstract classes in Java comes from the fact that Object has functions on it, and that same logic carried over to D. In practice, what I would expect to typically happen is that if you're defining a set of functions that a class needs to have but not providing any implementations, then you'd use an interface, whereas if you intend to provide an implementation for any part of it but not all of it, you'd use an abstract class. I wouldn't expect abstract classes with no functions (outside of those from Object) or variables being declared on them to be used much. Maybe someone would have a use case where it would make sense to have a common base class with no implementations, but I can't think of any reason why that would be useful other than preventing classes from being derived from any class from a different class hierarchy, which isn't usually something that's worth preventing. Regardless, the whole weirdness that you're running into with void* is not something that much code would care about, because very little code is going to do something like cast a reference to void*, and the code that does do that is @system and expected to deal with it correctly. In general, casting to void* and then casting to anything other than the original type is probably asking for trouble. If I understand correctly, with void*, you're basically doing a reinterpet cast, and that's not usually the type of cast you want when dealing with class references. If I had code where whether casting to an interface or abstract class mattered, I'd want to redesign it so that that didn't matter. - Jonathan M Davis
Re: Abstract classes vs interfaces, casting from void*
On Sunday, 11 August 2019 at 20:32:14 UTC, John Colvin wrote: E.g. why can I not inherit from multiple 100% abstract empty classes? Wouldn't that be the same as inheriting from multiple interfaces? There's kinda no such thing as 100% empty abstract classes, since they all have the implicit parent of Object with its associated pieces. D's interfaces have no implicit parent. But if that were to change, then yeah, it should work - that's basically what C++ does in lieu of interfaces. (I personally prefer separate interfaces anyway, as it makes the intention clear and thus can help with better error messages and documentation, but it would work.)
Re: Abstract classes vs interfaces, casting from void*
On Sunday, 11 August 2019 at 20:15:34 UTC, Alex wrote: On Sunday, 11 August 2019 at 16:05:20 UTC, John Colvin wrote: I'm trying to narrow down exactly what patterns work with each and how they overlap. What I was trying to get at with the abstract method thing is that abstract class C { void foo(); } is an abstract class with a non-abstract method, whose implementation is going to come from somewhere else (not a common pattern in D). class C { abstract void foo(); } is an abstract class with an abstract method foo, which means you have to override it in a inheriting class to get a non-abstract class. As I see this, everything you wrote is correct. :) But you compared abstractness with interface usage, initially. So... I would say, interfaces are more like the abstract method case without any function body. But then, you will have to use "override" all across the inherited classes. Ok. So that means the difference is pretty subtle, give or take a few extra keywords. Which leaves multiple inheritance as the only significant difference? From my perspective it looks like there are two massively overlapping features with some quite arbitrary feeling restrictions and differences. E.g. why can I not inherit from multiple 100% abstract empty classes? Wouldn't that be the same as inheriting from multiple interfaces?
Re: Abstract classes vs interfaces, casting from void*
On Sunday, 11 August 2019 at 16:05:20 UTC, John Colvin wrote: I'm trying to narrow down exactly what patterns work with each and how they overlap. What I was trying to get at with the abstract method thing is that abstract class C { void foo(); } is an abstract class with a non-abstract method, whose implementation is going to come from somewhere else (not a common pattern in D). class C { abstract void foo(); } is an abstract class with an abstract method foo, which means you have to override it in a inheriting class to get a non-abstract class. As I see this, everything you wrote is correct. :) But you compared abstractness with interface usage, initially. So... I would say, interfaces are more like the abstract method case without any function body. But then, you will have to use "override" all across the inherited classes.
Re: Abstract classes vs interfaces, casting from void*
On Sunday, 11 August 2019 at 15:16:03 UTC, Alex wrote: On Sunday, 11 August 2019 at 13:09:43 UTC, John Colvin wrote: Ok. What would go wrong (in D) if I just replaced every interface with an abstract class? I think there's some confusion here, because B.foo is not abstract. abstract on a class is not inherited by its methods. https://dlang.org/spec/attribute.html#abstract Now, I'm confused, as you asked about abstract classes. So, yes, you can define the abstractness of classes differently. And what is your point? I'm trying to narrow down exactly what patterns work with each and how they overlap. What I was trying to get at with the abstract method thing is that abstract class C { void foo(); } is an abstract class with a non-abstract method, whose implementation is going to come from somewhere else (not a common pattern in D). class C { abstract void foo(); } is an abstract class with an abstract method foo, which means you have to override it in a inheriting class to get a non-abstract class.
Re: Abstract classes vs interfaces, casting from void*
On Sunday, 11 August 2019 at 13:09:43 UTC, John Colvin wrote: Ok. What would go wrong (in D) if I just replaced every interface with an abstract class? I think there's some confusion here, because B.foo is not abstract. abstract on a class is not inherited by its methods. https://dlang.org/spec/attribute.html#abstract Now, I'm confused, as you asked about abstract classes. So, yes, you can define the abstractness of classes differently. And what is your point?
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 17:28:32 UTC, Alex wrote: ´´´ void main(){} interface A { void fun(); } abstract class B{ void fun(); } class C : A{ void fun(){} } class D : B{ /*override*/ void fun(){} } ´´´ case 1: interface A and class C implementing interface A: You don't need to "override" anything. You are forced to provide an implementation of the function inside the class. case 2: abstract class B and class D inheriting from it: You can but not have to provide an implementation of a function inside the abstract class. If I don't and do not provide any implementation inside D I get a linker error. Don't how this case behaves on your system. If you provide an implementation inside the abstract class, you don't have to provide any in the derived one. In any case, if you want to provide an implementation inside the derived class you have to literally "override", as in D implicit overrides are not allowed. I think there's some confusion here, because B.foo is not abstract. abstract on a class is not inherited by its methods. https://dlang.org/spec/attribute.html#abstract
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 17:46:37 UTC, Timon Gehr wrote: On 10.08.19 16:29, John Colvin wrote: Ok. What would go wrong (in D) if I just replaced every interface with an abstract class? interface A{} interface B{} class C: A,B{ } Yes, I know, I guess it wasn't clear unless you read my previous question, I said "apart from multiple inheritance".
Re: Abstract classes vs interfaces, casting from void*
On 10.08.19 16:29, John Colvin wrote: Ok. What would go wrong (in D) if I just replaced every interface with an abstract class? interface A{} interface B{} class C: A,B{ }
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 14:29:03 UTC, John Colvin wrote: On Saturday, 10 August 2019 at 10:11:15 UTC, Alex wrote: On Saturday, 10 August 2019 at 08:20:46 UTC, John Colvin wrote: On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO. The general question is tricky, as different languages differ in details what is forced and what is allowed for abstract classes and interfaces. But roughly speaking, my opinion is: if you can/want to provide some default behavior than you are about to write an abstract class. If you are about to provide information/restriction of behavior, then this is more like an interface. Ok. What would go wrong (in D) if I just replaced every interface with an abstract class? ´´´ void main(){} interface A { void fun(); } abstract class B{ void fun(); } class C : A{ void fun(){} } class D : B{ /*override*/ void fun(){} } ´´´ case 1: interface A and class C implementing interface A: You don't need to "override" anything. You are forced to provide an implementation of the function inside the class. case 2: abstract class B and class D inheriting from it: You can but not have to provide an implementation of a function inside the abstract class. If I don't and do not provide any implementation inside D I get a linker error. Don't how this case behaves on your system. If you provide an implementation inside the abstract class, you don't have to provide any in the derived one. In any case, if you want to provide an implementation inside the derived class you have to literally "override", as in D implicit overrides are not allowed.
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 10:11:15 UTC, Alex wrote: On Saturday, 10 August 2019 at 08:20:46 UTC, John Colvin wrote: On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO. The general question is tricky, as different languages differ in details what is forced and what is allowed for abstract classes and interfaces. But roughly speaking, my opinion is: if you can/want to provide some default behavior than you are about to write an abstract class. If you are about to provide information/restriction of behavior, then this is more like an interface. Ok. What would go wrong (in D) if I just replaced every interface with an abstract class?
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 10:02:02 UTC, Antonio Corbi wrote: On Saturday, 10 August 2019 at 08:20:46 UTC, John Colvin wrote: On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO. Hi John. One reason could be data. Abstract classes can hold data, interfaces can't. Antonio That's a reason to use an abstract class, not a reason to use an interface.
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 08:20:46 UTC, John Colvin wrote: On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO. The general question is tricky, as different languages differ in details what is forced and what is allowed for abstract classes and interfaces. But roughly speaking, my opinion is: if you can/want to provide some default behavior than you are about to write an abstract class. If you are about to provide information/restriction of behavior, then this is more like an interface.
Re: Abstract classes vs interfaces, casting from void*
On Saturday, 10 August 2019 at 08:20:46 UTC, John Colvin wrote: On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO. Hi John. One reason could be data. Abstract classes can hold data, interfaces can't. Antonio
Re: Abstract classes vs interfaces, casting from void*
On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO.
Re: Abstract classes vs interfaces, casting from void*
On Friday, 9 August 2019 at 13:39:53 UTC, Simen Kjærås wrote: We're getting into somewhat advanced topics now. This is described in the Application Binary Interface page of the documentation[0]. In short: classes and interfaces both use a vtable[1] that holds pointers to each of their methods. When we cast a class instance to an interface, the pointer is adjusted, such that the interface's vtable is the first member. Casting via `void*` bypasses this adjustment. Using `__traits(classInstanceSize)`, we can see that `C` has a size of 12 bytes, while `D` only is 8 bytes (24 and 16 on 64-bit). This corresponds to the extra interface vtable as described above. When we first cast to `void*`, no adjustment happens, because we're not casting to an interface. When we later cast the `void*` to an interface, again no adjustment happens - in this case because the compiler doesn't know what we're casting from. If we use `__traits(allMembers, C)`, we can figure out which methods it actually has, and implement those with some extra debug facilities (printf): class C : I { override void foo() { writeln("hi"); } override string toString() { writeln("toString"); return ""; } override hash_t toHash() { debug printf("toHash"); return 0; } override int opCmp(Object o) { writeln("opCmp"); return 0; } override bool opEquals(Object o) { writeln("opEquals"); return false; } } If we substitute the above in your program, we see that the `toString` method is the one being called. This is simply because it's at the same location in the vtable as `foo` is in `I`'s vtable. When casting from a class to a superclass, no pointer adjustment is needed, as the vtable location is the same for both. We can look closer at the vtable, and see that for a new subclass, additional entries are simply appended at the end: class C { void foo() {} } class D : C { void bar() {} } unittest { import std.stdio; C c = new C(); D d = new D(); writeln("Pointer to foo(): ", (&c.foo).funcptr); writeln("Pointer to bar(): ", (&d.bar).funcptr); writeln("Pointer to foo() in C's vtable: ", c.__vptr[5]); writeln("Pointer to foo() in D's vtable: ", d.__vptr[5]); writeln("Pointer to bar() in D's vtable: ", d.__vptr[6]); } As we see, `foo()` has the position in the vtable for both `c` and `d`, while `D`'s new `bar()` method is added as the next entry. -- Simen [0]: https://dlang.org/spec/abi.html [1]: https://en.wikipedia.org/wiki/Virtual_method_table Thanks for the extra detail. Is there a solid reason to ever use an interface over an abstract class? (Other than multiple inheritance). I'm such a noob at anything related to OO.
Re: Abstract classes vs interfaces, casting from void*
On Friday, 9 August 2019 at 12:26:59 UTC, John Colvin wrote: import std.stdio; interface I { void foo(); } class C : I { override void foo() { writeln("hi"); } } abstract class AC { void foo(); } class D : AC { override void foo() { writeln("hi"); } } void main() { auto c = new C(); writeln(0); (cast(I)cast(void*)c).foo(); writeln(1); (cast(C)cast(void*)c).foo(); writeln(2); (cast(I)cast(C)cast(void*)c).foo(); auto d = new D(); writeln(3); (cast(AC)cast(void*)d).foo(); writeln(4); (cast(D)cast(void*)d).foo(); writeln(5); (cast(AC)cast(D)cast(void*)d).foo(); } This produces the output: 0 1 hi 2 hi 3 hi 4 hi 5 hi Why is there no "hi" between 0 and 1? We're getting into somewhat advanced topics now. This is described in the Application Binary Interface page of the documentation[0]. In short: classes and interfaces both use a vtable[1] that holds pointers to each of their methods. When we cast a class instance to an interface, the pointer is adjusted, such that the interface's vtable is the first member. Casting via `void*` bypasses this adjustment. Using `__traits(classInstanceSize)`, we can see that `C` has a size of 12 bytes, while `D` only is 8 bytes (24 and 16 on 64-bit). This corresponds to the extra interface vtable as described above. When we first cast to `void*`, no adjustment happens, because we're not casting to an interface. When we later cast the `void*` to an interface, again no adjustment happens - in this case because the compiler doesn't know what we're casting from. If we use `__traits(allMembers, C)`, we can figure out which methods it actually has, and implement those with some extra debug facilities (printf): class C : I { override void foo() { writeln("hi"); } override string toString() { writeln("toString"); return ""; } override hash_t toHash() { debug printf("toHash"); return 0; } override int opCmp(Object o) { writeln("opCmp"); return 0; } override bool opEquals(Object o) { writeln("opEquals"); return false; } } If we substitute the above in your program, we see that the `toString` method is the one being called. This is simply because it's at the same location in the vtable as `foo` is in `I`'s vtable. When casting from a class to a superclass, no pointer adjustment is needed, as the vtable location is the same for both. We can look closer at the vtable, and see that for a new subclass, additional entries are simply appended at the end: class C { void foo() {} } class D : C { void bar() {} } unittest { import std.stdio; C c = new C(); D d = new D(); writeln("Pointer to foo(): ", (&c.foo).funcptr); writeln("Pointer to bar(): ", (&d.bar).funcptr); writeln("Pointer to foo() in C's vtable: ", c.__vptr[5]); writeln("Pointer to foo() in D's vtable: ", d.__vptr[5]); writeln("Pointer to bar() in D's vtable: ", d.__vptr[6]); } As we see, `foo()` has the position in the vtable for both `c` and `d`, while `D`'s new `bar()` method is added as the next entry. -- Simen [0]: https://dlang.org/spec/abi.html [1]: https://en.wikipedia.org/wiki/Virtual_method_table
Re: Abstract classes vs interfaces, casting from void*
On Friday, 9 August 2019 at 13:19:14 UTC, kinke wrote: On Friday, 9 August 2019 at 12:26:59 UTC, John Colvin wrote: Why is there no "hi" between 0 and 1? Because you are treating the unadjusted object pointer as interface pointer and then call the only virtual function of that interface, in the 2nd vtbl slot (after the TypeInfo ptr). Casting a class ref to an interface offsets the pointer, so that the interface ref points to the interface vptr for that object instance. This is missing in that line, and so you are invoking the first virtual function of class C, which is some base function in `Object`. Ok, makes sense, thanks.
Re: Abstract classes vs interfaces, casting from void*
On Friday, 9 August 2019 at 12:26:59 UTC, John Colvin wrote: Why is there no "hi" between 0 and 1? Because you are treating the unadjusted object pointer as interface pointer and then call the only virtual function of that interface, in the 2nd vtbl slot (after the TypeInfo ptr). Casting a class ref to an interface offsets the pointer, so that the interface ref points to the interface vptr for that object instance. This is missing in that line, and so you are invoking the first virtual function of class C, which is some base function in `Object`.
Abstract classes vs interfaces, casting from void*
import std.stdio; interface I { void foo(); } class C : I { override void foo() { writeln("hi"); } } abstract class AC { void foo(); } class D : AC { override void foo() { writeln("hi"); } } void main() { auto c = new C(); writeln(0); (cast(I)cast(void*)c).foo(); writeln(1); (cast(C)cast(void*)c).foo(); writeln(2); (cast(I)cast(C)cast(void*)c).foo(); auto d = new D(); writeln(3); (cast(AC)cast(void*)d).foo(); writeln(4); (cast(D)cast(void*)d).foo(); writeln(5); (cast(AC)cast(D)cast(void*)d).foo(); } This produces the output: 0 1 hi 2 hi 3 hi 4 hi 5 hi Why is there no "hi" between 0 and 1?
Re: Wrong vtable for COM interfaces that don't inherit IUnknown
On Sunday, 21 July 2019 at 07:04:00 UTC, rikki cattermole wrote: COM is used heavily in WinAPI since about Vista. Pretty much all new functionality has been exposed by it and NOT extern(Windows) functions which was the standard during up to about XP (for example notification icons would today be COM based but isn't). E.g. jump lists https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-icustomdestinationlist Shell object library? It shipped with Internet Explorer 4 and was installable on windows 95. Shell (explorer) is not really winapi, it's more or less a normal userland application that provides integration, like an RPC server, in this way it can be similar to d-bus, but it's difficult to say, because the library abstracts whether it works in process or out of process, most (older) shell objects work in process and simply provide shell logic like moving files to trash bin and creating shortcuts.
Re: Wrong vtable for COM interfaces that don't inherit IUnknown
On 21/07/2019 5:44 PM, Kagamin wrote: On Tuesday, 16 July 2019 at 01:38:49 UTC, evilrat wrote: Also from what I see MS done this intentionally, means they either no longer loves COM or there was some other good reason. Primary consumer of COM interfaces is Visual Basic. It was really only Bill Gates who loved Basic, he wrote a Basic interpreter in 1975 and created Microsoft as a business that sold Basic interpreters. As gamedev was locked in C++, there was no real use case for COM there, so MS probably does the expected thing and goes with straight C++. I suspect both of you are wrong in this regard. "No other XAudio2 objects are reference-counted; their lifetimes are explicitly controlled using create and destroy calls, and are bounded by the lifetime of the XAudio2 object that owns them." https://docs.microsoft.com/en-us/windows/win32/api/xaudio2/nn-xaudio2-ixaudio2 COM is used heavily in WinAPI since about Vista. Pretty much all new functionality has been exposed by it and NOT extern(Windows) functions which was the standard during up to about XP (for example notification icons would today be COM based but isn't). E.g. jump lists https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-icustomdestinationlist Windows isn't the only one with a solution like COM. Linux has D-Bus which underpins most newer Desktop Environments. You can do everything from shutdown, log out and even send notification messages via it.
Re: Wrong vtable for COM interfaces that don't inherit IUnknown
On Tuesday, 16 July 2019 at 01:38:49 UTC, evilrat wrote: Also from what I see MS done this intentionally, means they either no longer loves COM or there was some other good reason. Primary consumer of COM interfaces is Visual Basic. It was really only Bill Gates who loved Basic, he wrote a Basic interpreter in 1975 and created Microsoft as a business that sold Basic interpreters. As gamedev was locked in C++, there was no real use case for COM there, so MS probably does the expected thing and goes with straight C++.
Re: Wrong vtable for COM interfaces that don't inherit IUnknown
On Tuesday, 16 July 2019 at 01:38:49 UTC, evilrat wrote: As you can see it is by design. IUnknown has different vtbl[] comparing to regular D classes/interfaces. If it works with declaring your own empty IUnknown use it, also you can try extern(C++) which does similar thing to vtable, it might even work! ... Oh and let me put this here... Have you seen this? It even has very simple xaudio example. https://code.dlang.org/packages/directx-d Yes, i found that after posting. Declaring your interface extern(C++) and the methods in the interface extern(Windows) seems to do the trick. I hoped there would be a more elegant solution than to annotate each interface, but oh well. Thanks anyway!
Re: Wrong vtable for COM interfaces that don't inherit IUnknown
On Monday, 15 July 2019 at 22:01:25 UTC, KytoDragon wrote: I am currently trying to write a XAudio2 backend and have come across the problem, that some of the interfaces for XAudio2's COM objects seem to be missing the first entry in their vtable. After reading the iterface article in the spec (https://dlang.org/spec/interface.html#com-interfaces) it seems that only interfaces inheriting from core.stdc.windows.com.IUnknown (or any interface named "IUnknown") get the COM interface layout instead of the D layout. What can I do to get the COM layout on interfaces that don't inherit IUnknown? Examples: IXAudio2Voice or any of the IXAudio2*Callback interfaces. I have already declared everything extern(Windows), but that does not fix it. As you can see it is by design. IUnknown has different vtbl[] comparing to regular D classes/interfaces. If it works with declaring your own empty IUnknown use it, also you can try extern(C++) which does similar thing to vtable, it might even work! Another option is to craft your own "vtable" with structs, but I'm not going into details about that, you can always google how to do it in C and adapt. And finally you can swap vtable for object instances at runtime, this however is the most complicated and error prone solution, I for example doesn't fully understand D rules for vtable constructing, esp. confusing is that interface entry notice, so anything non trivial (such as class inheriting from class w/multiple interfaces) is beyond me. Expect heavy AV storm. Also from what I see MS done this intentionally, means they either no longer loves COM or there was some other good reason. Oh and let me put this here... Have you seen this? It even has very simple xaudio example. https://code.dlang.org/packages/directx-d
Re: Wrong vtable for COM interfaces that don't inherit IUnknown
On Monday, 15 July 2019 at 22:01:25 UTC, KytoDragon wrote: I am currently trying to write a XAudio2 backend and have come across the problem, that some of the interfaces for XAudio2's COM objects seem to be missing the first entry in their vtable. After reading the iterface article in the spec (https://dlang.org/spec/interface.html#com-interfaces) it seems that only interfaces inheriting from core.stdc.windows.com.IUnknown (or any interface named "IUnknown") get the COM interface layout instead of the D layout. What can I do to get the COM layout on interfaces that don't inherit IUnknown? Examples: IXAudio2Voice or any of the IXAudio2*Callback interfaces. I have already declared everything extern(Windows), but that does not fix it. From memory COM interfaces are really just `extern(C++) interface`s, so extern(C++) interface IXAudio2Voice { //methods... } should do the trick
Wrong vtable for COM interfaces that don't inherit IUnknown
I am currently trying to write a XAudio2 backend and have come across the problem, that some of the interfaces for XAudio2's COM objects seem to be missing the first entry in their vtable. After reading the iterface article in the spec (https://dlang.org/spec/interface.html#com-interfaces) it seems that only interfaces inheriting from core.stdc.windows.com.IUnknown (or any interface named "IUnknown") get the COM interface layout instead of the D layout. What can I do to get the COM layout on interfaces that don't inherit IUnknown? Examples: IXAudio2Voice or any of the IXAudio2*Callback interfaces. I have already declared everything extern(Windows), but that does not fix it.
Re: Order of interfaces
On Friday, 21 June 2019 at 20:50:02 UTC, user1234 wrote: On Friday, 21 June 2019 at 20:42:00 UTC, Tomas wrote: Does it matter in which order a class inherits from interfaces? class A : Interface1, Interface2{ ... } vs class A : Interface2, Interface1{ ... } Conceptually it should not matter, but I'm getting really weird segfault errors with one version and no errors with the other version. compiler segfault or segfault when the program runs ? I still do not know what I'm doing wrong, but does anyone have an idea why the order might matter? I'm getting segfault when running the program.
Re: Order of interfaces
On Friday, 21 June 2019 at 20:42:00 UTC, Tomas wrote: Does it matter in which order a class inherits from interfaces? class A : Interface1, Interface2{ ... } vs class A : Interface2, Interface1{ ... } Conceptually it should not matter, but I'm getting really weird segfault errors with one version and no errors with the other version. compiler segfault or segfault when the program runs ? I still do not know what I'm doing wrong, but does anyone have an idea why the order might matter?
Order of interfaces
Does it matter in which order a class inherits from interfaces? class A : Interface1, Interface2{ ... } vs class A : Interface2, Interface1{ ... } Conceptually it should not matter, but I'm getting really weird segfault errors with one version and no errors with the other version. I still do not know what I'm doing wrong, but does anyone have an idea why the order might matter?
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On 6/6/19 5:36 PM, Jonathan M Davis wrote: On Thursday, June 6, 2019 2:52:42 PM MDT Steven Schveighoffer via Digitalmars-d-learn wrote: On 6/6/19 4:49 PM, Steven Schveighoffer wrote: Oh wait! It's not empty, it has an empty string as a single member! That's definitely a bug. OK, not a bug, but not what I would have expected. From docs: "If T isn't a struct, class, or union, an expression tuple with an empty string is returned." I wonder why that behavior is there, certainly it's intentional. I guess that whoever wrote it did that rather than making it an error so that they wouldn't have to first check whether they were passing a type that even made sense. It still seems like an odd decision though. Normally, you'd just require that an appropriate type be passed. In fact, it feels like the opposite. Returning a tuple of an empty string almost guarantees you will get an error (__traits(getMember, T, "") likely is an error). I just am not sure why someone did that. A perfectly reasonable alternative would be simply to return an empty tuple. -Steve
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On Thursday, 6 June 2019 at 20:52:42 UTC, Steven Schveighoffer wrote: On 6/6/19 4:49 PM, Steven Schveighoffer wrote: Oh wait! It's not empty, it has an empty string as a single member! That's definitely a bug. OK, not a bug, but not what I would have expected. From docs: "If T isn't a struct, class, or union, an expression tuple with an empty string is returned." I wonder why that behavior is there, certainly it's intentional. -Steve It is wrong, regardless if it is intentional. Every day people do intentional things that are wrong. The problem is that one returns a non-empty tuple and so loops will be executed on the empty string. While one can test for the empty string return there is absolutely no reason why one shouldn't just return an empty tuple as it plays correctly with the use case.
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On Thursday, June 6, 2019 2:52:42 PM MDT Steven Schveighoffer via Digitalmars-d-learn wrote: > On 6/6/19 4:49 PM, Steven Schveighoffer wrote: > > Oh wait! It's not empty, it has an empty string as a single member! > > That's definitely a bug. > > OK, not a bug, but not what I would have expected. From docs: > > "If T isn't a struct, class, or union, an expression tuple with an empty > string is returned." > > I wonder why that behavior is there, certainly it's intentional. I guess that whoever wrote it did that rather than making it an error so that they wouldn't have to first check whether they were passing a type that even made sense. It still seems like an odd decision though. Normally, you'd just require that an appropriate type be passed. - Jonathan M Davis
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On 6/6/19 4:49 PM, Steven Schveighoffer wrote: Oh wait! It's not empty, it has an empty string as a single member! That's definitely a bug. OK, not a bug, but not what I would have expected. From docs: "If T isn't a struct, class, or union, an expression tuple with an empty string is returned." I wonder why that behavior is there, certainly it's intentional. -Steve
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On 6/6/19 4:43 PM, Steven Schveighoffer wrote: On 6/6/19 4:22 PM, Amex wrote: FieldNameTuple!T std.traits.Fields!T are non-empty when T is an interface! An interface cannot contain fields and yet these return non-zero and screws up my code. While I can filter for interfaces it makes me wonder what else may slip through? Is it a bug or what is going on? Can you provide code to demonstrate? I get no fields when I do this: interface I { } import std.traits; pragma(msg, FieldNameTuple!I); Oh wait! It's not empty, it has an empty string as a single member! That's definitely a bug. -Steve
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On 6/6/19 4:22 PM, Amex wrote: FieldNameTuple!T std.traits.Fields!T are non-empty when T is an interface! An interface cannot contain fields and yet these return non-zero and screws up my code. While I can filter for interfaces it makes me wonder what else may slip through? Is it a bug or what is going on? Can you provide code to demonstrate? I get no fields when I do this: interface I { } import std.traits; pragma(msg, FieldNameTuple!I); -Steve
Re: FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
On Thursday, 6 June 2019 at 20:22:26 UTC, Amex wrote: Is it a bug or what is going on? my suspicion is it is actually the pointer to the vtable getting caught up in it but idk, i didn't really look, just guessing.
FieldNameTuple!T and std.traits.Fields!T not empty for interfaces
FieldNameTuple!T std.traits.Fields!T are non-empty when T is an interface! An interface cannot contain fields and yet these return non-zero and screws up my code. While I can filter for interfaces it makes me wonder what else may slip through? Is it a bug or what is going on?
Re: Alternative to Interfaces
On Friday, 25 January 2019 at 19:34:02 UTC, Sebastien Alaiwan wrote: On Saturday, 19 January 2019 at 09:24:21 UTC, Kagamin wrote: On Friday, 18 January 2019 at 18:48:46 UTC, Jonathan M Davis wrote: Yes, but some D features will use the GC They would like to allocate, but they don't know nor care where it's allocated from, if the developer uses custom memory management, he will know how it's allocated and will be able to manage it. Is it possible to get the raw context pointer from a given delegate? If not, how to deallocate the context without garbage collection? You can access the context pointer of a delegate using its `.ptr` property, but changing how it's allocated would require changes to druntime. Some alternatives are discussed in this thread: https://forum.dlang.org/thread/mgbdrhcudlhsadnwz...@forum.dlang.org
Re: Alternative to Interfaces
On Saturday, 19 January 2019 at 09:24:21 UTC, Kagamin wrote: On Friday, 18 January 2019 at 18:48:46 UTC, Jonathan M Davis wrote: Yes, but some D features will use the GC They would like to allocate, but they don't know nor care where it's allocated from, if the developer uses custom memory management, he will know how it's allocated and will be able to manage it. Is it possible to get the raw context pointer from a given delegate? If not, how to deallocate the context without garbage collection?
Re: preconditions and interfaces
On Sunday, 20 January 2019 at 15:39:49 UTC, Antonio Corbi wrote: Hi all, Playing with interfaces and preconditions in methods I get strange results with dmd-2.0.84.0 but also with dmd-nightly. My code is like this: - import std.stdio; interface Thing2D { void width(int w) in { writeln("Thing2D.width contract w = ",w); assert(w > 0); } } class Line : Thing2D { override void width(int w) in { writeln("Line.width contract w = ",w); assert(w >= 0); } do { writeln("Line.width: w = ", w); } } void main() { auto l = new Line; l.width(-1); } --- 1) With dmd-2.084.0 I get: ./ifaceprecond Thing2D.width contract w = 2 Line.width: w = -1 2) With dmd-nightly (as of today) I get random values for interface's 'w': ./ifaceprecond Thing2D.width contract w = 647271536 Line.width: w = -1 I think this should be an error caught by the contract, isn't it? Thx! Antonio Seems to be something known... https://forum.dlang.org/post/hficlieevnvzrnxyw...@forum.dlang.org
preconditions and interfaces
Hi all, Playing with interfaces and preconditions in methods I get strange results with dmd-2.0.84.0 but also with dmd-nightly. My code is like this: - import std.stdio; interface Thing2D { void width(int w) in { writeln("Thing2D.width contract w = ",w); assert(w > 0); } } class Line : Thing2D { override void width(int w) in { writeln("Line.width contract w = ",w); assert(w >= 0); } do { writeln("Line.width: w = ", w); } } void main() { auto l = new Line; l.width(-1); } --- 1) With dmd-2.084.0 I get: ./ifaceprecond Thing2D.width contract w = 2 Line.width: w = -1 2) With dmd-nightly (as of today) I get random values for interface's 'w': ./ifaceprecond Thing2D.width contract w = 647271536 Line.width: w = -1 I think this should be an error caught by the contract, isn't it? Thx! Antonio
Re: Alternative to Interfaces
On Friday, 18 January 2019 at 18:48:46 UTC, Jonathan M Davis wrote: Yes, but some D features will use the GC They would like to allocate, but they don't know nor care where it's allocated from, if the developer uses custom memory management, he will know how it's allocated and will be able to manage it. The list of such features is short, but delegates are on it. Closures are, but not delegates. Delegate is just a pair of pointers, you don't need to allocate at all to keep them around, similar to slices. They even work in betterC. get around the allocations in some cases, but in general, if you use delegates, you're going to allocate with the GC. Custom memory management is obviously not the general case. but the allocations that happen for delegates and lambdas is one of the biggest reasons that some folks avoid std.algorithm and complain that it allocates. That's what happens when you pass stuff that the compiler decides has to have closures allocated for it. Is it really blocked? I got this to work with dip1000: @safe @nogc: alias int delegate(int) @safe @nogc dg; struct Map(T) { private T a; } Map!dg map(return dg b) { Map!dg m; m.a=b; return m; } void f() { int a; auto b=map(i=>a); a=b.a(0); } Templated function can't infer closure type for some reason.
Re: Alternative to Interfaces
On Friday, January 18, 2019 8:08:47 AM MST Kagamin via Digitalmars-d-learn wrote: > On Friday, 18 January 2019 at 00:08:00 UTC, 1001Days wrote: > > It works, but I have two questions regarding its efficacy: is > > it viable in the long run, and is it now possible to use > > delegates without the GC? > > GC is just a handy memory management approach, it even works for > C and C++, (example: gcc), nothing in D needs GC if you manage > memory in a different way. In fact there are D libraries that > rely solely on manual memory management. Yes, but some D features will use the GC, and you can't really stop that aside from simply not using those features. The list of such features is short, but delegates are on it. scope will get around the allocations in some cases, but in general, if you use delegates, you're going to allocate with the GC. There are alternatives to using delegates which will get you similar behavior allocating (e.g. functors), but the allocations that happen for delegates and lambdas is one of the biggest reasons that some folks avoid std.algorithm and complain that it allocates. That's what happens when you pass stuff that the compiler decides has to have closures allocated for it. Completely avoiding the GC with D is possible, but it tends to require that you be very careful and have a good understanding of where D needs to use the GC to do what it does (though the fact that we now have @nogc, and it screams at you if the code allocates does help you catch GC usage when you didn't realize that it was there). - Jonathan M Davis
Re: Alternative to Interfaces
On Friday, 18 January 2019 at 00:08:00 UTC, 1001Days wrote: It works, but I have two questions regarding its efficacy: is it viable in the long run, and is it now possible to use delegates without the GC? GC is just a handy memory management approach, it even works for C and C++, (example: gcc), nothing in D needs GC if you manage memory in a different way. In fact there are D libraries that rely solely on manual memory management.
Re: Alternative to Interfaces
On Friday, 18 January 2019 at 01:00:33 UTC, H. S. Teoh wrote: Maybe you could help us answer your question better by explaining a bit more what you're trying to achieve. Generally, if you want to use an interface, that usually means you want (1) runtime polymorphism, i.e., the ability to swap one concrete implementation for another at runtime, and (2) pass around possibly different concrete objects to code that expects objects of a single type (the interface type). I do apologize for my vagueness. In hindsight, it was quite a poor way to request for help. Anyway, for my current use case, the latter's functionality is what I am attempting to replicate. If the reason you're using structs is just to avoid the GC, then you should look up emplace() in the docs. It *is* possible to use classes without using the GC. Just in case you didn't know. Thank you for informing me of this. I didn't know. So from a cursory glance it would seem that I would, omitting details, make a wrapper function that combines an allocator (e.g. malloc) and emplace. (Though you should also keep in mind the possible drawbacks of template bloat -- which may cause more instruction cache misses by making your code larger than it could have been.) Yes, this is something I worried about too. My personal tendency is to start with structs and compile-time introspection as an initial stab, but depending on what might be needed, I may use some classes / interfaces. The two can be combined to some extent -- e.g., a template function can take both structs with compile-time introspection and also classes that allow runtime polymorphism. A template function instantiated with a class type will be able to accept different concrete objects at runtime (as long as they are subclasses of that type). However, it will only be able to "see" the static info of the class it was instantiated with, not any additional features of derived classes that it may receive at runtime, since there will be no runtime introspection. Initially, I was going to use Classes when I needed to use Interfaces and use Structs for everything else, but I decided against that because I was worried it would make the program's structure "inconsistent," for the lack of a better word, and again the GC. Though AFAIK, delegates probably still need heap allocation and depend on the GC, esp. if you have closures over local variables. There may be some cases where the compiler will elide this, e.g., if you have a function literal passed via an alias that does not escape the caller's scope. OTOH, you might be able to get around needing the GC if you put your delegates in an emplace()'d class as methods, and take their address (which produces a delegate). Just make sure your class doesn't go out of scope while the resulting delegates are still around. Keep in mind that in this case, you will not be able to have closure over local variables (delegates can only have 1 context pointer, and in this case it's already used up by the `this` reference) and will have to store any such contextual information inside the class itself. With regards to the emplaced class, this is interesting. My main use for the delegate was in achieving one of the effects of interfaces for Structs, so I don't think I'll be using them as much. I'll have to pay close attention to the profiler in any case. With the information you gave me, I think I'll try Class & emplace as I really don't want to attempt replicate existing functionality--especially so considering my experience level. With thanks, 1001Days
Re: Alternative to Interfaces
On Fri, Jan 18, 2019 at 12:08:00AM +, 1001Days via Digitalmars-d-learn wrote: > Hello, > > Preface: I do apologize if this is too simplistic of a matter, and if > I need to RTFM. I'm quite slow. > > I want to use Structs instead of Classes, but I don't want to lose the > abilities of Interfaces. So instead I used a combination of templates, > constraints, the hasMember trait, and delegates to achieve a simple > alternative. Maybe you could help us answer your question better by explaining a bit more what you're trying to achieve. Generally, if you want to use an interface, that usually means you want (1) runtime polymorphism, i.e., the ability to swap one concrete implementation for another at runtime, and (2) pass around possibly different concrete objects to code that expects objects of a single type (the interface type). So the first question is, do you need runtime polymorphism? Do you need to pass objects of different types to functions that only take a single type? Do you need the ability to change *at runtime* the type of object passed to a function? If so, you probably should stick with interfaces and classes. While it *is* possible to achieve equivalent functionality with structs and templates, you'll basically end up reinventing classes, possibly poorly, and spending coding / debugging time doing so when you could have just used the built-in construct. If the reason you're using structs is just to avoid the GC, then you should look up emplace() in the docs. It *is* possible to use classes without using the GC. Just in case you didn't know. OTOH, if you don't need runtime polymorphism, then using classes and templates would be the "more idiomatic" way to do it. (Though you should also keep in mind the possible drawbacks of template bloat -- which may cause more instruction cache misses by making your code larger than it could have been.) > It works, but I have two questions regarding its efficacy: is it > viable in the long run, and is it now possible to use delegates > without the GC? The latter is of particular importance as I'm using > Structs for compatibility. [...] Whether or not it's viable really depends on whether you need runtime polymorphism, and what you're trying to accomplish. My personal tendency is to start with structs and compile-time introspection as an initial stab, but depending on what might be needed, I may use some classes / interfaces. The two can be combined to some extent -- e.g., a template function can take both structs with compile-time introspection and also classes that allow runtime polymorphism. A template function instantiated with a class type will be able to accept different concrete objects at runtime (as long as they are subclasses of that type). However, it will only be able to "see" the static info of the class it was instantiated with, not any additional features of derived classes that it may receive at runtime, since there will be no runtime introspection. Though AFAIK, delegates probably still need heap allocation and depend on the GC, esp. if you have closures over local variables. There may be some cases where the compiler will elide this, e.g., if you have a function literal passed via an alias that does not escape the caller's scope. OTOH, you might be able to get around needing the GC if you put your delegates in an emplace()'d class as methods, and take their address (which produces a delegate). Just make sure your class doesn't go out of scope while the resulting delegates are still around. Keep in mind that in this case, you will not be able to have closure over local variables (delegates can only have 1 context pointer, and in this case it's already used up by the `this` reference) and will have to store any such contextual information inside the class itself. T -- It always amuses me that Windows has a Safe Mode during bootup. Does that mean that Windows is normally unsafe?
Alternative to Interfaces
Hello, Preface: I do apologize if this is too simplistic of a matter, and if I need to RTFM. I'm quite slow. I want to use Structs instead of Classes, but I don't want to lose the abilities of Interfaces. So instead I used a combination of templates, constraints, the hasMember trait, and delegates to achieve a simple alternative. It works, but I have two questions regarding its efficacy: is it viable in the long run, and is it now possible to use delegates without the GC? The latter is of particular importance as I'm using Structs for compatibility. With thanks, 1001Days
Re: Weird combo of static function, templates, interfaces (that doesn't link)
On Sunday, 30 December 2018 at 18:55:10 UTC, Ali Çehreli wrote: On 12/30/2018 05:05 AM, 0xEAB wrote: >> interface FooAdapter >> { >> FooBundle!(Handle) createSome(Handle)(); >> } Function templates cannot be virtual functions. One reason is the compiler cannot know how large the virtual function table should be, and the other one is it's just a template, not the real thing (i.e. not a function). >> private class SomeAdapter : FooAdapter >> { >> Bundle createSome() SomeAdapter.createSome is a function unrelated to FooAdapter.createSome. Their only relationship is through "name hiding." > - Does `SomeAdapter` even implement `FooAdapter` correctly? Yes because FooAdapter has no virtual function. :p > ~ Elias Ali Thanks for the technical explanation. ~ Elias
Re: Weird combo of static function, templates, interfaces (that doesn't link)
On 12/30/2018 05:05 AM, 0xEAB wrote: >> interface FooAdapter >> { >> FooBundle!(Handle) createSome(Handle)(); >> } Function templates cannot be virtual functions. One reason is the compiler cannot know how large the virtual function table should be, and the other one is it's just a template, not the real thing (i.e. not a function). >> private class SomeAdapter : FooAdapter >> { >> Bundle createSome() SomeAdapter.createSome is a function unrelated to FooAdapter.createSome. Their only relationship is through "name hiding." > - Does `SomeAdapter` even implement `FooAdapter` correctly? Yes because FooAdapter has no virtual function. :p > ~ Elias Ali
Weird combo of static function, templates, interfaces (that doesn't link)
void main() { StaticThingy.register(new SomeAdapter()); StaticThingy.createSome!Dummy(); } interface FooAdapter { FooBundle!(Handle) createSome(Handle)(); } private class SomeAdapter : FooAdapter { Bundle createSome() { auto w = new Dummy(); auto c = new FooDummy(); auto b = Bundle(c, w); return b; } } struct StaticThingy { static: FooBundle!(Handle) createSome(Handle)() { return fooAdapter.createSome!(Handle)(); } // ... error: undefined reference to '_D9onlineapp10FooAdapter__T10createSomeTCQBn5DummyZQyMFZSQCd__T9FooBundleTQBiZQp' collect2: error: ld returned 1 exit status Error: linker exited with status 1 Hey :) During playing around I came up with code similar to the example above. As the title says, this code doesn't link. For the full example please see: https://run.dlang.io/is/mr0u2i - But should this even compile successfully? - Does `SomeAdapter` even implement `FooAdapter` correctly? ~ Elias
Re: cas and interfaces
On Thursday, 27 December 2018 at 12:07:48 UTC, Rene Zwanenburg wrote: On Tuesday, 25 December 2018 at 22:07:07 UTC, Johannes Loher wrote: Thanks a lot for the info, that clarifies things a bit. But it still leaves the question, why it works correctly when inheriting from an abstract class instead of implementing an interface... Any idea about why that? Unlike interfaces, base class references don't need adjustment. Yeah. You shouldn't need to know these details but if you are interested, the details are here: https://dlang.org/spec/abi.html#classes (it's meant for tech reference, not for explanation. If you need more explanation, go search for vtables, multiple inheritance, etc.). -Johan
Re: cas and interfaces
On Tuesday, 25 December 2018 at 22:07:07 UTC, Johannes Loher wrote: Thanks a lot for the info, that clarifies things a bit. But it still leaves the question, why it works correctly when inheriting from an abstract class instead of implementing an interface... Any idea about why that? Unlike interfaces, base class references don't need adjustment. You can see this in action by printing addresses: https://run.dlang.io/is/m6icVr import std.stdio; interface I {} class Base : I {} class Derived : Base { } void main() { auto derived = new Derived; Base base = derived; I i = derived; writeln(cast(void*)derived); writeln(cast(void*)base); writeln(cast(void*)i); } 7FC1F96EE000 7FC1F96EE000 7FC1F96EE010
Re: cas and interfaces
On Monday, 24 December 2018 at 11:23:32 UTC, Johan Engelen wrote: On Sunday, 23 December 2018 at 14:07:04 UTC, Johannes Loher wrote: [...] The types of the 2nd and 3rd arguments of `cas` do not have to be the same, and aren't in your case. I think what's happening is that you are overwriting `testInterface` with a pointer to a TestClass which is not a valid TestInterface pointer. And then the program does something invalid because, well, you enter UB land. Fixed by: ``` cas(&testInterface, testInterface, cast(shared(TestInterface)) new shared TestClass).writeln; ``` Note the cast! Whether this is a bug in `cas` or not, I don't know. The `cas` template checks whether the 3rd can be assigned to the 1st argument (`*here = writeThis;`) which indeed compiles _with_ an automatic conversion. But then the implementation of `cas` does not do any automatic conversions (casts to `void*`). Hence the problem you are seeing. -Johan Thanks a lot for the info, that clarifies things a bit. But it still leaves the question, why it works correctly when inheriting from an abstract class instead of implementing an interface... Any idea about why that?
Re: cas and interfaces
On Sunday, 23 December 2018 at 14:07:04 UTC, Johannes Loher wrote: I recently played around with atomic operations. While doing so, I noticed a problem with the interaction of interfaces and cas. Consider the following program: ``` import core.atomic; import std.stdio; interface TestInterface { } class TestClass : TestInterface { } void main() { shared TestInterface testInterface = new shared TestClass; cas(&testInterface, testInterface, new shared TestClass).writeln; writeln(typeid(testInterface)); } ``` (https://run.dlang.io/is/9P7PAb) The types of the 2nd and 3rd arguments of `cas` do not have to be the same, and aren't in your case. I think what's happening is that you are overwriting `testInterface` with a pointer to a TestClass which is not a valid TestInterface pointer. And then the program does something invalid because, well, you enter UB land. Fixed by: ``` cas(&testInterface, testInterface, cast(shared(TestInterface)) new shared TestClass).writeln; ``` Note the cast! Whether this is a bug in `cas` or not, I don't know. The `cas` template checks whether the 3rd can be assigned to the 1st argument (`*here = writeThis;`) which indeed compiles _with_ an automatic conversion. But then the implementation of `cas` does not do any automatic conversions (casts to `void*`). Hence the problem you are seeing. -Johan
cas and interfaces
I recently played around with atomic operations. While doing so, I noticed a problem with the interaction of interfaces and cas. Consider the following program: ``` import core.atomic; import std.stdio; interface TestInterface { } class TestClass : TestInterface { } void main() { shared TestInterface testInterface = new shared TestClass; cas(&testInterface, testInterface, new shared TestClass).writeln; writeln(typeid(testInterface)); } ``` (https://run.dlang.io/is/9P7PAb) This program compiles successfully and outputs ``` true Error: program killed by signal 11 ``` i.e. a segmentation fault happens. When replacing "interface" with "abstract class" (https://run.dlang.io/is/sFaO1k), everything works as expected and the program outputs ``` true onlineapp.TestClass ``` Is this actually a bug or a fundamental limitation of cas and interfaces? Did I do anything wrong?
Re: contracts in interfaces: do they work, do I have to do something to enable checking of contracts ?
On Monday, 1 October 2018 at 13:49:53 UTC, Emil wrote: I am trying my hand at contracts and they work fine in plain functions and in methods, but I can't make them work in interfaces. https://dlang.org/spec/interface.html#interface-contracts $ dmd --version DMD64 D Compiler v2.081.1 Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright / void main() { WillBloop test = new WillBloop(); // also tried // Blooper test = new WillBloop(); // it compiles but the in contract does not seem enforced test.limited(-1); // this does not croak auto no_interface = new NoInterface(); no_interface.limited(-10); // this works as expected } interface Blooper { void limited(int some_other_name) in { assert(some_other_name > 0, "asssert failed in interface"); } } class WillBloop : Blooper { void limited(int a_name){ import std.stdio : writeln; writeln(a_name); } } class NoInterface { void limited(int another_name) in { assert(another_name > 0, "assert failed in NoInterface"); } do { import std.stdio: writeln; writeln(another_name); } } Yeah... had such problems too, a while ago. https://forum.dlang.org/thread/sadsceubvapbeezjy...@forum.dlang.org Seems, that one of the tickets is closed, but the pull request is not merged. Don't know how matters stand with this, actually.