Re: Enum that can be 0 or null

2016-06-07 Thread ag0aep6g via Digitalmars-d-learn

On 06/07/2016 08:50 PM, ParticlePeter wrote:

On Tuesday, 7 June 2016 at 14:31:40 UTC, Alex Parrill wrote:

I don't think opCast gets called for implicit conversions; it only
gets called for explicit casts. I'll test it later.


It does for type bool, but I fear that's the only exception.


No, opCast can't be used for implicit conversions to bool.

I guess you're thinking of the `if(foo) {...}` case. That's considered 
an explicit conversion. `bool b = foo;` still won't work.


Re: Enum that can be 0 or null

2016-06-07 Thread ParticlePeter via Digitalmars-d-learn

On Tuesday, 7 June 2016 at 14:31:40 UTC, Alex Parrill wrote:
I don't think opCast gets called for implicit conversions; it 
only gets called for explicit casts. I'll test it later.


It does for type bool, but I fear that's the only exception.


Re: Enum that can be 0 or null

2016-06-07 Thread Alex Parrill via Digitalmars-d-learn

On Tuesday, 7 June 2016 at 04:31:56 UTC, ParticlePeter wrote:

On Monday, 6 June 2016 at 20:32:23 UTC, Alex Parrill wrote:
They'd be the same type, since you would define the vulkan 
functions to take these structures instead of pointer or 
integer types.


It relies on a lot of assumptions about the ABI that make a 
raw pointer work the same as a structure containing just one 
pointer, which is why I did not give it much consideration.


Is there a way to use opCast (just an idea, not working code) ?

private struct VK_HANDLE_HELPER {
const void * handle = null;
alias handle this;
T opCast(T)() if( is( T == uint64_t )) {
return 0uL;
}
}
const VK_NULL_HANDLE = VK_HANDLE_HELPER();



I don't think opCast gets called for implicit conversions; it 
only gets called for explicit casts. I'll test it later.


Re: Enum that can be 0 or null

2016-06-07 Thread tsbockman via Digitalmars-d-learn

On Monday, 6 June 2016 at 20:32:23 UTC, Alex Parrill wrote:
It relies on a lot of assumptions about the ABI that make a raw 
pointer work the same as a structure containing just one 
pointer, which is why I did not give it much consideration.


At least some of those assumptions could be verified at compile 
time:


// insert at the end of the VkHandle mixin template:
static assert(typeof(this).sizeof == typeof(bits).sizeof);
static assert(typeof(this).alignof == typeof(bits).alignof);

If you want to be extra careful, you can also use a string mixin 
to declare each extern(C) function with its official C parameter 
types, plus a D pragma(inline, true) wrapper that accepts 
VkDevice or whatever, instead.


Of course, it's probably a lot easier to just tel your users to 
replace VK_NULL_HANDLE with VK_NULL_DISPATCHABLE or 
VK_NULL_NONDISPATCHABLE like you suggested earlier.


Re: Enum that can be 0 or null

2016-06-06 Thread ParticlePeter via Digitalmars-d-learn

On Monday, 6 June 2016 at 20:32:23 UTC, Alex Parrill wrote:
They'd be the same type, since you would define the vulkan 
functions to take these structures instead of pointer or 
integer types.


It relies on a lot of assumptions about the ABI that make a raw 
pointer work the same as a structure containing just one 
pointer, which is why I did not give it much consideration.


Is there a way to use opCast (just an idea, not working code) ?

private struct VK_HANDLE_HELPER {
const void * handle = null;
alias handle this;
T opCast(T)() if( is( T == uint64_t )) {
return 0uL;
}
}
const VK_NULL_HANDLE = VK_HANDLE_HELPER();



Re: Enum that can be 0 or null

2016-06-06 Thread Alex Parrill via Digitalmars-d-learn

On Monday, 6 June 2016 at 18:43:33 UTC, ParticlePeter wrote:

On Saturday, 21 May 2016 at 06:36:53 UTC, tsbockman wrote:

...
As an example, if VK_NULL_HANDLE only ever needs to be 
assigned to opaque types on the D side (that is, types that 
serve only as an ID or address for communicating with the C 
side), you could do this:


private struct VkNullHandle { }
enum VK_NULL_HANDLE = VkNullHandle.init;

mixin template VkHandle(bool dispatchable) {
static if (dispatchable || (size_t.sizeof == 8))
void* bits = null;
else
ulong bits = 0;

this(typeof(this) that) {
this.bits = that.bits; }
this(VkNullHandle that) {
this.bits = typeof(this.bits).init; }

ref typeof(this) opAssign(typeof(this) that) {
this.bits = that.bits;
return this;
}
ref typeof(this) opAssign(VkNullHandle that) {
this.bits = typeof(this.bits).init;
return this;
}
}

struct VkDevice { mixin VkHandle!true; }
struct VkInstance { mixin VkHandle!true; }

struct VkFence { mixin VkHandle!false; }
struct VkSemaphore { mixin VkHandle!false; }


