www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - supporting DMD-1.016 and DMD-2.000 with the same source code

reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Below are a few code samples that might help you to make your code
compatible with DMD-1.016 as well as DMD-2.000.


1) What compiler am I running?
==============================

# static if(is(typeof((new char[3]).idup))){
# 	pragma(msg, "DMD version 2");
#   static dmd_version = 2;
# }else{
# 	pragma(msg, "DMD version 1");
#   static dmd_version = 1;
# }

Usually I try to avoid any kind of version detection, however
the class invariant changes (see below) require it this time.
If you are only using Phobos and not alternatives like Tango
the language version can be accessed via:

# import std.compiler : version_major;
# import std.metastrings : ToString;
#
# pragma(msg, "DMD version " ~ ToString!(version_major));
# alias version_major dmd_version;


2) 'string', 'wstring', 'dstring'
=================================

If you defined a 'string' type or alias replace it with myString or
similar. The same is valid for 'wstring' and 'dstring'.


3) Object.toString
==================

In DMD-1 the signature is
	char[] Object.toString();
however in DMD-2 the signature is
	const(char)[] Object.toString();

An ad-hock solution would be:

# class Foo{
#    typeof((new Object()).toString()) toString(){
#       return "abc";
#    }
# }

This solution works reliably but is 'ugly' and doesn't scale
very well. Thus the slightly longer version:

# static if(!is(string)){
#    static if(! is(typeof((new Object()).toString()) string)){
#       alias char[] string;
#    }
# }
#
# class Foo{
#    string toString(){
#       return "abc";
#    }
# }


4) class invariants
===================

This is the only real trouble spot so far. DMD-1 uses
	invariant{ ... assert(...); ... }
however DMD-2 uses
	invariant(){ ... assert(...); ... }

There are basically two approaches. Both require dmd_version from
1) "What compiler am I running?" (see above). First the complete
mixin solution:

# class Foo : Object{
#    int x;
#
#    mixin("invariant" ~ (dmd_version < 2 ? "" : "()") ~
#       "{
#          assert(x < 100);
#       }");
# }

This might be a quick hack however in most cases you are going to
lose nice features like syntax highlighting. Invariants are
prohibited from calling 'public' member function but calling
'private' member functions is OK:

# const char[] invariantCall = "invariant" ~ (dmd_version < 2 ? "" : "()")
#    ~ "{ invariant_(); }";
#
# class Foo : Object{
#    int x;
#
#    mixin(invariantCall);
#
#    private void invariant_(){
#       assert(x < 100);
#    }
# }

5) string functions
===================

Where ever reasonable replace 'char[]' with 'string' (see 3) above).
Due to my general coding style this was basically a search/replace
operation that requires almost no further code changes. In the case of
Flectioned 2 additional ".dup"s were needed.


6) C-strings
============

Sometime I have to interface with C libries this "const char*" is
required:

# static if(1 < dmd_version){
#    mixin("alias const(char)* stringz;");
# }else{
#    alias char* stringz;
# }

The mixin in required because the content has to be syntactically
correct and "const(char)" isn't a valid DMD-1 construct.


7) the 'rest'
=============

Depending on your coding style you might have to deal with 'final'
parameters and 'final' foreach value variables, but in my case 
(3873 lines of cross OS code) not a single change was required.

Thomas

-----BEGIN PGP SIGNATURE-----

iQIVAwUBRnaPP7ZlboUnBhRKAQK46RAAhAOvSpZTtaJ+2OdcLfCkDsJNE/kzQm9A
BK7xVUovXs63uvAGkrOeN5SwRxHhWousdbrYZwAmKrQ9KrEDOZVFON134SEC0IAf
Greg1fYZSXc/g6myWeqGzAXT7OBSQ4EkRTl8lkbTvSO6467ynx88GlATRxsFZ+t6
EHSbqS8M1Gkh3tiXXMQqOBxqmLJujJyS78c4f2pQsvPqYpPgugZsQrpgKseIlH5q
b3v7qji9ACnvZGIMCq5zhrq945J9YvJYQEjqLDs4+SCcgGFzuvLUXTdVlga5MyeI
UmyGDS5fvdDNX35wsKk1St8ZHfxORyI3+FEHeMCxHY5YT1govhkgBqK7suS/Kp6M
ySZsQ9sIpjYwWTIEViflJ9otuY7l/nH1H5OGm2tS+dxDhzLjFw7jCBy/9c0eIxtL
WrXovAv2fVn6MbnkqGs3lBGEj0o518Chc2zHyBQikFUaE8cpdj5PxEP2usnq/WGE
2vQ0fsRUhfnHcV/p9DOyNsQyjBGIBL2BK2sNBDSqkScxVoPE7ZBAHNpsDsQZlUwS
8IlkqAbLPFRJxPBWiR/2dsi6SbM/hg+lfyqOqdzZvNfpICWcXcETab0JEk3WODb0
7EpT9F6CDLpWBvOhxtb/rzTkPpjWdpYg0Q2alT4CgnwjdrYDH1btSxYCPmm/OL23
qi8DHAD+X0o=
=fZxN
-----END PGP SIGNATURE-----
Jun 18 2007
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
Great tips thank you. These deserve a place on a website and a link from 
digitalmars imho.
Jun 18 2007
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Thomas Kuehne wrote:
 
 4) class invariants
 ===================
 
 This is the only real trouble spot so far. DMD-1 uses
 	invariant{ ... assert(...); ... }
 however DMD-2 uses
 	invariant(){ ... assert(...); ... }

