Re: How to get an IP address from network interfaces

2022-04-22 Thread H. S. Teoh via Digitalmars-d-learn
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

2022-04-22 Thread IGotD- via Digitalmars-d-learn

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

2022-04-22 Thread H. S. Teoh via Digitalmars-d-learn
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

2022-04-22 Thread IGotD- via Digitalmars-d-learn

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

2022-04-21 Thread dangbinghoo via Digitalmars-d-learn

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

2022-04-21 Thread dangbinghoo via Digitalmars-d-learn
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

2022-04-21 Thread Alexander Zhirov via Digitalmars-d-learn

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

2022-04-21 Thread dangbinghoo via Digitalmars-d-learn

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

2022-04-21 Thread dangbinghoo via Digitalmars-d-learn
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

2022-04-21 Thread Alexander Zhirov via Digitalmars-d-learn
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

2021-09-27 Thread Ali Çehreli via Digitalmars-d-learn

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

2021-09-27 Thread Tejas via Digitalmars-d-learn

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

2021-09-27 Thread kyle via Digitalmars-d-learn

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

2021-09-27 Thread Adam D Ruppe via Digitalmars-d-learn
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

2021-09-27 Thread Salih Dincer via Digitalmars-d-learn

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

2021-09-27 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2021-09-27 Thread kyle via Digitalmars-d-learn
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[]

2021-03-13 Thread tsbockman via Digitalmars-d-learn

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[]

2021-03-13 Thread frame via Digitalmars-d-learn

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[]

2021-03-12 Thread tsbockman via Digitalmars-d-learn

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[]

2021-03-12 Thread David Zhang via Digitalmars-d-learn

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[]

2021-03-12 Thread tsbockman via Digitalmars-d-learn

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[]

2021-03-12 Thread David Zhang via Digitalmars-d-learn

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[]

2021-03-12 Thread David Zhang via Digitalmars-d-learn

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[]

2021-03-12 Thread tsbockman via Digitalmars-d-learn

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[]

2021-03-12 Thread tsbockman via Digitalmars-d-learn

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[]

2021-03-12 Thread Imperatorn via Digitalmars-d-learn

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[]

2021-03-12 Thread David Zhang via Digitalmars-d-learn

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[]

2021-03-12 Thread Imperatorn via Digitalmars-d-learn

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[]

2021-03-12 Thread David Zhang via Digitalmars-d-learn
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

2020-10-27 Thread frame via Digitalmars-d-learn

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

2020-10-27 Thread frame via Digitalmars-d-learn

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

2020-10-27 Thread Jacob Carlborg via Digitalmars-d-learn

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

2020-10-27 Thread frame via Digitalmars-d-learn

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

2020-10-26 Thread Jacob Carlborg via Digitalmars-d-learn

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

2020-10-26 Thread frame via Digitalmars-d-learn

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

2020-10-26 Thread Simen Kjærås via Digitalmars-d-learn

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

2020-10-26 Thread frame via Digitalmars-d-learn

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

2019-09-20 Thread Ali Çehreli via Digitalmars-d-learn

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

2019-09-20 Thread Adam D. Ruppe via Digitalmars-d-learn

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

2019-09-20 Thread JN via Digitalmars-d-learn

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*

2019-08-14 Thread wjoe via Digitalmars-d-learn

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*

2019-08-11 Thread Alex via Digitalmars-d-learn

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*

2019-08-11 Thread Jonathan M Davis via Digitalmars-d-learn
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*

2019-08-11 Thread Adam D. Ruppe via Digitalmars-d-learn

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*

2019-08-11 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-11 Thread Alex via Digitalmars-d-learn

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*

2019-08-11 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-11 Thread Alex via Digitalmars-d-learn

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*

2019-08-11 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-11 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-10 Thread Timon Gehr via Digitalmars-d-learn

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*

2019-08-10 Thread Alex via Digitalmars-d-learn

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*

2019-08-10 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-10 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-10 Thread Alex via Digitalmars-d-learn

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*

2019-08-10 Thread Antonio Corbi via Digitalmars-d-learn

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*

2019-08-10 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-10 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-09 Thread Simen Kjærås via Digitalmars-d-learn

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*

2019-08-09 Thread John Colvin via Digitalmars-d-learn

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*

2019-08-09 Thread kinke via Digitalmars-d-learn

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*

2019-08-09 Thread John Colvin via Digitalmars-d-learn

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

2019-07-21 Thread Kagamin via Digitalmars-d-learn

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

2019-07-21 Thread rikki cattermole via Digitalmars-d-learn

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

2019-07-20 Thread Kagamin via Digitalmars-d-learn

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

2019-07-16 Thread KytoDragon via Digitalmars-d-learn

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

2019-07-15 Thread evilrat via Digitalmars-d-learn

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

2019-07-15 Thread Nicholas Wilson via Digitalmars-d-learn

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

2019-07-15 Thread KytoDragon via Digitalmars-d-learn
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

2019-06-21 Thread Tomas via Digitalmars-d-learn

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

2019-06-21 Thread user1234 via Digitalmars-d-learn

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

2019-06-21 Thread Tomas via Digitalmars-d-learn

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

2019-06-08 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2019-06-07 Thread Amex via Digitalmars-d-learn
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

2019-06-06 Thread Jonathan M Davis via Digitalmars-d-learn
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

2019-06-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2019-06-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2019-06-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2019-06-06 Thread Adam D. Ruppe via Digitalmars-d-learn

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

2019-06-06 Thread Amex via Digitalmars-d-learn

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

2019-01-25 Thread Paul Backus via Digitalmars-d-learn
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

2019-01-25 Thread Sebastien Alaiwan via Digitalmars-d-learn

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

2019-01-20 Thread Alex via Digitalmars-d-learn

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

2019-01-20 Thread Antonio Corbi via Digitalmars-d-learn

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

2019-01-19 Thread Kagamin via Digitalmars-d-learn
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

2019-01-18 Thread Jonathan M Davis via Digitalmars-d-learn
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

2019-01-18 Thread Kagamin via Digitalmars-d-learn

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

2019-01-17 Thread 1001Days via Digitalmars-d-learn

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

2019-01-17 Thread H. S. Teoh via Digitalmars-d-learn
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

2019-01-17 Thread 1001Days via Digitalmars-d-learn

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)

2019-01-02 Thread 0xEAB via Digitalmars-d-learn

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)

2018-12-30 Thread Ali Çehreli via Digitalmars-d-learn

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)

2018-12-30 Thread 0xEAB via Digitalmars-d-learn

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

2018-12-27 Thread Johan Engelen via Digitalmars-d-learn
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

2018-12-27 Thread Rene Zwanenburg via Digitalmars-d-learn
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

2018-12-25 Thread Johannes Loher via Digitalmars-d-learn

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

2018-12-24 Thread Johan Engelen via Digitalmars-d-learn

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

2018-12-23 Thread Johannes Loher via Digitalmars-d-learn
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 ?

2018-10-01 Thread Alex via Digitalmars-d-learn

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.


  1   2   3   4   5   >