July 08, 2007
This sounds like the perfect place for alias, or something like it.  The idea would be to write code like this:

--------------
version(Windows)
  <do alias declaration here>;
else
  <do other alias delcaration here>;

extern(myAlias) typedef void function() foo;
--------------

Problem is, I haven't yet found a syntax that I like.  I came up with 3 possibilities:

1) alias extern(Windows) extern(myAlias);

I don't like the extern(mine) part, because it reminds me too much of C function pointers.  That was a good example of a nice theoretical syntax that never worked in practice, IMHO.

Plus, this syntax could easily be read as "extern(Windows) attribute on the type extern(mine)..."  Technically, I guess the grammar's not ambiguous, but it's ugly.

2) alias extern(Windows) myAlias;

I don't like how this breaks the parallelism.  Would you use the alias extern(myAlias)?  Or would you drop the extern() part around it?  If the latter, how would you parse it without ambiguities?

Plus, the same problem as before where it looks like extern(Windows) is an attribute on something else.

3) alias Windows myAlias;

I presume that Windows isn't a valid symbol, so this has its own problems.


Thoughts?  About the concept in general, or about a good syntax?

Russ

Walter Bright wrote:
> Bug 1311 http://d.puremagic.com/issues/show_bug.cgi?id=1311
> is about using version declarations to control part of a following declaration (or series of declarations):
> 
> -------------------------
> version(Windows)
>     extern(Windows):
> else
>     extern(C):
> 
> typedef void function() foo;
> --------------------------
> 
> This does not work now, and it was a bug that it ever did appear to work. The issue is that version declarations can only affect entire declarations, not parts of them. An extern statement with a : is implicitly the same as:
> 
> ----------------
> extern(Windows):
> int a;
> int b;
> -----is same as---
> extern(Windows)
> {
>    int a;
>    int b;
> }
> -----------------
> 
> That cannot be split up with a version declaration; it would be like trying to make:
> 
>     version (Windows)
>         int
>     else
>         long
>     x;
> 
> work. The old behavior of dmd contained a serious (unreported) bug where such constructs would cause forward references to behave unpredictably.
> 
> So, the question is how to get the same effect? The alternatives are:
> 
> 1.
> version(Windows)
> {
>     extern(Windows):
>        typedef void function() foo;
> }
> else
> {
>     extern(C):
>        typedef void function() foo;
> }
> 
> Yes, that means doing a cut & paste on the code in the braces. Not thrilling, but it works.
> 
> 2. Stop using extern(Windows). The Windows calling convention is only necessary when a) calling Win32 API functions (which don't exist on Linux anyway) and b) calling someone else's C code that pointlessly and spuriously uses the Windows calling convention, and cannot be fixed.
> There is no reason in new C/C++ code to ever use the Windows calling convention.
> 
> 3. Create two source files, one for the extern(Windows) and the other for the extern(C). Have your makefile automatically copy one to the other, using sed to edit that one line. Import one under Windows, the other under Linux.
> 
> 4. Wait for the future 2.0 macro feature, which should be able to deal with this nicely:
> 
> macro Foo()
> {
>     typedef void function() foo;
> }
> version(Windows)
> {   extern(Windows): Foo(); }
> else
> {    extern(C): Foo(); }
> 
> 5. Do the same as (4) using string mixins:
> 
> const string Foo =
> "
>     typedef void function() foo;
> ";
> version(Windows)
> {   extern(Windows): mixin(Foo); }
> else
> {    extern(C): mixin(Foo); }
> 
> 
> 6. Use template mixins:
> 
> template Foo()
> {
>     typedef void function() foo;
> }
> version(Windows)
> {   extern(Windows): mixin Foo; }
> else
> {    extern(C): mixin Foo; }
July 08, 2007
Russell Lewis wrote:
> This sounds like the perfect place for alias, or something like it.  The idea would be to write code like this:
> 

(...)

> 
> 2) alias extern(Windows) myAlias;
> 
> I don't like how this breaks the parallelism.  Would you use the alias extern(myAlias)?  Or would you drop the extern() part around it?  If the latter, how would you parse it without ambiguities?
> 
> Plus, the same problem as before where it looks like extern(Windows) is an attribute on something else.

This is exactly what I thought while reading the OP. Maybe it would be clearer if the scope syntax is reused for alias:

version (Windows)
	alias(extern) Windows MyAlias;
else
	alias(extern) C MyAlias;

extern(MyAlias):

void foo();
void bar();

...
July 08, 2007
Reply to Russell,

> This sounds like the perfect place for alias, or something like it.
> The idea would be to write code like this:
> 
> --------------
> version(Windows)
> <do alias declaration here>;
> else
> <do other alias delcaration here>;
> extern(myAlias) typedef void function() foo;
> --------------
> Problem is, I haven't yet found a syntax that I like.  I came up with
> 3 possibilities:
> 
> 1) alias extern(Windows) extern(myAlias);
> 