Well that's unfortunate. I don't suppose unittest has gotten parenthesis as well? Sean
Jun 18 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Sean Kelly wrote:
 Thomas Kuehne wrote:
 4) class invariants
 ===================

 This is the only real trouble spot so far. DMD-1 uses
     invariant{ ... assert(...); ... }
 however DMD-2 uses
     invariant(){ ... assert(...); ... }

Well that's unfortunate. I don't suppose unittest has gotten parenthesis as well? Sean

I suspect this is because invariant is now a declaration, a storage class *and* a type constructor. -- Daniel
Jun 18 2007
next sibling parent Sean Kelly <sean f4.ca> writes:
Daniel Keep wrote:
 
 Sean Kelly wrote:
 Thomas Kuehne wrote:
 4) class invariants
 ===================

 This is the only real trouble spot so far. DMD-1 uses
     invariant{ ... assert(...); ... }
 however DMD-2 uses
     invariant(){ ... assert(...); ... }

parenthesis as well?

I suspect this is because invariant is now a declaration, a storage class *and* a type constructor.

Well sure. But adding parens breaks consistency with other similar blocks. Sean
Jun 18 2007
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Daniel Keep wrote:
 I suspect this is because invariant is now a declaration, a storage
 class *and* a type constructor.

It's a dessert topping *and* a floor wax! http://www.jibjab.com/view/101069#
Jun 18 2007
prev sibling next sibling parent Henning Hasemann <hhasemann web.de> writes:
Am Mon, 18 Jun 2007 07:57:05 -0700
schrieb Sean Kelly <sean f4.ca>:

 Well sure.  But adding parens breaks consistency with other similar
 blocks.

What I find more confusing is the "overloading" of keywords with different meanings or even worse *similar* meanings, especially for programmers that down "grow with the language" like most readers of this NG but will start using it at some point in the future. They have to learn a lot of things in order to use a keyword correctly. Henning -- GPG Public Key: http://keyserver.ganneff.de:11371/pks/lookup?op=get&search=0xDDD6D36D41911851 Fingerprint: 344F 4072 F038 BB9E B35D E6AB DDD6 D36D 4191 1851
Jun 18 2007
prev sibling next sibling parent Carlos Santander <csantander619 gmail.com> writes:
Thomas Kuehne escribió:
 4) class invariants
 ===================
 
 This is the only real trouble spot so far. DMD-1 uses
 	invariant{ ... assert(...); ... }
 however DMD-2 uses
 	invariant(){ ... assert(...); ... }
 
 There are basically two approaches. Both require dmd_version from
 1) "What compiler am I running?" (see above). First the complete
 mixin solution:
 
 # class Foo : Object{
 #    int x;
 #
 #    mixin("invariant" ~ (dmd_version < 2 ? "" : "()") ~
 #       "{
 #          assert(x < 100);
 #       }");
 # }
 
 This might be a quick hack however in most cases you are going to
 lose nice features like syntax highlighting. Invariants are
 prohibited from calling 'public' member function but calling
 'private' member functions is OK:
 
 # const char[] invariantCall = "invariant" ~ (dmd_version < 2 ? "" : "()")
 #    ~ "{ invariant_(); }";
 #
 # class Foo : Object{
 #    int x;
 #
 #    mixin(invariantCall);
 #
 #    private void invariant_(){
 #       assert(x < 100);
 #    }
 # }
 

