supporting DMD-1.016 and DMD-2.000 with the same source code
Walter Bright
newshound1 at digitalmars.com
Mon Jun 18 11:48:23 PDT 2007
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.
More information about the Digitalmars-d
mailing list