www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Defining a version after it's tested for

reply Robert Clipsham <robert octarineparrot.com> writes:
I recently came across this:

version( BackendFoo ) {}
else version( BackendBar ) {}
else version( BackendCar ) {}
else
{
   pragma( msg, "Warning: backend version undefined" );
   pragma( msg, "Attempting to guess backend" );
   version( Windows )
   {
     version = BackendFoo;
     pragma( msg, "Selected the Foo backend." );
   }
   else version(...)
   { /* You get the idea */ }
}

However, when trying to compile I get the following error:

Error: version BackendFoo defined after use

What is the reasoning behind this? It could be extremely useful to have 
this functionality. The only reason I can think of for doing this is 
that this code could be evaluated after modules that depend on the 
version being defined, causing it not to work. Surely there would be a 
way around that?

If it's not possible to fix this, what way would you recommend I get 
around this? The only idea I've come up with so far is to do:

else
{
   static assert( false, "Please compile with 
-version=Backend(Foo|Bar|Bar)" );
}

Which is less than optimal.
May 21 2009
next sibling parent "Tim Matthews" <tim.matthews7 gmail.com> writes:
On Fri, 22 May 2009 02:45:24 +1200, Robert Clipsham  
<robert octarineparrot.com> wrote:


 If it's not possible to fix this, what way would you recommend I get  
 around this?
I think versions are powerfull enough so I created a wrapper around which makes best use of static asserts (attached) I think the reason behind this is to discourage version usage.
May 21 2009
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 21 May 2009 10:45:24 -0400, Robert Clipsham  
<robert octarineparrot.com> wrote:

 I recently came across this:

 version( BackendFoo ) {}
 else version( BackendBar ) {}
 else version( BackendCar ) {}
 else
 {
    pragma( msg, "Warning: backend version undefined" );
    pragma( msg, "Attempting to guess backend" );
    version( Windows )
    {
      version = BackendFoo;
      pragma( msg, "Selected the Foo backend." );
    }
    else version(...)
    { /* You get the idea */ }
 }

 However, when trying to compile I get the following error:

 Error: version BackendFoo defined after use

 What is the reasoning behind this? It could be extremely useful to have  
 this functionality. The only reason I can think of for doing this is  
 that this code could be evaluated after modules that depend on the  
 version being defined, causing it not to work. Surely there would be a  
 way around that?

 If it's not possible to fix this, what way would you recommend I get  
 around this? The only idea I've come up with so far is to do:

 else
 {
    static assert( false, "Please compile with  
 -version=Backend(Foo|Bar|Bar)" );
 }

 Which is less than optimal.
Versions are intended to be predefined before usage. It's the same thing as using a variable before it's defined. The rational is, to flag errors to the user where he thinks forward referencing of versions works. Unfortunately, you have to do the following workaround: version(BackendFoo) { version=BackendFoo_;} else version(BackendBar) { version=BackendBar_;} else version(BackendCar) { version=BackendCar_;} else { version(Windows) {version=BackendFoo_;} } And now, you must use Backend*_ in your code. It should work, but it's ugly. Maybe Walter has a better method. -Steve
May 21 2009
parent reply Robert Clipsham <robert octarineparrot.com> writes:
Steven Schveighoffer wrote:
 Versions are intended to be predefined before usage.  It's the same 
 thing as using a variable before it's defined.  The rational is, to flag 
 errors to the user where he thinks forward referencing of versions works.
 
 Unfortunately, you have to do the following workaround:
 
 version(BackendFoo) { version=BackendFoo_;}
 else version(BackendBar) { version=BackendBar_;}
 else version(BackendCar) { version=BackendCar_;}
 else
 {
   version(Windows) {version=BackendFoo_;}
 }
 
 And now, you must use Backend*_ in your code.  It should work, but it's 
 ugly.
 
 Maybe Walter has a better method.
 
 -Steve
Unfortunately I thought this might be the case. Thanks.
May 21 2009
parent reply "Tim Matthews" <tim.matthews7 gmail.com> writes:
On Fri, 22 May 2009 07:54:07 +1200, Robert Clipsham
<robert octarineparrot.com> wrote:

 Steven Schveighoffer wrote:
 Versions are intended to be predefined before usage.  It's the same  
 thing as using a variable before it's defined.  The rational is, to  
 flag errors to the user where he thinks forward referencing of versions  
 works.
  Unfortunately, you have to do the following workaround:
  version(BackendFoo) { version=BackendFoo_;}
 else version(BackendBar) { version=BackendBar_;}
 else version(BackendCar) { version=BackendCar_;}
 else
 {
   version(Windows) {version=BackendFoo_;}
 }
  And now, you must use Backend*_ in your code.  It should work, but  
 it's ugly.
  Maybe Walter has a better method.
  -Steve
Unfortunately I thought this might be the case. Thanks.
I think this would be less ugly: template vers(char[] V) { mixin("version(" ~ V ~ ") { const bool vers = true; } else { const bool vers = false; }"); } static if(vers!("BackendFoo") || vers!("Windows")) { // } else static if(vers!("BackendBar")) { // } else static if (vers!("BackendCar")) { // } else { // } I would prefer the normal version statement to work like that directly though.
May 21 2009
parent reply Robert Clipsham <robert octarineparrot.com> writes:
Tim Matthews wrote:
 
 I think this would be less ugly:
 
 template vers(char[] V)
 {
      mixin("version(" ~ V ~ ")
      {
            const bool vers = true;
      }
      else
      {
            const bool vers = false;
      }");
 }
 
 static if(vers!("BackendFoo") || vers!("Windows"))
 {
       //
 }
 else static if(vers!("BackendBar"))
 {
      //
 }
 else static if (vers!("BackendCar"))
 {
     //
 }
 else
 {
     //
 }
 
 I would prefer the normal version statement to work like that directly 
 though.
This still doesn't solve my problem though, all it does is remove the usage of the version statement, which seems... pointless :S
May 22 2009
parent reply "Tim Matthews" <tim.matthews7 gmail.com> writes:
On Fri, 22 May 2009 20:29:03 +1200, Robert Clipsham  
<robert octarineparrot.com> wrote:

 Tim Matthews wrote:
  I think this would be less ugly:
  template vers(char[] V)
 {
      mixin("version(" ~ V ~ ")
      {
            const bool vers = true;
      }
      else
      {
            const bool vers = false;
      }");
 }
  static if(vers!("BackendFoo") || vers!("Windows"))
 {
       //
 }
 else static if(vers!("BackendBar"))
 {
      //
 }
 else static if (vers!("BackendCar"))
 {
     //
 }
 else
 {
     //
 }
  I would prefer the normal version statement to work like that directly  
 though.
This still doesn't solve my problem though, all it does is remove the usage of the version statement, which seems... pointless :S
From what can I see you have a few different posssible versions but when no version is defined you can select a default version based on other stuff like windows operating system. Rather than modify the versions or add aditional to match the system you can create complex 'static if' statements which also are a compile time feature but can have other static ifs and logical comparisons like '&&' and '||'. When you have put the right checks in you can match your select target systems all within a single static if.
May 22 2009
parent Robert Clipsham <robert octarineparrot.com> writes:
Tim Matthews wrote:
  From what can I see you have a few different posssible versions but 
 when no version is defined you can select a default version based on 
 other stuff like windows operating system. Rather than modify the 
 versions or add aditional to match the system you can create complex 
 'static if' statements which also are a compile time feature but can 
 have other static ifs and logical comparisons like '&&' and '||'. When 
 you have put the right checks in you can match your select target 
 systems all within a single static if.
Ah, I see what you mean now, you don't mean to use this on its own, but rather use it along with other tests, so rather than using a version identifier it would resolve to something internally which could be tested in a static if... this would work nicely actually, thanks!
May 22 2009
prev sibling next sibling parent Don <nospam nospam.com> writes:
Robert Clipsham wrote:
 I recently came across this:
 
 version( BackendFoo ) {}
 else version( BackendBar ) {}
 else version( BackendCar ) {}
 else
 {
   pragma( msg, "Warning: backend version undefined" );
   pragma( msg, "Attempting to guess backend" );
   version( Windows )
   {
     version = BackendFoo;
     pragma( msg, "Selected the Foo backend." );
   }
   else version(...)
   { /* You get the idea */ }
 }
 
 However, when trying to compile I get the following error:
 
 Error: version BackendFoo defined after use
 
 What is the reasoning behind this? It could be extremely useful to have 
 this functionality. The only reason I can think of for doing this is 
 that this code could be evaluated after modules that depend on the 
 version being defined, causing it not to work. Surely there would be a 
 way around that?
Versions are like in functional programming, they are NOT variables. Once you've tested the existence of a non-existent version identifier, you've implicitly declared it. When there was a discussion about 'version' some time back, I made a proposal which (among other things) would require you to explicitly state that a particular version identifier is set from the command line; that would make this case clearer.
May 22 2009
prev sibling parent reply Jason House <jason.house gmail.com> writes:
Robert Clipsham Wrote:

 I recently came across this:
 
 version( BackendFoo ) {}
 else version( BackendBar ) {}
 else version( BackendCar ) {}
 else
 {
    pragma( msg, "Warning: backend version undefined" );
    pragma( msg, "Attempting to guess backend" );
    version( Windows )
    {
      version = BackendFoo;
      pragma( msg, "Selected the Foo backend." );
    }
    else version(...)
    { /* You get the idea */ }
 }
 
 However, when trying to compile I get the following error:
 
 Error: version BackendFoo defined after use
 
 What is the reasoning behind this? It could be extremely useful to have 
 this functionality. The only reason I can think of for doing this is 
 that this code could be evaluated after modules that depend on the 
 version being defined, causing it not to work. Surely there would be a 
 way around that?
 
 If it's not possible to fix this, what way would you recommend I get 
 around this? The only idea I've come up with so far is to do:
 
 else
 {
    static assert( false, "Please compile with 
 -version=Backend(Foo|Bar|Bar)" );
 }
 
 Which is less than optimal.
I wonder if a compiler patch to loosen the restrictions would be accepted. Something like what you tried should be trivial to support.
May 22 2009
parent Robert Clipsham <robert octarineparrot.com> writes:
Jason House wrote:
 I wonder if a compiler patch to loosen the restrictions would be accepted.
Something like what you tried should be trivial to support.
I doubt it's trivial to support... depending on when it's evaluated the version may or may not be set when it's checked, which is likely to cause confusion later on.
May 22 2009