To avoid this ugly hack, how about supporting invariant(){} in Dv1? -- Carlos Santander Bernal
Jun 18 2007
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Thomas Kuehne wrote:
 Below are a few code samples that might help you to make your code
 compatible with DMD-1.016 as well as DMD-2.000.
 
 
 1) What compiler am I running?
 ==============================
 
 # static if(is(typeof((new char[3]).idup))){
 # 	pragma(msg, "DMD version 2");
 #   static dmd_version = 2;
 # }else{
 # 	pragma(msg, "DMD version 1");
 #   static dmd_version = 1;
 # }

It's obvious I need to put together a predefined compiler version.
 If you are only using Phobos and not alternatives like Tango
 the language version can be accessed via:
 
 # import std.compiler : version_major;
 # import std.metastrings : ToString;
 #
 # pragma(msg, "DMD version " ~ ToString!(version_major));
 # alias version_major dmd_version;
 
 
 2) 'string', 'wstring', 'dstring'
 =================================
 
 If you defined a 'string' type or alias replace it with myString or
 similar. The same is valid for 'wstring' and 'dstring'.
 
 
 3) Object.toString
 ==================
 
 In DMD-1 the signature is
 	char[] Object.toString();
 however in DMD-2 the signature is
 	const(char)[] Object.toString();
 
 An ad-hock solution would be:
 
 # class Foo{
 #    typeof((new Object()).toString()) toString(){
 #       return "abc";
 #    }
 # }
 
 This solution works reliably but is 'ugly' and doesn't scale
 very well. Thus the slightly longer version:
 
 # static if(!is(string)){
 #    static if(! is(typeof((new Object()).toString()) string)){
 #       alias char[] string;
 #    }
 # }
 #
 # class Foo{
 #    string toString(){
 #       return "abc";
 #    }
 # }

This is why I put the string aliases into dmd 1.016. Then, just replace the char[] with string, and it'll work with both 1.0 and 2.0.
 
 4) class invariants
 ===================
 
 This is the only real trouble spot so far. DMD-1 uses
 	invariant{ ... assert(...); ... }
 however DMD-2 uses
 	invariant(){ ... assert(...); ... }

I fixed the 1.015 compiler to accept the () as being optional. So, use the () for both, and it should work.
 
 There are basically two approaches. Both require dmd_version from
 1) "What compiler am I running?" (see above). First the complete
 mixin solution:
 
 # class Foo : Object{
 #    int x;
 #
 #    mixin("invariant" ~ (dmd_version < 2 ? "" : "()") ~
 #       "{
 #          assert(x < 100);
 #       }");
 # }
 
 This might be a quick hack however in most cases you are going to
 lose nice features like syntax highlighting. Invariants are
 prohibited from calling 'public' member function but calling
 'private' member functions is OK:
 
 # const char[] invariantCall = "invariant" ~ (dmd_version < 2 ? "" : "()")
 #    ~ "{ invariant_(); }";
 #
 # class Foo : Object{
 #    int x;
 #
 #    mixin(invariantCall);
 #
 #    private void invariant_(){
 #       assert(x < 100);
 #    }
 # }
 
 5) string functions
 ===================
 
 Where ever reasonable replace 'char[]' with 'string' (see 3) above).
 Due to my general coding style this was basically a search/replace
 operation that requires almost no further code changes. In the case of
 Flectioned 2 additional ".dup"s were needed.

I find that doing a mechanical global search/replace of char[] with string will successfully convert 95+% of the code, with a little touchup here and there.
 
 
 6) C-strings
 ============
 
 Sometime I have to interface with C libries this "const char*" is
 required:
 
 # static if(1 < dmd_version){
 #    mixin("alias const(char)* stringz;");
 # }else{
 #    alias char* stringz;
 # }
 
 The mixin in required because the content has to be syntactically
 correct and "const(char)" isn't a valid DMD-1 construct.

Hmm, I like the stringz alias. Or maybe cstring?
 
 
 7) the 'rest'
 =============
 
 Depending on your coding style you might have to deal with 'final'
 parameters and 'final' foreach value variables, but in my case 
 (3873 lines of cross OS code) not a single change was required.

Jun 18 2007
parent Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Walter Bright schrieb am 2007-06-18:
 Thomas Kuehne wrote:
 Below are a few code samples that might help you to make your code
 compatible with DMD-1.016 as well as DMD-2.000.


[...]
 This is why I put the string aliases into dmd 1.016. Then, just replace 
 the char[] with string, and it'll work with both 1.0 and 2.0.

[...]
 I fixed the 1.015 compiler to accept the () as being optional. So, use 
 the () for both, and it should work.

