Introspection: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added a solution in Ada.)
(Added Java)
Line 7: Line 7:
=={{header|Ada}}==
=={{header|Ada}}==
Ada doesn't allow you to ask about compiler versions, but you can query specific parameters of the target, such as the range of the standard integer type, or the precision of the standard floating point type:
Ada doesn't allow you to ask about compiler versions, but you can query specific parameters of the target, such as the range of the standard integer type, or the precision of the standard floating point type:
'''with''' Ada.Integer_Text_IO, Ada.Text_IO;
<ada>with Ada.Integer_Text_IO, Ada.Text_IO;
'''procedure''' Introspection '''is'''
procedure Introspection is
'''use''' Ada.Integer_Text_IO, Ada.Text_IO;
use Ada.Integer_Text_IO, Ada.Text_IO;
'''begin'''
begin
Put ("Integer range: ");
Put ("Integer range: ");
Put (Integer'First);
Put (Integer'First);
Line 20: Line 20:
Put (Float'Digits);
Put (Float'Digits);
New_Line;
New_Line;
'''end''' Introspection;
end Introspection;</ada>



=={{header|C}}==
=={{header|C}}==
Line 27: Line 26:


{{works with|C|94 and later}}
{{works with|C|94 and later}}
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
<c>#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
#pragma error("C compiler must adhere to at least C99 for the following code.")
#pragma error("C compiler must adhere to at least C99 for the following code.")
#else
#else
/* rest of file */
/* rest of file */
#endif
#endif</c>


However, there is no facility in C for checking whether individual variables and functions have been declared. In open source, the GNU [[autotools]] are often used for this purpose, doing this kind of check in a shell script and defining symbols such as __HAVE_ABS__ which ''can'' be checked by the preprocessor.
However, there is no facility in C for checking whether individual variables and functions have been declared. In open source, the GNU [[autotools]] are often used for this purpose, doing this kind of check in a shell script and defining symbols such as __HAVE_ABS__ which ''can'' be checked by the preprocessor.
Line 39: Line 38:
The DMD compiler has macros defined for the version, more easily accessible through std.compiler:
The DMD compiler has macros defined for the version, more easily accessible through std.compiler:


import std.compiler;
<d>import std.compiler;
static if (version_major < 2 || version_minor > 7) {
static if (version_major < 2 || version_minor > 7) {
// this prevents further compilation
// this prevents further compilation
static assert (false, "I can't cope with this compiler version");
static assert (false, "I can't cope with this compiler version");
}
}</d>


To check if something compiles or not:
To check if something compiles or not:


version(D_Version2) {
<d>version(D_Version2) {
static if( __traits(compiles,abs(bloop)) ) {
static if( __traits(compiles,abs(bloop)) ) {
Line 56: Line 55:
}
}
} else static assert(0, "Requires D version 2");
} else static assert(0, "Requires D version 2");</d>


Note that this checks that bloop is of a type which abs() accepts. It is generic code; if the type of abs() changes, so will the return type of the function. The test can also be written so that it will work on D version 1:
Note that this checks that bloop is of a type which abs() accepts. It is generic code; if the type of abs() changes, so will the return type of the function. The test can also be written so that it will work on D version 1:


static if ( is(typeof(abs(bloop))) ) {
<d>static if ( is(typeof(abs(bloop))) ) {
typeof(abs(bloop)) computeAbsBloop() {
typeof(abs(bloop)) computeAbsBloop() {
return abs(bloop);
return abs(bloop);
}
}
}
}</d>


=={{header|E}}==
=={{header|E}}==
Line 87: Line 86:
bloop @ abs
bloop @ abs
[then] [then]
[then] [then]

=={{header|Java}}==
You can't see if a variable or function is available in Java (it will be a compile time error if you try to use them when you they aren't available), but you can check the version number using the <tt>System</tt> class:
<java>public class VersCheck {
public static void main(String[] args) {
String vers = System.getProperty("java.version");
vers = vers.substring(0,vers.indexOf('.')) + "." + //some String fiddling to get the version number into a usable form
vers.substring(vers.indexOf('.')+1,vers.lastIndexOf('.'));
if(Double.parseDouble(vers) >= 1.5){
System.out.println("YAY!");
}else{
System.err.println("Must use Java >=1.5");
}
}
}</java>


=={{header|MAXScript}}==
=={{header|MAXScript}}==
Line 120: Line 134:
=={{header|Perl}}==
=={{header|Perl}}==
{{works with|Perl|5.x}}
{{works with|Perl|5.x}}
require v5.6.1; # run time version check
<perl>require v5.6.1; # run time version check
require 5.6.1; # ditto
require 5.6.1; # ditto
require 5.006_001; # ditto; preferred for backwards compatibility
require 5.006_001; # ditto; preferred for backwards compatibility</perl>
Checking whether a variable exists is kind of daft. Good style dictates that I declare the variables I'm going to use, and then I already know $bloop exists. Checking for the ''value'' of a variable however is something very common.
Checking whether a variable exists is kind of daft. Good style dictates that I declare the variables I'm going to use, and then I already know $bloop exists. Checking for the ''value'' of a variable however is something very common.
defined $bloop;
<perl>defined $bloop;
# returns true if bloop has been filled with something useful
# returns true if bloop has been filled with something useful</perl>
What if 'bloop' is a computed value? Good style forbids that I dereference willy-nilly variables with unknown names, that's what hashes are good for.
What if 'bloop' is a computed value? Good style forbids that I dereference willy-nilly variables with unknown names, that's what hashes are good for.
$computed = 'bloop';
<perl>$computed = 'bloop';
exists $introspect{$computed};
exists $introspect{$computed};
# returns true if the key bloop exists in hash %introspect
# returns true if the key bloop exists in hash %introspect</perl>
But neither you can do this, for example:
But neither you can do this, for example:
#$bloop = -123; # uncomment this line to see the difference
<perl>#$bloop = -123; # uncomment this line to see the difference
if (defined($::{'bloop'})) {print abs(${'bloop'})} else {print "bloop isn't defined"};
if (defined($::{'bloop'})) {print abs(${'bloop'})} else {print "bloop isn't defined"};</perl>
The trick in this example is to use bloop variable by reference ${'bloop'} (otherwise it will be created unconditionally by the compiler). Perl store nametables inside hashes: '::' - for main package and 'xxx::' for package 'xxx'.
The trick in this example is to use bloop variable by reference ${'bloop'} (otherwise it will be created unconditionally by the compiler). Perl store nametables inside hashes: '::' - for main package and 'xxx::' for package 'xxx'.
In Perl, you cannot check for the existence of built-in functions, of which abs() is one. However in practice that's not a problem because most functions live in classes, and those are easily inspectable at runtime.
In Perl, you cannot check for the existence of built-in functions, of which abs() is one. However in practice that's not a problem because most functions live in classes, and those are easily inspectable at runtime.
use UNIVERSAL qw(can);
<perl>use UNIVERSAL qw(can);
use Math::Cephes qw();
use Math::Cephes qw();
print Math::Cephes->fabs($bloop) if can 'Math::Cephes', 'fabs';
print Math::Cephes->fabs($bloop) if can 'Math::Cephes', 'fabs';</perl>


=={{header|Pop11}}==
=={{header|Pop11}}==
Line 170: Line 184:


=={{header|Python}}==
=={{header|Python}}==
# Checking for system version
<python># Checking for system version
import sys
import sys
major, minor, bugfix = sys.version_info[:3]
major, minor, bugfix = sys.version_info[:3]
Line 176: Line 190:
sys.exit('Python 2 is required')
sys.exit('Python 2 is required')
<pre>
def defined(name): # LBYL (Look Before You Leap)
def defined(name): # LBYL (Look Before You Leap)
return name in globals() or name in locals() or name in vars(__builtins__)
return name in globals() or name in locals() or name in vars(__builtins__)
Line 192: Line 206:
if defined2('bloop') and defined2('abs') and callable(abs):
if defined2('bloop') and defined2('abs') and callable(abs):
print abs(bloop)
print abs(bloop)
</pre>
</python>


=={{header|Raven}}==
=={{header|Raven}}==
Line 202: Line 216:


=={{header|Ruby}}==
=={{header|Ruby}}==
exit if RUBY_VERSION < '1.8.6'
<ruby>exit if RUBY_VERSION < '1.8.6'
puts bloop.abs if defined?(bloop) and bloop.respond_to?(:abs)
puts bloop.abs if defined?(bloop) and bloop.respond_to?(:abs)</ruby>


=={{header|Tcl}}==
=={{header|Tcl}}==

Revision as of 03:47, 17 March 2008

Task
Introspection
You are encouraged to solve this task according to the task description, using any language you may know.

This task asks to

  • verify the version/revision of your currently running (compiler/interpreter/byte-compiler/runtime environment/whatever your language uses) and exit if it is too old.
  • check whether the variable "bloop" exists and whether the math-function "abs()" is available and if yes compute abs(bloop).


Ada

Ada doesn't allow you to ask about compiler versions, but you can query specific parameters of the target, such as the range of the standard integer type, or the precision of the standard floating point type: <ada>with Ada.Integer_Text_IO, Ada.Text_IO;

procedure Introspection is
   use Ada.Integer_Text_IO, Ada.Text_IO;
begin
   Put ("Integer range: ");
   Put (Integer'First);
   Put (" .. ");
   Put (Integer'Last);
   New_Line;

   Put ("Float digits: ");
   Put (Float'Digits);
   New_Line;
end Introspection;</ada>

C

Determining the make and version of the compiler, C standard, and environment features is one of the primary uses of the C preprocessor. This has allowed C to become the lingua franca of the open source movement.

Works with: C version 94 and later

<c>#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L

#pragma error("C compiler must adhere to at least C99 for the following code.")
#else
/* rest of file */
#endif</c>

However, there is no facility in C for checking whether individual variables and functions have been declared. In open source, the GNU autotools are often used for this purpose, doing this kind of check in a shell script and defining symbols such as __HAVE_ABS__ which can be checked by the preprocessor.

D

The DMD compiler has macros defined for the version, more easily accessible through std.compiler:

<d>import std.compiler;

 static if (version_major < 2 || version_minor > 7) {
   // this prevents further compilation
   static assert (false, "I can't cope with this compiler version");
 }</d>

To check if something compiles or not:

<d>version(D_Version2) {

 static if( __traits(compiles,abs(bloop)) ) {

  typeof(abs(bloop)) computeAbsBloop()  {
     return abs(bloop);
  }

 }
} else static assert(0, "Requires D version 2");</d>

Note that this checks that bloop is of a type which abs() accepts. It is generic code; if the type of abs() changes, so will the return type of the function. The test can also be written so that it will work on D version 1:

<d>static if ( is(typeof(abs(bloop))) ) {

  typeof(abs(bloop)) computeAbsBloop()  {
     return abs(bloop);
  }
}</d>

E

def version := interp.getProps()["e.version"]

(There is no built-in version comparison, and the author of this example assumes that implementing a version comparison algorithm isn't the point of this task.)

escape fail {
    def &x := meta.getState().fetch("&bloop", fn { fail("no bloop") })
    if (!x.__respondsTo("abs", 0)) { fail("no abs") }
    x.abs()
}

Forth

Standard Forth doesn't necessarily provide for version numbers, but you can query information about the environment at interpretation time:

s" MAX-U" environment? [IF]
   0xffffffff <> [IF] .( Requires 32 bits! ) bye [THEN]
[THEN]
[defined] bloop [if]
[defined] abs [if]
  bloop @ abs
[then] [then]

Java

You can't see if a variable or function is available in Java (it will be a compile time error if you try to use them when you they aren't available), but you can check the version number using the System class: <java>public class VersCheck { public static void main(String[] args) { String vers = System.getProperty("java.version"); vers = vers.substring(0,vers.indexOf('.')) + "." + //some String fiddling to get the version number into a usable form vers.substring(vers.indexOf('.')+1,vers.lastIndexOf('.')); if(Double.parseDouble(vers) >= 1.5){ System.out.println("YAY!"); }else{ System.err.println("Must use Java >=1.5"); } } }</java>

MAXScript

fn computeAbsBloop bloop =
(
    versionNumber = maxVersion()

    if versionNumber[1] < 9000 then
    (
        print "Max version 9 required"
        return false
    )

    if bloop == undefined then
    (
        print "Bloop is undefined"
        return false
    )

    try
    (
        abs bloop
    )
    catch
    (
        print "No function abs"
        false
    )
)

computeAbsBloop -17

Perl

Works with: Perl version 5.x

<perl>require v5.6.1; # run time version check

require 5.6.1;     # ditto
require 5.006_001; # ditto; preferred for backwards compatibility</perl>

Checking whether a variable exists is kind of daft. Good style dictates that I declare the variables I'm going to use, and then I already know $bloop exists. Checking for the value of a variable however is something very common. <perl>defined $bloop;

# returns true if bloop has been filled with something useful</perl>

What if 'bloop' is a computed value? Good style forbids that I dereference willy-nilly variables with unknown names, that's what hashes are good for. <perl>$computed = 'bloop';

exists $introspect{$computed};
# returns true if the key bloop exists in hash %introspect</perl>

But neither you can do this, for example: <perl>#$bloop = -123; # uncomment this line to see the difference

if (defined($::{'bloop'})) {print abs(${'bloop'})} else {print "bloop isn't defined"};</perl>

The trick in this example is to use bloop variable by reference ${'bloop'} (otherwise it will be created unconditionally by the compiler). Perl store nametables inside hashes: '::' - for main package and 'xxx::' for package 'xxx'. In Perl, you cannot check for the existence of built-in functions, of which abs() is one. However in practice that's not a problem because most functions live in classes, and those are easily inspectable at runtime. <perl>use UNIVERSAL qw(can);

use Math::Cephes qw();
print Math::Cephes->fabs($bloop) if can 'Math::Cephes', 'fabs';</perl>

Pop11

Variable pop_internal_version contains Poplog version in numeric form (as an integer) -- this one is most convenient for version checks. For printing one can use pop_version (which is a string containing more information).

;;; Exit if version below 15.00
if pop_internal_version < 150000 then
    sysexit()
endif;

Pop11 variables are named by words. Pop11 word is a unique version of string stored in dictionary. So we need first convert strings to words and then query about words. Pop11 variables can store any value including functions and in fact when one accesses a function like abs by name one merely access a variable abs which happen to hold predefined function abs. To follow spirit of the task as closely as possible we check if abs indeed holds functional value.

;;; We do main task in a procedure
define check_and_call(x, y);
   lvars wx=consword(x), wy=consword(y);
   if identprops(wx) = 0 and isprocedure(valof(wx))
      and identprops(wy) = 0 then
          return(valof(wx)(valof(wy)));
   else
        return("failed");
   endif;
enddefine;
;;; Prints failed because bloop is undefined
check_and_call('abs' , 'bloop') =>
;;; Define bloop
vars bloop = -5;
;;; Now prints 5
check_and_call('abs' , 'bloop') =>

Note that here bloop is defined as "permanent" variable, Pop11 also have lexical variables which are not available for introspection.

Python

<python># Checking for system version

import sys
major, minor, bugfix = sys.version_info[:3]
if major < 2:
    sys.exit('Python 2 is required')


def defined(name): # LBYL (Look Before You Leap)
    return name in globals() or name in locals() or name in vars(__builtins__)
def defined2(name): # EAFP (Easier to Ask Forgiveness than Permission)
    try:
         eval(name)
         return True
    except NameError:
         return False
if defined('bloop') and defined('abs') and callable(abs):
    print abs(bloop)
if defined2('bloop') and defined2('abs') and callable(abs):
    print abs(bloop)
</python>

Raven

VERSION 0 prefer 20071104 <
if  'version >= 20071104 required' print bye
'bloop' GLOBAL keys in && 'abs' CORE keys in
if  bloop abs print

Ruby

exit if RUBY_VERSION < '1.8.6'

 puts bloop.abs if defined?(bloop) and bloop.respond_to?(:abs)

Tcl

package require Tcl 8.2 ; # throws an error if older
if {[info exists bloop] && [llength [info functions abs]]} {
  puts [expr abs($bloop)]
}

Toka

Works with: Toka version 1.1+

Starting with Release 1.1, Toka allows for checking the version number:

VERSION 101 > [ bye ] ifFalse

Release 1.0 can be detected by doing:

` VERSION FALSE = [ bye ] ifTrue

Basic introspection is possible via `

` bloop FALSE <> ` abs FALSE <> and [ ` bloop invoke @ ` abs invoke ] ifTrue