how about alow extern to take a string?

const char[] type = "Windows";

extern(type);


July 09, 2007
Walter Bright wrote:
> Bug 1311 http://d.puremagic.com/issues/show_bug.cgi?id=1311
> is about using version declarations to control part of a following declaration (or series of declarations):
> 
> -------------------------
> version(Windows)
>     extern(Windows):
> else
>     extern(C):
> 
> typedef void function() foo;
> --------------------------
> 
> This does not work now, and it was a bug that it ever did appear to work. The issue is that version declarations can only affect entire declarations, not parts of them. An extern statement with a : is implicitly the same as:
> 
> ----------------
> extern(Windows):
> int a;
> int b;
> -----is same as---
> extern(Windows)
> {
>    int a;
>    int b;
> }
> -----------------
> 
> That cannot be split up with a version declaration; it would be like trying to make:
> 
>     version (Windows)
>         int
>     else
>         long
>     x;
> 
> work. The old behavior of dmd contained a serious (unreported) bug where such constructs would cause forward references to behave unpredictably.
> 
> So, the question is how to get the same effect? The alternatives are:
> 
> 1.
> version(Windows)
> {
>     extern(Windows):
>        typedef void function() foo;
> }
> else
> {
>     extern(C):
>        typedef void function() foo;
> }
> 
> Yes, that means doing a cut & paste on the code in the braces. Not thrilling, but it works.
> 
> 2. Stop using extern(Windows). The Windows calling convention is only necessary when a) calling Win32 API functions (which don't exist on Linux anyway) and b) calling someone else's C code that pointlessly and spuriously uses the Windows calling convention, and cannot be fixed.
> There is no reason in new C/C++ code to ever use the Windows calling convention.

Unfortunately (b) is extremely common, including on some significant libraries.
(eg, MySQL).
We really need a solution to this.
July 09, 2007
Walter Bright wrote:
> Bug 1311 http://d.puremagic.com/issues/show_bug.cgi?id=1311
> is about using version declarations to control part of a following declaration (or series of declarations):
> 
> -------------------------
> version(Windows)
>     extern(Windows):
> else
>     extern(C):
> 
> typedef void function() foo;
> --------------------------
> 
> This does not work now, and it was a bug that it ever did appear to work. The issue is that version declarations can only affect entire declarations, not parts of them. An extern statement with a : is implicitly the same as:
> 
> ----------------
> extern(Windows):
> int a;
> int b;
> -----is same as---
> extern(Windows)
> {
>    int a;
>    int b;
> }
> -----------------
> 
> That cannot be split up with a version declaration;


Why not

  extern(ecc) void function() foo;

where ecc would resolve to Windows or C.

This of course requires some tweaking of the compiler, but it might be worth it.
July 09, 2007
Walter Bright wrote:
> Mike Wey wrote:
>> Should this work?
>>
>> version(Windows)
>> {   const char[] external = "extern(Windows):"; }
>> else
>> {   const char[] external = "extern(C):"; }
>>
>> mixin(external);
>> typedef void function() foo;
> 
> No, it doesn't work (although it compiles).

That seems like it should work.  Is the problem something to do with the order in which things are evaluated at compile-time?


Sean
July 09, 2007
I guess that:

mixin("extern(C):");
typedef void function() foo;

is the same as:

extern(C){}
typedef void function() foo;

Sean Kelly wrote:
> Walter Bright wrote:
>> Mike Wey wrote:
>>> Should this work?
>>>
>>> version(Windows)
>>> {   const char[] external = "extern(Windows):"; }
>>> else
>>> {   const char[] external = "extern(C):"; }
>>>
>>> mixin(external);
>>> typedef void function() foo;
>>
>> No, it doesn't work (although it compiles).
> 
> That seems like it should work.  Is the problem something to do with the order in which things are evaluated at compile-time?
> 
> 
> Sean
July 09, 2007
Sean Kelly wrote:
> That seems like it should work.  Is the problem something to do with the order in which things are evaluated at compile-time?

It doesn't work because mixin is supposed to be a complete statement, not part of one. The XXX: forms a prefix, not a complete statement.
July 09, 2007
Don Clugston wrote:
> Unfortunately (b) is extremely common, including on some significant libraries.
> (eg, MySQL).

I know. I was just hoping to head off *new* code being written that way.

> We really need a solution to this.

I proposed several, they should work.
July 09, 2007
Georg Wrede wrote:
> Why not
> 
>   extern(ecc) void function() foo;
> 
> where ecc would resolve to Windows or C.
> 
> This of course requires some tweaking of the compiler, but it might be worth it.

Do you mean "ecc" being a magic identifier that the compiler sets to Windows on Windows, and C otherwise? That might be a pretty good idea. Why "ecc", though? It doesn't jump out at me what it might mean.

How about "System" ?