The main problem is that both changes aren't yet incorporated into GDC and unlike GDC DMD can't generate 64bit code. Thomas -----BEGIN PGP SIGNATURE----- iQIVAwUBRneF17ZlboUnBhRKAQJa9Q//Ubhl+WwZcJ5sdcoNhwM6bLZo7Mebc2Po T4S0LWHAwsDQoHlwMaz4iQpuFxThm/EIED90fMZMuRdGb9c4iNsfhIqS6i0SjRTK 2GKSHQFt2dTZHxYdJ8H4l7n32BZssnUXuAKDG0k4O72roCrbZutECIXnFxlwtbcy pP/7poSU/Peuh+Ap5YxuGea3idhUBFSUXmweL6ZruJtIv6OhayVIa0DDkcgds2Wz csYTpBQlN+FhOkZLCF7fhh3uPgQUp7yk4w7R/0rhpuTCGRY2vX2Ffgr5A6ObQWu/ 2dRlAEFnFbE0V3eDq/ps9WlfrVippDcPRic18EnHJH4l9PG5bL4ApvcbVhKXWoUp UBqgd5qFMaVnnOG5GTPbNKD8nUFwY20JsJ4yn/hhpAWByMm97n/O+xAJ1Nyc+9CR Dc77iQw5ggSJBQbeMhR4PKrNysITJ0ub2lOC5Hr+VV+6jAkwsdmfDNqZWOe8gfX/ e4UHotOSbWxyqzB5/sVlZ9t/ZXCwYAIENnxTujsqr4su0NUCcKt385t0q7a7KAOE KfCxiAf5jZJSQ3VH1IrmFxxHn5mZU5Q6+XLJ1XTrI3vgJWIlQeG3nTZOi6jBhHWY OIj+A0OrzzYBx3QuThkJQKEmdYmqFbsbUuHhUYO5jMGHJs4P66VnV4x+BkntrNI4 sxaytxsl3TQ= =fcLc -----END PGP SIGNATURE-----
Jun 18 2007
prev sibling next sibling parent reply Georg Wrede <georg nospam.org> writes:
Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 -----BEGIN PGP SIGNATURE-----
 -----END PGP SIGNATURE-----

<snip lots of amazing D future info> I hope I'm not the only one who's looking at this in amazement. Have I grossly skipped something fundamentally obvious in this NG, or is it that some info about future improvements are distributed through channels other than this NG?
Jun 18 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Georg Wrede wrote:
 Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 -----BEGIN PGP SIGNATURE-----
 -----END PGP SIGNATURE-----

<snip lots of amazing D future info> I hope I'm not the only one who's looking at this in amazement. Have I grossly skipped something fundamentally obvious in this NG, or is it that some info about future improvements are distributed through channels other than this NG?

Aside from this NG there is the digitalmars.D.announce NG. Did you miss the announcement of D2.0 over there? Nothing mysterious here. I think Thomas just got busy figuring out how D2.0 works the minute Walter uploaded it. --bb
Jun 18 2007
parent Georg Wrede <georg nospam.org> writes:
Bill Baxter wrote:
 Georg Wrede wrote:
 Thomas Kuehne wrote:

 -----BEGIN PGP SIGNED MESSAGE-----
 -----BEGIN PGP SIGNATURE-----
 -----END PGP SIGNATURE-----

<snip lots of amazing D future info> I hope I'm not the only one who's looking at this in amazement. Have I grossly skipped something fundamentally obvious in this NG, or is it that some info about future improvements are distributed through channels other than this NG?

Aside from this NG there is the digitalmars.D.announce NG. Did you miss the announcement of D2.0 over there? Nothing mysterious here. I think Thomas just got busy figuring out how D2.0 works the minute Walter uploaded it.

Heh, after two days of nothing new in D.announce, i blink, and pow! it's full of breathtaking news. Sigh. PS, Congrats to Walter!
Jun 18 2007
prev sibling parent torhu <fake address.dude> writes:
Thomas Kuehne wrote:
 6) C-strings
 ============
 
 Sometime I have to interface with C libries this "const char*" is
 required:
 
 # static if(1 < dmd_version){
 #    mixin("alias const(char)* stringz;");
 # }else{
 #    alias char* stringz;
 # }
 
 The mixin in required because the content has to be syntactically
 correct and "const(char)" isn't a valid DMD-1 construct.

Is there any reason not to use 'in' instead? stringz looks a bit alien in C prototypes. Phobos does just that, so I suppose it's okay: char* strcpy(char* s1, in char* s2);
Jul 01 2007