void main() {
VkInstance a = VK_NULL_HANDLE;
VkFence b = VK_NULL_HANDLE;
}

(DPaste: https://dpaste.dzfl.pl/8f4ce39a907f )

The above is typesafe, and can easily be made compatible with 
a typical C API, since C does no parameter-related name 
mangling.


In this case I don't see how it would be possible to use your 
VkDevice, etc. as argument to the C functions, as they are of 
different type, no?


They'd be the same type, since you would define the vulkan 
functions to take these structures instead of pointer or integer 
types.


It relies on a lot of assumptions about the ABI that make a raw 
pointer work the same as a structure containing just one pointer, 
which is why I did not give it much consideration.


Re: Enum that can be 0 or null

2016-06-06 Thread ParticlePeter via Digitalmars-d-learn

On Saturday, 21 May 2016 at 06:36:53 UTC, tsbockman wrote:

...
As an example, if VK_NULL_HANDLE only ever needs to be assigned 
to opaque types on the D side (that is, types that serve only 
as an ID or address for communicating with the C side), you 
could do this:


private struct VkNullHandle { }
enum VK_NULL_HANDLE = VkNullHandle.init;

mixin template VkHandle(bool dispatchable) {
static if (dispatchable || (size_t.sizeof == 8))
void* bits = null;
else
ulong bits = 0;

this(typeof(this) that) {
this.bits = that.bits; }
this(VkNullHandle that) {
this.bits = typeof(this.bits).init; }

ref typeof(this) opAssign(typeof(this) that) {
this.bits = that.bits;
return this;
}
ref typeof(this) opAssign(VkNullHandle that) {
this.bits = typeof(this.bits).init;
return this;
}
}

struct VkDevice { mixin VkHandle!true; }
struct VkInstance { mixin VkHandle!true; }

struct VkFence { mixin VkHandle!false; }
struct VkSemaphore { mixin VkHandle!false; }


void main() {
VkInstance a = VK_NULL_HANDLE;
VkFence b = VK_NULL_HANDLE;
}

(DPaste: https://dpaste.dzfl.pl/8f4ce39a907f )

The above is typesafe, and can easily be made compatible with a 
typical C API, since C does no parameter-related name mangling.


In this case I don't see how it would be possible to use your 
VkDevice, etc. as argument to the C functions, as they are of 
different type, no?


Re: Enum that can be 0 or null

2016-05-20 Thread tsbockman via Digitalmars-d-learn

On Saturday, 21 May 2016 at 01:09:42 UTC, Alex Parrill wrote:

On Friday, 20 May 2016 at 22:10:51 UTC, tsbockman wrote:
If that's not a satisfactory answer, please show some specific 
examples of code that you don't know how to make work without 
VK_NULL_HANDLE so that I can propose a workaround.


Because, as I mentioned in the OP, for VK_NULL_HANDLE to work 
like it does in C on 32-bit systems, it needs to be compatible 
with both pointer types (VkDevice, VkInstance, etc) and 64-bit 
integer types (VkFence, VkSemaphore, many others).


That is not code. As I said, there are many possible workarounds, 
but it is hard to say which is best for you without actually 
seeing your code.


As an example, if VK_NULL_HANDLE only ever needs to be assigned 
to opaque types on the D side (that is, types that serve only as 
an ID or address for communicating with the C side), you could do 
this:


private struct VkNullHandle { }
enum VK_NULL_HANDLE = VkNullHandle.init;

mixin template VkHandle(bool dispatchable) {
static if (dispatchable || (size_t.sizeof == 8))
void* bits = null;
else
ulong bits = 0;

this(typeof(this) that) {
this.bits = that.bits; }
this(VkNullHandle that) {
this.bits = typeof(this.bits).init; }

ref typeof(this) opAssign(typeof(this) that) {
this.bits = that.bits;
return this;
}
ref typeof(this) opAssign(VkNullHandle that) {
this.bits = typeof(this.bits).init;
return this;
}
}

struct VkDevice { mixin VkHandle!true; }
struct VkInstance { mixin VkHandle!true; }

struct VkFence { mixin VkHandle!false; }
struct VkSemaphore { mixin VkHandle!false; }


void main() {
VkInstance a = VK_NULL_HANDLE;
VkFence b = VK_NULL_HANDLE;
}

(DPaste: https://dpaste.dzfl.pl/8f4ce39a907f )

The above is typesafe, and can easily be made compatible with a 
typical C API, since C does no parameter-related name mangling.


Re: Enum that can be 0 or null

2016-05-20 Thread tsbockman via Digitalmars-d-learn

On Saturday, 21 May 2016 at 01:53:21 UTC, Mike Parker wrote:
When binding to a C library, it's desirable to have as close to 
the original C API as possible so that you *can* drop C 
snippets and examples into D code and have them just work. 
Obviously, 100% compatibility is not possible, but it is 
possible to get pretty close most of the time.


The reason that VK_NULL_HANDLE cannot (currently) be directly 
implemented in D it is not type safe.


D's type safety is usually considered to be a positive selling 
point for the language; that's what I mean when I say that "you 
aren't *supposed* to be able to just copy-paste any random C 
snippet into D".


Re: Enum that can be 0 or null

2016-05-20 Thread Alex Parrill via Digitalmars-d-learn

On Saturday, 21 May 2016 at 02:04:23 UTC, Mike Parker wrote:

On Saturday, 21 May 2016 at 01:09:42 UTC, Alex Parrill wrote:



Looks like my best bet is to mark it as deprecated and point 
them to Vk(Type).init instead.


I would prefer to do something like this:

enum VK_NULL_HANDLE_0 = 0;
enum VK_NULL_HANDLE_PTR = null;

Then document it clearly. Alias VK_NULL_HANDLE to one of them 
and keep it deprecated forever. Many users are not going to 
read the documentation on their own initiative, so the 
deprecation message telling them how to solve the problem will 
save you from responding to the same issue again and again and 
again.


Hm, I could do `VK_NULL_DISPATCHABLE_HANDLE = null` for the types 
that are always pointers and `VK_NULL_NONDISPATCHABLE_HANDLE = 
null ? IS_64BIT : 0` for types that are either pointers are 
integers depending on arch, but those names are a bit long. Your 
specific example wouldn't work.


Re: Enum that can be 0 or null

2016-05-20 Thread Mike Parker via Digitalmars-d-learn

On Saturday, 21 May 2016 at 01:09:42 UTC, Alex Parrill wrote:



Looks like my best bet is to mark it as deprecated and point 
them to Vk(Type).init instead.


I would prefer to do something like this:

enum VK_NULL_HANDLE_0 = 0;
enum VK_NULL_HANDLE_PTR = null;

Then document it clearly. Alias VK_NULL_HANDLE to one of them and 
keep it deprecated forever. Many users are not going to read the 
documentation on their own initiative, so the deprecation message 
telling them how to solve the problem will save you from 
responding to the same issue again and again and again.


Re: Enum that can be 0 or null

2016-05-20 Thread Mike Parker via Digitalmars-d-learn

On Friday, 20 May 2016 at 22:10:51 UTC, tsbockman wrote:



Just use null for pointer types, and 0 for integers. D is not 
C; you aren't *supposed* to be able to just copy-paste any 
random C snippet into D and expect it to work without 
modification.


If that's not a satisfactory answer, please show some specific 
examples of code that you don't know how to make work without 
VK_NULL_HANDLE so that I can propose a workaround.


When binding to a C library, it's desirable to have as close to 
the original C API as possible so that you *can* drop C snippets 
and examples into D code and have them just work. Obviously, 100% 
compatibility is not possible, but it is possible to get pretty 
close most of the time.


Re: Enum that can be 0 or null

2016-05-20 Thread Alex Parrill via Digitalmars-d-learn

On Friday, 20 May 2016 at 22:10:51 UTC, tsbockman wrote:

Why do you need to?

Just use null for pointer types, and 0 for integers. D is not 
C; you aren't *supposed* to be able to just copy-paste any 
random C snippet into D and expect it to work without 
modification.


If that's not a satisfactory answer, please show some specific 
examples of code that you don't know how to make work without 
VK_NULL_HANDLE so that I can propose a workaround.


Because, as I mentioned in the OP, for VK_NULL_HANDLE to work 
like it does in C on 32-bit systems, it needs to be compatible 
with both pointer types (VkDevice, VkInstance, etc) and 64-bit 
integer types (VkFence, VkSemaphore, many others).


There is of course a workaround: since VK_NULL_HANDLE is always 
zero/null, Vk(Type).init will work as a replacement as long as 
you match up the types. But then people will try to use 
VK_NULL_HANDLE (as every C or C++ Vulkan tutorial or reference 
will instruct) and find out that either a) it doesn't work or b) 
it works fine on their 64 bit development system, but then cause 
a ton of errors when they try to compile their project for a 
32-bit system.


Looks like my best bet is to mark it as deprecated and point them 
to Vk(Type).init instead.


Re: Enum that can be 0 or null

2016-05-20 Thread tsbockman via Digitalmars-d-learn

On Friday, 20 May 2016 at 13:39:50 UTC, Alex Parrill wrote:
(How) can I make a constant that is either zero or null 
depending on how it is used?


In the general case, I don't think this is possible in D 
currently. (It will become possible if the proposed "multiple 
alias this" ever gets implemented, though: 
http://wiki.dlang.org/DIP66 )


However, various workarounds are possible depending on the 
context.



Anyone have an idea on how to make this work?


Why do you need to?

Just use null for pointer types, and 0 for integers. D is not C; 
you aren't *supposed* to be able to just copy-paste any random C 
snippet into D and expect it to work without modification.


If that's not a satisfactory answer, please show some specific 
examples of code that you don't know how to make work without 
VK_NULL_HANDLE so that I can propose a workaround.