Introspection: Difference between revisions
Add Jsish |
→{{header|jq}}: typo |
||
(29 intermediate revisions by 21 users not shown) | |||
Line 12: | Line 12: | ||
=={{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: |
||
< |
<syntaxhighlight lang="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; |
||
Line 25: | Line 25: | ||
Put (Float'Digits); |
Put (Float'Digits); |
||
New_Line; |
New_Line; |
||
end Introspection;</ |
end Introspection;</syntaxhighlight> |
||
All Ada compilers recognize obsolete parts of a programs and either automatically recompile them or fail to link the program. |
All Ada compilers recognize obsolete parts of a programs and either automatically recompile them or fail to link the program. |
||
=={{header|Aikido}}== |
=={{header|Aikido}}== |
||
The version of the Aikido interpreter is in the global scope variable <em>version</em>. AIkido doesn't have <code>abs</code> but it does have <code>fabs</code>. Getting the variables in main involves getting their names and then evaluating them as an expression in order to retrieve their type. |
The version of the Aikido interpreter is in the global scope variable <em>version</em>. AIkido doesn't have <code>abs</code> but it does have <code>fabs</code>. Getting the variables in main involves getting their names and then evaluating them as an expression in order to retrieve their type. |
||
< |
<syntaxhighlight lang="aikido"> |
||
import math |
import math |
||
Line 83: | Line 83: | ||
</syntaxhighlight> |
|||
</lang> |
|||
Here is the result: |
Here is the result: |
||
fabs(bloop) is 1.4 |
fabs(bloop) is 1.4 |
||
There are 3 integer variables in the global scope |
There are 3 integer variables in the global scope |
||
Their sum is 1936 |
Their sum is 1936 |
||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
Line 103: | Line 101: | ||
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}} |
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}} |
||
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386}} |
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386}} |
||
< |
<syntaxhighlight lang="algol68">BEGIN |
||
print (("Integer range: ", -max int, " .. ", max int, new line)); |
print (("Integer range: ", -max int, " .. ", max int, new line)); |
||
print (("Integer digits: ", int width, new line)); |
print (("Integer digits: ", int width, new line)); |
||
print (("Float range: ", -max real, " .. ", max real, new line)); |
print (("Float range: ", -max real, " .. ", max real, new line)); |
||
print (("Float digits: ", real width, new line)) |
print (("Float digits: ", real width, new line)) |
||
END</ |
END</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 123: | Line 121: | ||
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}} |
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}} |
||
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - MODEs BYTE, SEMA, FORMAT etc are not available in ELLA Algol68RS}} |
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - MODEs BYTE, SEMA, FORMAT etc are not available in ELLA Algol68RS}} |
||
< |
<syntaxhighlight lang="algol68">BEGIN |
||
MODE SSMODES = UNION(SHORT SHORT BITS, SHORT SHORT BYTES, #SHORT SHORT CHAR,# |
MODE SSMODES = UNION(SHORT SHORT BITS, SHORT SHORT BYTES, #SHORT SHORT CHAR,# |
||
SHORT SHORT INT, SHORT SHORT REAL, SHORT SHORT COMPL); |
SHORT SHORT INT, SHORT SHORT REAL, SHORT SHORT COMPL); |
||
Line 172: | Line 170: | ||
sep := ", " |
sep := ", " |
||
OD |
OD |
||
END</ |
END</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 186: | Line 184: | ||
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.3.3 algol68g-2.3.3].}} |
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.3.3 algol68g-2.3.3].}} |
||
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}} |
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}} |
||
'''File: Typeof_operator.a68'''< |
'''File: Typeof_operator.a68'''<syntaxhighlight lang="algol68">#!/usr/local/bin/a68g --script # |
||
OP TYPEOF = (INT skip)STRING: "INT"; |
OP TYPEOF = (INT skip)STRING: "INT"; |
||
Line 193: | Line 191: | ||
OP TYPEOF = (COMPL skip)STRING: "COMPL"; |
OP TYPEOF = (COMPL skip)STRING: "COMPL"; |
||
printf(($g" "$,TYPEOF 1, TYPEOF "x", TYPEOF pi, TYPEOF (0 I 1 ), $l$))</ |
printf(($g" "$,TYPEOF 1, TYPEOF "x", TYPEOF pi, TYPEOF (0 I 1 ), $l$))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 205: | Line 203: | ||
{{works with|ELLA ALGOL 68|Any (with appropriate job cards)}} |
{{works with|ELLA ALGOL 68|Any (with appropriate job cards)}} |
||
'''File: Introspection_array_bounds.a68'''< |
'''File: Introspection_array_bounds.a68'''<syntaxhighlight lang="algol68">#!/usr/local/bin/a68g --script # |
||
[]INT x = (5,4,3,2,1); |
[]INT x = (5,4,3,2,1); |
||
print(("x =", x, new line)); |
print(("x =", x, new line)); |
||
print(("LWB x =", LWB x, ", UPB x = ",UPB x, new line))</ |
print(("LWB x =", LWB x, ", UPB x = ",UPB x, new line))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 216: | Line 214: | ||
LWB x = +1, UPB x = +5 |
LWB x = +1, UPB x = +5 |
||
</pre> |
</pre> |
||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="rebol">if not? sys\version > 0.9.0 -> panic "version too old!" |
|||
bloop: 3 - 5 |
|||
if? set? 'bloop -> "variable 'bloop' is set" |
|||
else -> "variable 'bloop' is not set" |
|||
if set? 'abs -> print ["the absolute value of bloop is:" abs bloop] |
|||
print [ |
|||
"The sum of all globally defined integers is:" |
|||
sum map select keys symbols 'sym -> integer? var sym |
|||
'sym -> var sym |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>the absolute value of bloop is: 2 |
|||
The sum of all globally defined integers is: -2</pre> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
< |
<syntaxhighlight lang="autohotkey">if (A_AhkVersion < "1.0.48.03") |
||
{ |
{ |
||
MsgBox % "you are using" . A_AhkVersion . "`nplease upgrade to" . "1.0.48.03" |
MsgBox % "you are using" . A_AhkVersion . "`nplease upgrade to" . "1.0.48.03" |
||
Line 227: | Line 247: | ||
if IsFunc("abs") |
if IsFunc("abs") |
||
MsgBox % abs(bloop) |
MsgBox % abs(bloop) |
||
return</ |
return</syntaxhighlight> |
||
=={{header|AWK}}== |
=={{header|AWK}}== |
||
{{works with|gawk|4.1.0}} PROCINFO is a gawk-extension |
{{works with|gawk|4.1.0}} PROCINFO is a gawk-extension |
||
<syntaxhighlight lang="awk"> |
|||
<lang AWK> |
|||
# syntax: GAWK -f INTROSPECTION.AWK |
# syntax: GAWK -f INTROSPECTION.AWK |
||
BEGIN { |
BEGIN { |
||
Line 246: | Line 266: | ||
} |
} |
||
function abs(x) { if (x >= 0) { return x } else { return -x } } |
function abs(x) { if (x >= 0) { return x } else { return -x } } |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 255: | Line 275: | ||
=={{header|BBC BASIC}}== |
=={{header|BBC BASIC}}== |
||
{{works with|BBC BASIC for Windows}} |
{{works with|BBC BASIC for Windows}} |
||
< |
<syntaxhighlight lang="bbcbasic"> IF VAL(FNversion) < 5.94 THEN PRINT "Version is too old" : END |
||
ON ERROR LOCAL PRINT "Variable 'bloop' doesn't exist" : END |
ON ERROR LOCAL PRINT "Variable 'bloop' doesn't exist" : END |
||
Line 277: | Line 297: | ||
INPUT #F%,V$ |
INPUT #F%,V$ |
||
CLOSE #F% |
CLOSE #F% |
||
= RIGHT$(V$,5)</ |
= RIGHT$(V$,5)</syntaxhighlight> |
||
=={{header|C}}== |
=={{header|C}}== |
||
Line 285: | Line 305: | ||
{{works with|C|94 and later}} |
{{works with|C|94 and later}} |
||
< |
<syntaxhighlight lang="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</syntaxhighlight> |
||
However, there is no facility in C for checking whether individual variables |
However, there is no facility in C for checking whether individual variables |
||
Line 296: | Line 316: | ||
doing this kind of check in a shell script and defining symbols |
doing this kind of check in a shell script and defining symbols |
||
such as HAVE_ABS which ''can'' be checked by the preprocessor. |
such as HAVE_ABS which ''can'' be checked by the preprocessor. |
||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
There has to be some caveats made with C#. There are no truly "global" variables - just publicly exported ones from individual classes/types. I chose to make a couple of public static variables in my program's class. Also, the "version" of the compiler is difficult to impossible to get at. There are no predefined compiler constants that can be compared against as in C/C++ but then again, it's hardly the thing that counts in C#. What really counts is the version of .NET and the framework you're working with since that determines what C++ features you can use and the various calls that can be made. Consequently, I check the .NET version to make sure it's past 4.0 and exit if not. |
There has to be some caveats made with C#. There are no truly "global" variables - just publicly exported ones from individual classes/types. I chose to make a couple of public static variables in my program's class. Also, the "version" of the compiler is difficult to impossible to get at. There are no predefined compiler constants that can be compared against as in C/C++ but then again, it's hardly the thing that counts in C#. What really counts is the version of .NET and the framework you're working with since that determines what C++ features you can use and the various calls that can be made. Consequently, I check the .NET version to make sure it's past 4.0 and exit if not. |
||
< |
<syntaxhighlight lang="csharp">using System; |
||
using System.Reflection; |
using System.Reflection; |
||
Line 379: | Line 400: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>bloop's abs value = 10 |
<pre>bloop's abs value = 10 |
||
2 exported ints which total to -30</pre> |
2 exported ints which total to -30</pre> |
||
=={{header|C++}}== |
|||
Identifying the version of the C++ standard used by the compiler in C++ is syntactically very similar to the way of checking the C standard version (also seen on this page). |
|||
<syntaxhighlight lang="cpp">#if !defined(__cplusplus) || __cplusplus < 201103L |
|||
#pragma error("The following code requires at least C++11.") |
|||
#else |
|||
// ... |
|||
#endif</syntaxhighlight> |
|||
As in C, the introspective capabilities of C++ are very limited. |
|||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
Partial answer... |
Partial answer... |
||
< |
<syntaxhighlight lang="clojure"> |
||
; check Java version |
; check Java version |
||
(let [version (Double/parseDouble (re-find #"\d*\.\d*" (System/getProperty "java.version")))] |
(let [version (Double/parseDouble (re-find #"\d*\.\d*" (System/getProperty "java.version")))] |
||
Line 399: | Line 431: | ||
(println "Version ok") |
(println "Version ok") |
||
(throw (Error. "Bad version")))) |
(throw (Error. "Bad version")))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
< |
<syntaxhighlight lang="lisp">(let* ((ver (lisp-implementation-version)) |
||
(major (parse-integer ver :start 0 :end (position #\. ver)))) |
(major (parse-integer ver :start 0 :end (position #\. ver)))) |
||
#+lispworks (assert (>= 5 major) () "Requires Lispworks version 5 or above") |
#+lispworks (assert (>= 5 major) () "Requires Lispworks version 5 or above") |
||
#+clisp (assert (>= 2 major) () "Requires CLISP 2.n") |
#+clisp (assert (>= 2 major) () "Requires CLISP 2.n") |
||
)</ |
)</syntaxhighlight> |
||
< |
<syntaxhighlight lang="lisp">(defvar bloop -4) |
||
(if (and (fboundp 'abs) |
(if (and (fboundp 'abs) |
||
(boundp 'bloop)) |
(boundp 'bloop)) |
||
(format t "~d~%" (abs bloop)))</ |
(format t "~d~%" (abs bloop)))</syntaxhighlight> |
||
The ''list-all-packages'' and ''do-symbols'' forms enable a lisp program to examine all symbols and these can be tested to identify integer variables. |
The ''list-all-packages'' and ''do-symbols'' forms enable a lisp program to examine all symbols and these can be tested to identify integer variables. |
||
< |
<syntaxhighlight lang="lisp">(let ((sum 0) |
||
(ints '())) |
(ints '())) |
||
(loop for pkg in (list-all-packages) |
(loop for pkg in (list-all-packages) |
||
Line 422: | Line 453: | ||
(incf sum (symbol-value s))))) |
(incf sum (symbol-value s))))) |
||
(format t "there are ~d integer variables adding up to ~d~%" |
(format t "there are ~d integer variables adding up to ~d~%" |
||
(length ints) sum))</ |
(length ints) sum))</syntaxhighlight> |
||
=={{header|D}}== |
=={{header|D}}== |
||
With extra credit. |
With extra credit. |
||
< |
<syntaxhighlight lang="d">// Some module-level variables (D doesn't have a global scope). |
||
immutable x = 3, y = 100, z = 3_000; |
immutable x = 3, y = 100, z = 3_000; |
||
short w = 1; // Not an int, must be ignored. |
short w = 1; // Not an int, must be ignored. |
||
Line 457: | Line 488: | ||
tot += mixin("." ~ name); |
tot += mixin("." ~ name); |
||
writeln("Total of the module-level ints (could overflow): ", tot); |
writeln("Total of the module-level ints (could overflow): ", tot); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>The expression is compilable. |
<pre>The expression is compilable. |
||
Line 464: | Line 495: | ||
=={{header|E}}== |
=={{header|E}}== |
||
Version: |
Version: |
||
< |
<syntaxhighlight lang="e">def version := interp.getProps()["e.version"]</syntaxhighlight> |
||
(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.) |
(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.) |
||
Existence: |
Existence: |
||
< |
<syntaxhighlight lang="e">escape fail { |
||
def &x := meta.getState().fetch("&bloop", fn { fail("no bloop") }) |
def &x := meta.getState().fetch("&bloop", fn { fail("no bloop") }) |
||
if (!x.__respondsTo("abs", 0)) { fail("no abs") } |
if (!x.__respondsTo("abs", 0)) { fail("no abs") } |
||
x.abs() |
x.abs() |
||
}</ |
}</syntaxhighlight> |
||
This will return either bloop.abs(), "no bloop", or "no abs". |
This will return either bloop.abs(), "no bloop", or "no abs". |
||
Sum of integers: |
Sum of integers: |
||
<syntaxhighlight lang="e">{ |
|||
<lang e>{ |
|||
var sum := 0 |
var sum := 0 |
||
for &x in interp.getTopScope() { sum += try { x :int } catch _ { 0 } } |
for &x in interp.getTopScope() { sum += try { x :int } catch _ { 0 } } |
||
sum |
sum |
||
}</ |
}</syntaxhighlight> |
||
<code>try</code> rather than an ordinary type check is used because in general a slot might be broken; this way we skip over all read failures as well as non-integers. The block around the code ensures that the sum variable itself will not be involved in the computation. |
<code>try</code> rather than an ordinary type check is used because in general a slot might be broken; this way we skip over all read failures as well as non-integers. The block around the code ensures that the sum variable itself will not be involved in the computation. |
||
=={{header|EchoLisp}}== |
=={{header|EchoLisp}}== |
||
< |
<syntaxhighlight lang="scheme"> |
||
(version) |
(version) |
||
→ EchoLisp - 2.50.3 |
→ EchoLisp - 2.50.3 |
||
Line 515: | Line 546: | ||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
Erlang does not have global variables so I look for a function bloop/0 that returns an integer. |
Erlang does not have global variables so I look for a function bloop/0 that returns an integer. |
||
Moreover, I sum the available modules, instead of the unavailable global integers. |
Moreover, I sum the available modules, instead of the unavailable global integers. |
||
<syntaxhighlight lang="erlang"> |
|||
<lang Erlang> |
|||
-module( introspection ). |
-module( introspection ). |
||
Line 541: | Line 572: | ||
exit_if_too_old( Release ) when Release < "R13A" -> erlang:exit( too_old_release ); |
exit_if_too_old( Release ) when Release < "R13A" -> erlang:exit( too_old_release ); |
||
exit_if_too_old( _Release ) -> ok. |
exit_if_too_old( _Release ) -> ok. |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 551: | Line 582: | ||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
Check for build number and execute a quotation if it's too old. (There are no such things as versions for Factor yet.) |
Check for build number and execute a quotation if it's too old. (There are no such things as versions for Factor yet.) |
||
< |
<syntaxhighlight lang="factor">: if-older ( n true false -- ) |
||
[ build > ] 2dip if ; inline |
[ build > ] 2dip if ; inline |
||
Line 559: | Line 590: | ||
[ [ ] ] dip if-older ; inline |
[ [ ] ] dip if-older ; inline |
||
900 [ "Your version of Factor is too old." print 1 exit ] when-older</ |
900 [ "Your version of Factor is too old." print 1 exit ] when-older</syntaxhighlight> |
||
It is possible to test if a function or a variable exists (<code>search</code>), but that shouldn't be used outside of parsing. |
It is possible to test if a function or a variable exists (<code>search</code>), but that shouldn't be used outside of parsing. |
||
< |
<syntaxhighlight lang="factor">"bloop" search [ |
||
get [ |
get [ |
||
"abs" search [ execute( n -- n' ) ] when* |
"abs" search [ execute( n -- n' ) ] when* |
||
] [ 0 ] if* |
] [ 0 ] if* |
||
] [ 0 ] if*</ |
] [ 0 ] if*</syntaxhighlight> |
||
On the other hand, it is possible to search the global namespace for integer variables: |
On the other hand, it is possible to search the global namespace for integer variables: |
||
< |
<syntaxhighlight lang="factor">USING: assocs formatting kernel math namespaces ; |
||
0 0 |
0 0 |
||
Line 575: | Line 606: | ||
nip dup integer? [ + [ 1 + ] dip ] [ drop ] if |
nip dup integer? [ + [ 1 + ] dip ] [ drop ] if |
||
] assoc-each |
] assoc-each |
||
"There are %d integer variables, the sum is %d\n" printf</ |
"There are %d integer variables, the sum is %d\n" printf</syntaxhighlight> |
||
=={{header|Forth}}== |
=={{header|Forth}}== |
||
Standard Forth doesn't necessarily provide for version numbers, but you can query information about the environment at interpretation time: |
Standard Forth doesn't necessarily provide for version numbers, but you can query information about the environment at interpretation time: |
||
< |
<syntaxhighlight lang="forth">s" MAX-U" environment? [IF] |
||
0xffffffff <> [IF] .( Requires 32 bits! ) bye [THEN] |
0xffffffff <> [IF] .( Requires 32 bits! ) bye [THEN] |
||
[THEN] |
[THEN] |
||
Line 587: | Line 618: | ||
[defined] abs [if] |
[defined] abs [if] |
||
bloop @ abs |
bloop @ abs |
||
[then] [then]</ |
[then] [then]</syntaxhighlight> |
||
[[4tH]] is able to fulfill all requirements. Note that since only one variable has been declared, the sum of all integer (user)variables is consequently the value of that variable. |
[[4tH]] is able to fulfill all requirements. Note that since only one variable has been declared, the sum of all integer (user)variables is consequently the value of that variable. |
||
{{Works with|4tH|3.62.2}} |
{{Works with|4tH|3.62.2}} |
||
< |
<syntaxhighlight lang="forth">[hex] 362 [decimal] 4TH# - [if] [abort] [then] |
||
-32 value bloop |
-32 value bloop |
||
Line 600: | Line 631: | ||
0 last cell+ first over over - .( User variables: ) . |
0 last cell+ first over over - .( User variables: ) . |
||
?do i @ + loop .( Sum: ) . cr</ |
?do i @ + loop .( Sum: ) . cr</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 609: | Line 640: | ||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
Version 1: |
Version 1: |
||
< |
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
||
#If __FB_VERSION__ < "1.06.0" |
#If __FB_VERSION__ < "1.06.0" |
||
Line 625: | Line 656: | ||
Print "bloop does not exist" |
Print "bloop does not exist" |
||
#EndIf |
#EndIf |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>introspection.bas(4) error: Compiler version is too old - needs to be 1.06.0 or later</pre> |
<pre>introspection.bas(4) error: Compiler version is too old - needs to be 1.06.0 or later</pre> |
||
Version 2: |
Version 2: |
||
< |
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
||
#If __FB_VERSION__ < "1.05.0" '' version 1.05.0 is now OK |
#If __FB_VERSION__ < "1.05.0" '' version 1.05.0 is now OK |
||
Line 645: | Line 676: | ||
Print "bloop does not exist" |
Print "bloop does not exist" |
||
#EndIf |
#EndIf |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Abs(bloop) = 15</pre> |
<pre>Abs(bloop) = 15</pre> |
||
Version 3 (version code omitted for brevity): |
Version 3 (version code omitted for brevity): |
||
< |
<syntaxhighlight lang="freebasic">#Undef Abs '' undefine Abs keyword |
||
Dim bloop As Integer = -15 |
Dim bloop As Integer = -15 |
||
#IfDef bloop |
#IfDef bloop |
||
Line 660: | Line 691: | ||
Print "bloop does not exist" |
Print "bloop does not exist" |
||
#EndIf |
#EndIf |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Abs is not available</pre> |
<pre>Abs is not available</pre> |
||
Version 4 (version code omitted for brevity): |
Version 4 (version code omitted for brevity): |
||
< |
<syntaxhighlight lang="freebasic">#Undef Abs '' undefine Abs keyword |
||
'Dim bloop As Integer = -15 '' bloop declaration commented out |
'Dim bloop As Integer = -15 '' bloop declaration commented out |
||
#IfDef bloop |
#IfDef bloop |
||
Line 675: | Line 706: | ||
Print "bloop does not exist" |
Print "bloop does not exist" |
||
#EndIf |
#EndIf |
||
Sleep</ |
Sleep</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>bloop does not exist</pre> |
<pre>bloop does not exist</pre> |
||
=={{header|Frink}}== |
|||
<syntaxhighlight lang="frink">if FrinkVersion[] < "2024-01-01" |
|||
{ |
|||
println["Version of Frink is too old."] |
|||
exit[] |
|||
} |
|||
if isVariableDefined["bloop"] |
|||
{ |
|||
func = getFunction["abs",1] |
|||
if func != undef |
|||
println[func[bloop]] |
|||
}</syntaxhighlight> |
|||
=={{header|GAP}}== |
=={{header|GAP}}== |
||
< |
<syntaxhighlight lang="gap"># Apply a function to a value, given variable names for both function and value |
||
CheckEval := function(fun, val) |
CheckEval := function(fun, val) |
||
local f, x; |
local f, x; |
||
Line 709: | Line 754: | ||
od; |
od; |
||
return s; |
return s; |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|Go}}== |
=={{header|Go}}== |
||
Task variance: "exit if it is too old" is not done here. Go version strings do not present an easily interpreted chronology. This version of the program simply prints the version string. |
Task variance: "exit if it is too old" is not done here. Go version strings do not present an easily interpreted chronology. This version of the program simply prints the version string. |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 771: | Line 816: | ||
fmt.Println(" abs(bloop): ", math.Abs(bloop)) |
fmt.Println(" abs(bloop): ", math.Abs(bloop)) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 786: | Line 831: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import Data.Version |
||
import Control.Monad |
import Control.Monad |
||
import System.Info |
import System.Info |
||
Line 793: | Line 838: | ||
main = when (compilerName == "ghc" && compilerVersion < minGHCVersion) $ |
main = when (compilerName == "ghc" && compilerVersion < minGHCVersion) $ |
||
fail "Compiler too old."</ |
fail "Compiler too old."</syntaxhighlight> |
||
No means exists of checking whether a variable exists at runtime. The set of variables that exist in any given scope is fixed at compile-time. |
No means exists of checking whether a variable exists at runtime. The set of variables that exist in any given scope is fixed at compile-time. |
||
Line 799: | Line 844: | ||
=={{header|Icon}} and {{header|Unicon}}== |
=={{header|Icon}} and {{header|Unicon}}== |
||
< |
<syntaxhighlight lang="unicon">global bloop |
||
procedure main(A) |
procedure main(A) |
||
Line 816: | Line 861: | ||
return (major < maj) | ((major = maj) & (minor < min)) |
return (major < maj) | ((major = maj) & (minor < min)) |
||
} |
} |
||
end</ |
end</syntaxhighlight> |
||
Sample run: |
Sample run: |
||
<pre>->introspect |
<pre>->introspect |
||
Line 825: | Line 870: | ||
=={{header|Inform 7}}== |
=={{header|Inform 7}}== |
||
Inform 7 doesn't have built-in functionality for checking the runtime version number, but the version number is available and can be read by including a snippet of Inform 6 code. The address and format of the version number vary according to the virtual machine being targeted. |
Inform 7 doesn't have built-in functionality for checking the runtime version number, but the version number is available and can be read by including a snippet of Inform 6 code. The address and format of the version number vary according to the virtual machine being targeted. |
||
< |
<syntaxhighlight lang="inform7">Home is a room. |
||
When play begins: |
When play begins: |
||
Line 849: | Line 894: | ||
To decide which version is current runtime version: (- ($32-->0) -). |
To decide which version is current runtime version: (- ($32-->0) -). |
||
To decide which version is required runtime version: decide on 1.1.</ |
To decide which version is required runtime version: decide on 1.1.</syntaxhighlight> |
||
It's not possible to check for the existence of functions (invoking a nonexistent phrase causes a compile-time error) or list global variables. |
It's not possible to check for the existence of functions (invoking a nonexistent phrase causes a compile-time error) or list global variables. |
||
=={{header|Io}}== |
=={{header|Io}}== |
||
< |
<syntaxhighlight lang="io">if(System version < 20080000, exit) |
||
if(hasSlot("bloop") and bloop hasSlot("abs"), bloop abs)</ |
if(hasSlot("bloop") and bloop hasSlot("abs"), bloop abs)</syntaxhighlight> |
||
Io can also inspect the source code of methods written in Io: |
Io can also inspect the source code of methods written in Io: |
||
< |
<syntaxhighlight lang="io">getSlot("arbitraryMethod") code</syntaxhighlight> |
||
=={{header|IS-BASIC}}== |
=={{header|IS-BASIC}}== |
||
< |
<syntaxhighlight lang="is-basic">100 IF VERNUM<2.1 THEN PRINT "Version is too old.":STOP |
||
110 WHEN EXCEPTION USE ERROR |
110 WHEN EXCEPTION USE ERROR |
||
120 PRINT ABS(BLOOP) |
120 PRINT ABS(BLOOP) |
||
Line 869: | Line 914: | ||
150 PRINT EXSTRING$(EXTYPE) |
150 PRINT EXSTRING$(EXTYPE) |
||
160 CONTINUE |
160 CONTINUE |
||
170 END HANDLER</ |
170 END HANDLER</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
Exit if we're running an old version of J (earlier than version 6, which is current as of this writing), giving version number as the exit status: |
Exit if we're running an old version of J (earlier than version 6, which is current as of this writing), giving version number as the exit status: |
||
< |
<syntaxhighlight lang="j">6 (2!:55@:]^:>) 0 ". 1 { 9!:14''</syntaxhighlight> |
||
Compute <tt>abs(bloop)</tt> if <tt>abs</tt> is a function and <tt>bloop</tt> is data: |
Compute <tt>abs(bloop)</tt> if <tt>abs</tt> is a function and <tt>bloop</tt> is data: |
||
< |
<syntaxhighlight lang="j">".(#~3 0*./ .=4!:0@;:)'abs bloop'</syntaxhighlight> |
||
'''Extra credit''': report the number of integer variables in global scope, and their sum: |
'''Extra credit''': report the number of integer variables in global scope, and their sum: |
||
< |
<syntaxhighlight lang="j">((],&(+/);@#~)((=<.)@[^:](''-:$)*.0=0{.@#,)&>)".&.>4!:1]0</syntaxhighlight> |
||
This last expression is longer than the others, because it has a couple of extra guard checks; in J, the programmer doesn't need to care if the data is a single number or an array, or what hardware representation is used for numbers (32-bit int, IEEE float, etc). |
This last expression is longer than the others, because it has a couple of extra guard checks; in J, the programmer doesn't need to care if the data is a single number or an array, or what hardware representation is used for numbers (32-bit int, IEEE float, etc). |
||
Line 885: | Line 930: | ||
=={{header|Java}}== |
=={{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: |
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: |
||
< |
<syntaxhighlight lang="java">public class VersCheck { |
||
public static void main(String[] args) { |
public static void main(String[] args) { |
||
String vers = System.getProperty("java.version"); |
String vers = System.getProperty("java.version"); |
||
Line 896: | Line 941: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
Line 904: | Line 949: | ||
Testing whether the variable “bloop” exists: |
Testing whether the variable “bloop” exists: |
||
< |
<syntaxhighlight lang="javascript">if (typeof bloop !== "undefined") { ... }</syntaxhighlight> |
||
The <code>typeof</code> operator explicitly does not throw an error when given an undeclared variable. |
The <code>typeof</code> operator explicitly does not throw an error when given an undeclared variable. |
||
Line 910: | Line 955: | ||
Test whether <code>Math.abs()</code> is available: |
Test whether <code>Math.abs()</code> is available: |
||
< |
<syntaxhighlight lang="javascript">if ("abs" in Math) { ... }</syntaxhighlight> |
||
<code>abs</code> is a method of the Math object, methods are properties, and the <code>in</code> operator tests whether an object has the named property. |
<code>abs</code> is a method of the Math object, methods are properties, and the <code>in</code> operator tests whether an object has the named property. |
||
=={{header|jq}}== |
|||
'''Works with jq, the C implementation of jq''' |
|||
'''Works with gojq, the Go implementation of jq''' |
|||
jq's support for introspection is limited. For example, jq's version |
|||
number is available from the command-line but not as a built-in; and |
|||
it is not in general possible to check whether a variable has been |
|||
defined without causing an error. However, jq does make it possible |
|||
for a program to check whether a variable has been defined globally, |
|||
so we'll go with that. |
|||
Note that jq's `builtins` function provides details about jq's built-in |
|||
functions, and similarly the `modulemeta` function provides some support for |
|||
introspection within modules, but otherwise there is no support for |
|||
determining the functions that have been user-defined. |
|||
Assuming JQ has been defined appropriately as a shell variable, one could |
|||
invoke jq with a global "bloop" variable as follows: |
|||
<pre> |
|||
$JQ -n --arg version "$($JQ --version)" --argjson bloop -3 -f introspection.jq |
|||
</pre> |
|||
The following program has been tested with recent versions of both jq |
|||
and gojq, but may fail with earlier versions. Note also that |
|||
jq's `length` has the semantics of `abs` when applied to numbers, |
|||
so if your jq does not support `abs` by that name, you could use `length`. |
|||
<syntaxhighlight lang="jq"> |
|||
def checkVersion: |
|||
$version |
|||
| capture("^[^- ]*(?<jq>[- ])(?<major>[0-9]*)[.](?<minor>[0-9]*)") // {jq: 0} |
|||
| if .jq == 0 then "unrecognized version identification: \($version)" | error |
|||
elif .jq == "-" # jq |
|||
and (.major < "1" or (.major == "1" and .minor < "5")) |
|||
then "version \($version) is too old" | error |
|||
elif .jq == " " # gojq |
|||
and (.major == "0" and (.minor | tonumber) < 12) |
|||
then "version \($version) is too old" | error |
|||
else . |
|||
end; |
|||
checkVersion |
|||
# Check that abs/0 is defined |
|||
| (builtins | index("abs/0")) as $ix |
|||
| if $ix == null then "abs/0 not available" | error else . end |
|||
# Is bloop a global variable? |
|||
| if ($ARGS.named | has("bloop")) then $ARGS.named["bloop"] | abs |
|||
else "There is no globally defined variable name $bloop." | error |
|||
end |
|||
</syntaxhighlight> |
|||
Examples: |
|||
{{output}} |
|||
<pre> |
|||
$ gojq -n --arg version "$(gojq --version)" --argjson bloop -3 -f introspection.jq |
|||
3 |
|||
$ jq -n --arg version "$(jq --version)" -f introspection.jq |
|||
jq: error (at <unknown>): There is no globally defined variable name bloop. |
|||
</pre> |
|||
=={{header|Jsish}}== |
=={{header|Jsish}}== |
||
< |
<syntaxhighlight lang="javascript">/* Introspection, in jsish */ |
||
if (Info.version() < 2. |
if (Info.version() < Util.verConvert('2.8.6')) { |
||
puts("need at least version 2. |
puts("need at least version 2.8.6 of jsish for this application"); |
||
exit(1); |
exit(1); |
||
} |
} |
||
/* Check for "abs()" as function and "bloop" as defined value, call if both check true */ |
|||
if ((bloop != undefined) && (typeof Math.abs == 'function')) { |
if ((bloop != undefined) && (typeof Math.abs == 'function')) { |
||
puts(Math.abs(bloop)); |
puts(Math.abs(bloop)); |
||
} |
} |
||
/* ECMAScript, this will sum all numeric values, not just strict integers */ |
|||
var nums = 0, sums = 0, v; |
var nums = 0, sums = 0, v; |
||
for (v of Info.vars(this)) { |
for (v of Info.vars(this)) { |
||
Line 932: | Line 1,043: | ||
} |
} |
||
} |
} |
||
printf("%d numerics with sum of: %d\n", nums, sums);</ |
printf("%d numerics with sum of: %d\n", nums, sums);</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 939: | Line 1,050: | ||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
<syntaxhighlight lang="julia">@show VERSION |
|||
{{works with|Julia|0.6}} |
|||
<lang julia>@show VERSION |
|||
VERSION < v"0.4" && exit(1) |
VERSION < v"0.4" && exit(1) |
||
if isdefined(:bloop) && !isempty(methods(abs)) |
if isdefined(Base, :bloop) && !isempty(methods(abs)) |
||
@show abs(bloop) |
@show abs(bloop) |
||
end |
end |
||
Line 951: | Line 1,060: | ||
vars = filter(x -> eval(x) isa Integer, names(Main)) |
vars = filter(x -> eval(x) isa Integer, names(Main)) |
||
println("Integer variables: ", join(vars, ", "), ".") |
println("Integer variables: ", join(vars, ", "), ".") |
||
println("Sum of integers in the global scope: ", sum(eval.(vars)), ".")</ |
println("Sum of integers in the global scope: ", sum(eval.(vars)), ".")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>VERSION = v" |
<pre>VERSION = v"1.2.0" |
||
Integer variables: a, b, c. |
Integer variables: a, b, c. |
||
Sum of integers in the global scope: 6.</pre> |
Sum of integers in the global scope: 6.</pre> |
||
Line 960: | Line 1,069: | ||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
We will use Java reflection for this task as Kotlin's own reflection facilities do not appear to be able to deal generically with top-level entities at the present time (i.e. ::class isn't yet supported): |
We will use Java reflection for this task as Kotlin's own reflection facilities do not appear to be able to deal generically with top-level entities at the present time (i.e. ::class isn't yet supported): |
||
< |
<syntaxhighlight lang="scala">// version 1.0.6 (intro.kt) |
||
import java.lang.reflect.Method |
import java.lang.reflect.Method |
||
Line 999: | Line 1,108: | ||
} |
} |
||
println("\nThere are $count global integer variables and their sum is $sum") |
println("\nThere are $count global integer variables and their sum is $sum") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,011: | Line 1,120: | ||
=={{header|Lasso}}== |
=={{header|Lasso}}== |
||
< |
<syntaxhighlight lang="lasso">var(bloob = -26) |
||
decimal(lasso_version(-lassoversion)) < 9.2 ? abort |
decimal(lasso_version(-lassoversion)) < 9.2 ? abort |
||
var_defined('bloob') and $bloob -> isa(::integer) and lasso_tagexists('math_abs') ? math_abs($bloob)</ |
var_defined('bloob') and $bloob -> isa(::integer) and lasso_tagexists('math_abs') ? math_abs($bloob)</syntaxhighlight> |
||
-> 26 |
-> 26 |
||
Lassos equivalence of global variables are thread variables. They have scope that lasts for the entire call in contrast to local variables that are confined to the page or method they are created within. |
Lassos equivalence of global variables are thread variables. They have scope that lasts for the entire call in contrast to local variables that are confined to the page or method they are created within. |
||
< |
<syntaxhighlight lang="lasso">var( |
||
bloob = -26, |
bloob = -26, |
||
positive = 450 |
positive = 450 |
||
Line 1,034: | Line 1,143: | ||
} |
} |
||
#total</ |
#total</syntaxhighlight> |
||
-> 424 |
-> 424 |
||
=={{header|Lingo}}== |
=={{header|Lingo}}== |
||
*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. |
*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. |
||
< |
<syntaxhighlight lang="lingo">put _player.productVersion |
||
-- "11.5.9" |
-- "11.5.9" |
||
_player.itemDelimiter="." |
_player.itemDelimiter="." |
||
if integer(_player.productVersion.item[1])<11 then _player.quit()</ |
if integer(_player.productVersion.item[1])<11 then _player.quit()</syntaxhighlight> |
||
*check whether the variable "bloop" exists and whether the math-function "abs()" is available and if yes compute abs(bloop). |
*check whether the variable "bloop" exists and whether the math-function "abs()" is available and if yes compute abs(bloop). |
||
< |
<syntaxhighlight lang="lingo">-- check existence of bloop in local scope |
||
bloopExists = not voidP(value("bloop")) |
bloopExists = not voidP(value("bloop")) |
||
-- or for global scope: |
-- or for global scope: |
||
-- bloopExists = not voidP(_global.bloop) |
-- bloopExists = not voidP(_global.bloop) |
||
absExists = value("abs(1)")=1 |
absExists = value("abs(1)")=1 |
||
if bloopExists and absExists then put abs(bloop) -- or abs(_global.bloop)</ |
if bloopExists and absExists then put abs(bloop) -- or abs(_global.bloop)</syntaxhighlight> |
||
*Report the number of integer variables in global scope, and their sum. |
*Report the number of integer variables in global scope, and their sum. |
||
< |
<syntaxhighlight lang="lingo">cnt = 0 |
||
sum = 0 |
sum = 0 |
||
repeat with v in the globals |
repeat with v in the globals |
||
Line 1,063: | Line 1,172: | ||
end repeat |
end repeat |
||
put cnt |
put cnt |
||
put sum</ |
put sum</syntaxhighlight> |
||
=={{header|Locomotive Basic}}== |
=={{header|Locomotive Basic}}== |
||
Line 1,069: | Line 1,178: | ||
To get the BASIC ROM version number, we need to use a Z80 machine code routine which copies the version number (major/minor/patchlevel) to RAM where BASIC can then read it. Here is the assembly: |
To get the BASIC ROM version number, we need to use a Z80 machine code routine which copies the version number (major/minor/patchlevel) to RAM where BASIC can then read it. Here is the assembly: |
||
< |
<syntaxhighlight lang="z80">org &4000 ; program start address |
||
push bc |
push bc |
||
Line 1,092: | Line 1,201: | ||
pop de |
pop de |
||
pop bc |
pop bc |
||
ret</ |
ret</syntaxhighlight> |
||
The following BASIC program POKEs that routine into memory and quits prematurely if BASIC 1.0 is detected (meaning the machine is a CPC464), as opposed to the more standard 1.1 or later: |
The following BASIC program POKEs that routine into memory and quits prematurely if BASIC 1.0 is detected (meaning the machine is a CPC464), as opposed to the more standard 1.1 or later: |
||
< |
<syntaxhighlight lang="locobasic">10 s=&4000:SYMBOL AFTER 256:MEMORY s-1 |
||
20 FOR i=0 to 34:READ a:POKE s+i,a:NEXT |
20 FOR i=0 to 34:READ a:POKE s+i,a:NEXT |
||
30 DATA &c5,&d5,&e5,&f5,&01,&00,&df,&ed,&49,&01,&86,&7f,&ed,&49 |
30 DATA &c5,&d5,&e5,&f5,&01,&00,&df,&ed,&49,&01,&86,&7f,&ed,&49 |
||
Line 1,104: | Line 1,213: | ||
70 PRINT "BASIC ROM version is ";PEEK(&4040);".";PEEK(&4041);".";PEEK(&4042) |
70 PRINT "BASIC ROM version is ";PEEK(&4040);".";PEEK(&4041);".";PEEK(&4042) |
||
80 IF PEEK(&4041)=0 THEN PRINT "Uh oh, you are still using BASIC 1.0":END |
80 IF PEEK(&4041)=0 THEN PRINT "Uh oh, you are still using BASIC 1.0":END |
||
90 PRINT "You are using BASIC 1.1 or later, program can continue"</ |
90 PRINT "You are using BASIC 1.1 or later, program can continue"</syntaxhighlight> |
||
The second subtask, testing for the presence of a variable, is done here by trying to get the memory address of the variable. If that fails, it is obviously is not yet defined: |
The second subtask, testing for the presence of a variable, is done here by trying to get the memory address of the variable. If that fails, it is obviously is not yet defined: |
||
< |
<syntaxhighlight lang="locobasic">1 ' decide randomly whether to define the variable: |
||
10 IF RND>.5 THEN bloop=-100*RND |
10 IF RND>.5 THEN bloop=-100*RND |
||
20 ON ERROR GOTO 100 |
20 ON ERROR GOTO 100 |
||
Line 1,115: | Line 1,224: | ||
50 PRINT "ABS of bloop is",ABS(bloop) |
50 PRINT "ABS of bloop is",ABS(bloop) |
||
90 END |
90 END |
||
100 IF ERL=30 THEN PRINT "Variable bloop not defined":RESUME 90</ |
100 IF ERL=30 THEN PRINT "Variable bloop not defined":RESUME 90</syntaxhighlight> |
||
(Like the Spectrum version, we have omitted checking for ABS because it is a builit-in function of the BASIC interpreter and therefore always present.) |
(Like the Spectrum version, we have omitted checking for ABS because it is a builit-in function of the BASIC interpreter and therefore always present.) |
||
Line 1,121: | Line 1,230: | ||
'''Extra credit''': Finally, we can traverse the memory area where BASIC stores its integer, real, and string variables and add together all integers (type 1): |
'''Extra credit''': Finally, we can traverse the memory area where BASIC stores its integer, real, and string variables and add together all integers (type 1): |
||
< |
<syntaxhighlight lang="locobasic">10 ' The program should find and add those three integers (%), ignoring reals: |
||
20 foo%=-4:bar%=7:baz%=9:somereal=3.141 |
20 foo%=-4:bar%=7:baz%=9:somereal=3.141 |
||
30 varstart=&ae68 ' for CPC 664 and 6128 |
30 varstart=&ae68 ' for CPC 664 and 6128 |
||
Line 1,138: | Line 1,247: | ||
160 WEND |
160 WEND |
||
170 PRINT "There are"num"integer variables." |
170 PRINT "There are"num"integer variables." |
||
180 PRINT "Their sum is"sum</ |
180 PRINT "Their sum is"sum</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,146: | Line 1,255: | ||
=={{header|Logo}}== |
=={{header|Logo}}== |
||
{{works with|UCB Logo}} |
{{works with|UCB Logo}} |
||
< |
<syntaxhighlight lang="logo">show logoversion ; 5.6 |
||
if logoversion < 6.0 [print [too old!]] |
if logoversion < 6.0 [print [too old!]] |
||
if and [name? "a] [number? :a] [ |
if and [name? "a] [number? :a] [ |
||
print ifelse procedure? "abs [abs :a] [ifelse :a < 0 [minus :a] [:a]] |
print ifelse procedure? "abs [abs :a] [ifelse :a < 0 [minus :a] [:a]] |
||
]</ |
]</syntaxhighlight> |
||
=={{header|Logtalk}}== |
=={{header|Logtalk}}== |
||
< |
<syntaxhighlight lang="logtalk"> |
||
:- object(my_application). |
:- object(my_application). |
||
Line 1,188: | Line 1,297: | ||
:- end_object. |
:- end_object. |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">if _VERSION:sub(5) + 0 < 5.1 then print"too old" end --_VERSION is "Lua <version>". |
||
if bloop and math.abs then print(math.abs(bloop)) end</ |
if bloop and math.abs then print(math.abs(bloop)) end</syntaxhighlight> |
||
=={{header|Maple}}== |
=={{header|Maple}}== |
||
The "version" kernel option returns a string similar to |
The "version" kernel option returns a string similar to |
||
< |
<syntaxhighlight lang="maple">> kernelopts( 'version' ); |
||
Maple 16.00, SUN SPARC SOLARIS, Mar 3 2012, Build ID 732982</ |
Maple 16.00, SUN SPARC SOLARIS, Mar 3 2012, Build ID 732982</syntaxhighlight> |
||
The following does the trick for the first bit. |
The following does the trick for the first bit. |
||
< |
<syntaxhighlight lang="maple">> if sscanf( (StringTools:-Split(kernelopts(version))[2]), "%d.%d" )[1] < 300 then `quit`(1) end;</syntaxhighlight> |
||
(There is also an internal "version" procedure, which returns a build ID, but this is less obvious to use, as you'd need a table mapping versions to build IDs. Besides, it prints stuff.) |
(There is also an internal "version" procedure, which returns a build ID, but this is less obvious to use, as you'd need a table mapping versions to build IDs. Besides, it prints stuff.) |
||
It doesn't really make sense to ask whether a variable "exists"; it springs into existence by uttering it in code. So I'll interpret the problem as asking whether it is assigned some kind of numeric value to which abs() can be applied. |
It doesn't really make sense to ask whether a variable "exists"; it springs into existence by uttering it in code. So I'll interpret the problem as asking whether it is assigned some kind of numeric value to which abs() can be applied. |
||
< |
<syntaxhighlight lang="maple">> if type( bloop, complex( extended_numeric ) ) and type( abs, mathfunc ) then print( abs( bloop ) ) end: |
||
1/2 |
1/2 |
||
13</ |
13</syntaxhighlight> |
||
Note that it is not necessary to check that the name "bloop" is assigned (though it is possible to do so), since an unassigned name is a first-class value in Maple. Another possible interpretation is that the symbolic expression |
Note that it is not necessary to check that the name "bloop" is assigned (though it is possible to do so), since an unassigned name is a first-class value in Maple. Another possible interpretation is that the symbolic expression |
||
< |
<syntaxhighlight lang="maple">> abs( bloop ); |
||
| bloop |</ |
| bloop |</syntaxhighlight> |
||
is a perfectly good expression in Maple, so checking for the the "existence" of "bloop" isn't necessary in the first place. (One probably would not bother to check that abs() was actually there either, unless one expected that the standard library was broken.) |
is a perfectly good expression in Maple, so checking for the the "existence" of "bloop" isn't necessary in the first place. (One probably would not bother to check that abs() was actually there either, unless one expected that the standard library was broken.) |
||
Here are the number and sum of the assigned integer globals in my current (fresh) session. |
Here are the number and sum of the assigned integer globals in my current (fresh) session. |
||
< |
<syntaxhighlight lang="maple">> nops([anames](integer)); |
||
3 |
3 |
||
> eval(`+`(anames(integer))); |
> eval(`+`(anames(integer))); |
||
17 |
17 |
||
</syntaxhighlight> |
|||
</lang> |
|||
If I change it, I get: |
If I change it, I get: |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
> foo := 25: |
> foo := 25: |
||
> nops([anames](integer)); |
> nops([anames](integer)); |
||
Line 1,226: | Line 1,335: | ||
> eval(`+`(anames(integer))); |
> eval(`+`(anames(integer))); |
||
42</ |
42</syntaxhighlight> |
||
=={{header|Mathematica}}== |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
< |
<syntaxhighlight lang="mathematica">If[$VersionNumber < 8, Quit[]] |
||
If[NameQ["bloop"] && NameQ["Abs"], |
If[NameQ["bloop"] && NameQ["Abs"], |
||
Print[Abs[bloop]]]</ |
Print[Abs[bloop]]]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>7</pre> |
<pre>7</pre> |
||
<lang>globalintegers = Symbol /@ Select[Names["Global`*"], IntegerQ[Symbol[#]] &]; |
<syntaxhighlight lang="text">globalintegers = Symbol /@ Select[Names["Global`*"], IntegerQ[Symbol[#]] &]; |
||
Print [ globalintegers //Length, " global integer(s) and their sum is: ", globalintegers // Total] </ |
Print [ globalintegers //Length, " global integer(s) and their sum is: ", globalintegers // Total] </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,243: | Line 1,352: | ||
=={{header|MATLAB}} / {{header|Octave}}== |
=={{header|MATLAB}} / {{header|Octave}}== |
||
< |
<syntaxhighlight lang="matlab"> % convert version into numerical value |
||
v = version; |
v = version; |
||
v(v=='.')=' '; |
v(v=='.')=' '; |
||
Line 1,263: | Line 1,372: | ||
printf('abs(bloob) is %f\n',abs(bloob)); |
printf('abs(bloob) is %f\n',abs(bloob)); |
||
return; |
return; |
||
end; </ |
end; </syntaxhighlight> |
||
Extra credit task: |
Extra credit task: |
||
<syntaxhighlight lang="matlab"> |
|||
<lang Matlab> |
|||
% find all integers |
% find all integers |
||
varlist = whos; |
varlist = whos; |
||
Line 1,281: | Line 1,390: | ||
printf('sum of integer scalars: %i\n',intsum); |
printf('sum of integer scalars: %i\n',intsum); |
||
printf('sum of all integer elements: %i\n',intsumall); |
printf('sum of all integer elements: %i\n',intsumall); |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Maxima}}== |
=={{header|Maxima}}== |
||
< |
<syntaxhighlight lang="maxima">/* Get version information */ |
||
build_info(); |
build_info(); |
||
/* build_info("5.27.0", "2012-05-08 11:27:57", "i686-pc-mingw32", "GNU Common Lisp (GCL)", "GCL 2.6.8") */ |
/* build_info("5.27.0", "2012-05-08 11:27:57", "i686-pc-mingw32", "GNU Common Lisp (GCL)", "GCL 2.6.8") */ |
||
Line 1,301: | Line 1,410: | ||
/* Sum of integer variables */ |
/* Sum of integer variables */ |
||
lreduce("+", sublist(map(ev, values), integerp));</ |
lreduce("+", sublist(map(ev, values), integerp));</syntaxhighlight> |
||
=={{header|MAXScript}}== |
=={{header|MAXScript}}== |
||
< |
<syntaxhighlight lang="maxscript">fn computeAbsBloop bloop = |
||
( |
( |
||
versionNumber = maxVersion() |
versionNumber = maxVersion() |
||
Line 1,331: | Line 1,440: | ||
) |
) |
||
computeAbsBloop -17</ |
computeAbsBloop -17</syntaxhighlight> |
||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |
||
Line 1,337: | Line 1,446: | ||
The language does however return a string identifying the version of NetRexx in effect when the current class was last processed. This information can be retrieved through the '''<tt>version</tt>''' ''special variable''. |
The language does however return a string identifying the version of NetRexx in effect when the current class was last processed. This information can be retrieved through the '''<tt>version</tt>''' ''special variable''. |
||
< |
<syntaxhighlight lang="netrexx">/* NetRexx */ |
||
options replace format comments java crossref symbols binary |
options replace format comments java crossref symbols binary |
||
Line 1,362: | Line 1,471: | ||
end |
end |
||
return |
return |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,373: | Line 1,482: | ||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
In Nim, many checks are done at compile time. So, you have the choice to emit an error or warning at compile time or exit at runtime. |
|||
<lang nim>echo NimVersion |
|||
<syntaxhighlight lang="nim">when NimVersion < "1.2": |
|||
error "This compiler is too old" # Error at compile time. |
|||
assert NimVersion >= "1.4", "This compiler is too old." # Assertion defect at runtime. |
|||
var bloop = -12 |
var bloop = -12 |
||
when compiles abs(bloop): |
when compiles abs(bloop): |
||
echo abs(bloop)</ |
echo abs(bloop)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre>12</pre> |
||
12</pre> |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml"># Sys.ocaml_version;; |
||
- : string = "3.10.2"</ |
- : string = "3.10.2"</syntaxhighlight> |
||
< |
<syntaxhighlight lang="ocaml"># Scanf.sscanf (Sys.ocaml_version) "%d.%d.%d" |
||
(fun major minor micro -> major, minor, micro) ;; |
(fun major minor micro -> major, minor, micro) ;; |
||
- : int * int * int = (3, 10, 2)</ |
- : int * int * int = (3, 10, 2)</syntaxhighlight> |
||
Checking if an identifier (a value or a function) is bound doesn't make any sens in OCaml, which is strongly staticaly typed. |
Checking if an identifier (a value or a function) is bound doesn't make any sens in OCaml, which is strongly staticaly typed. |
||
Line 1,400: | Line 1,513: | ||
Oforth does not have global variables, only global constants. |
Oforth does not have global variables, only global constants. |
||
< |
<syntaxhighlight lang="oforth">: bloopAbs |
||
| bl m | |
| bl m | |
||
System.VERSION println |
System.VERSION println |
||
Line 1,411: | Line 1,524: | ||
System.Out "bloop value is : " << bl value << cr |
System.Out "bloop value is : " << bl value << cr |
||
System.Out "bloop abs is : " << bl value m perform << cr ;</ |
System.Out "bloop abs is : " << bl value m perform << cr ;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,427: | Line 1,540: | ||
ok |
ok |
||
</pre> |
</pre> |
||
=={{header|OxygenBasic}}== |
|||
Compile time introspection |
|||
<syntaxhighlight lang="text"> |
|||
$ rtlversion "0.4.0" |
|||
' |
|||
#if not match(rtlversion,o2version) |
|||
#error "This RTL version mismatches o2 version "+o2version |
|||
#else |
|||
print o2version |
|||
#endif |
|||
float bloop=-1618 |
|||
#ifdef bloop |
|||
#ifdef abs |
|||
print abs(bloop) |
|||
#endif |
|||
#endif |
|||
</syntaxhighlight> |
|||
=={{header|Oz}}== |
=={{header|Oz}}== |
||
We cannot check whether a variable is in scope (static property). |
We cannot check whether a variable is in scope (static property). |
||
We <em>can</em> check whether a module exports a certain value. However, for system modules the compiler will refuse to compile if we try to use a non-existing value. |
We <em>can</em> check whether a module exports a certain value. However, for system modules the compiler will refuse to compile if we try to use a non-existing value. |
||
< |
<syntaxhighlight lang="oz">declare |
||
Version = {Property.get 'oz.version'} |
Version = {Property.get 'oz.version'} |
||
%% Version is an atom like '1.4.0'. So we can not compare it directly. |
%% Version is an atom like '1.4.0'. So we can not compare it directly. |
||
Line 1,444: | Line 1,578: | ||
else |
else |
||
{System.showInfo "Your Mozart version is too old."} |
{System.showInfo "Your Mozart version is too old."} |
||
end</ |
end</syntaxhighlight> |
||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
{{works with|PARI/GP|2.4.3 and above}} |
{{works with|PARI/GP|2.4.3 and above}} |
||
< |
<syntaxhighlight lang="parigp">if(lex(version(), [2,4,3]) < 0, quit()); \\ Compare the version to 2.4.3 lexicographically |
||
if(bloop!='bloop && type(abs) == "t_CLOSURE", abs(bloop))</ |
if(bloop!='bloop && type(abs) == "t_CLOSURE", abs(bloop))</syntaxhighlight> |
||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{works with|Perl|5.x}} |
{{works with|Perl|5.x}} |
||
< |
<syntaxhighlight lang="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</syntaxhighlight> |
||
To check if a variable exists, do a name lookup of it in the package symbol table: |
To check if a variable exists, do a name lookup of it in the package symbol table: |
||
< |
<syntaxhighlight lang="perl">#$bloop = -123; # uncomment this line to see the difference |
||
no strict 'refs'; # referring to variable by name goes against 'strict' pragma |
no strict 'refs'; # referring to variable by name goes against 'strict' pragma |
||
if (defined($::{'bloop'})) {print abs(${'bloop'})} else {print "bloop isn't defined"};</ |
if (defined($::{'bloop'})) {print abs(${'bloop'})} else {print "bloop isn't defined"};</syntaxhighlight> |
||
To check if certain built-in function is available (maybe you are using a stripped down build of perl binary, for example), one can use eval, but make sure the statement you are eval'ing doesn't have side effect: |
To check if certain built-in function is available (maybe you are using a stripped down build of perl binary, for example), one can use eval, but make sure the statement you are eval'ing doesn't have side effect: |
||
< |
<syntaxhighlight lang="perl">eval('abs(0)'); # eval("") instead of eval{}; the latter is not for run-time check |
||
print "abs() doesn't seem to be available\n" if $@;</ |
print "abs() doesn't seem to be available\n" if $@;</syntaxhighlight> |
||
To check if a package or object provides certain method name, use 'can': |
To check if a package or object provides certain method name, use 'can': |
||
< |
<syntaxhighlight lang="perl">use Math::Complex; |
||
my $cpl = Math::Complex->new(1,1); |
my $cpl = Math::Complex->new(1,1); |
||
Line 1,476: | Line 1,610: | ||
print "object \$cpl does not have 'explode' method\n" |
print "object \$cpl does not have 'explode' method\n" |
||
unless $cpl->can('explode'); |
unless $cpl->can('explode'); |
||
</syntaxhighlight> |
|||
</lang> |
|||
Keep in mind that what a package has as method names are not equal to what method names can be called on this package, due to things like AUTOLOAD. |
Keep in mind that what a package has as method names are not equal to what method names can be called on this package, due to things like AUTOLOAD. |
||
For most uses, introspection is meaningless, just call the method (and catch exceptions if it's important). |
For most uses, introspection is meaningless, just call the method (and catch exceptions if it's important). |
||
An example that solves the task: |
An example that solves the task: |
||
< |
<syntaxhighlight lang="perl">use 5.010; |
||
our $bloop = -12; |
our $bloop = -12; |
||
if (defined $::bloop) { |
if (defined $::bloop) { |
||
Line 1,493: | Line 1,627: | ||
else { |
else { |
||
say '$bloop is not defined'; |
say '$bloop is not defined'; |
||
}</ |
}</syntaxhighlight> |
||
Note that this program will exit with a message "Perl v5.10.0 required" if run under perl version lower than 5.10 and it actually uses a feature introduced in that version (<code>say</code>). |
Note that this program will exit with a message "Perl v5.10.0 required" if run under perl version lower than 5.10 and it actually uses a feature introduced in that version (<code>say</code>). |
||
The program checks whether the variable is actually defined and not if it just exists. |
The program checks whether the variable is actually defined and not if it just exists. |
||
Line 1,501: | Line 1,635: | ||
Extra task: |
Extra task: |
||
< |
<syntaxhighlight lang="perl">use 5.010; |
||
package test; |
package test; |
||
use Regexp::Common; |
use Regexp::Common; |
||
Line 1,516: | Line 1,650: | ||
my $num = @ints; |
my $num = @ints; |
||
my $sum = sum @ints; |
my $sum = sum @ints; |
||
say "$num integers, sum = $sum";</ |
say "$num integers, sum = $sum";</syntaxhighlight> |
||
It prints: |
It prints: |
||
<pre> |
<pre> |
||
Line 1,523: | Line 1,657: | ||
This example uses the <code>test</code> namespace instead of the default, because there already are some integer numbers in the <code>main</code> namespace like the PID, etc. |
This example uses the <code>test</code> namespace instead of the default, because there already are some integer numbers in the <code>main</code> namespace like the PID, etc. |
||
The program to sum those numbers would be: |
The program to sum those numbers would be: |
||
< |
<syntaxhighlight lang="perl">use 5.010; |
||
use Regexp::Common; |
use Regexp::Common; |
||
use List::Util qw(sum); |
use List::Util qw(sum); |
||
Line 1,529: | Line 1,663: | ||
my $num = @ints; |
my $num = @ints; |
||
my $sum = sum @ints; |
my $sum = sum @ints; |
||
say "$num integers, sum = $sum";</ |
say "$num integers, sum = $sum";</syntaxhighlight> |
||
<pre> |
<pre> |
||
4 integers, sum = 74717 |
4 integers, sum = 74717 |
||
</pre> |
</pre> |
||
=={{header| |
=={{header|Phix}}== |
||
The requires procedure behaves like a compiler directive, although it is in fact just a normal executable routine. |
|||
<lang perl6>use v6; # require Perl 6 |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
my $bloop = -123; |
|||
<span style="color: #7060A8;">requires<span style="color: #0000FF;">(<span style="color: #008000;">"0.8.2"<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- crashes on 0.8.1 and earlier </span> |
|||
<span style="color: #7060A8;">requires<span style="color: #0000FF;">(<span style="color: #000000;">WINDOWS<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- crashes on Linux </span> |
|||
<span style="color: #7060A8;">requires<span style="color: #0000FF;">(<span style="color: #000000;">64<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- crashes on 32-bit |
|||
<!--</syntaxhighlight>--> |
|||
If passed a string it compares it (intelligently) against the interpreter/compiler version and terminates in error with a suitable message should it be too old to cope. Otherwise the parameter must be an integer: <32 checks the platform, >=32 checks the word size. In the latter case when (interpreting and) it needs to, it hunts for a suitable alternative runtime and offers to re-run with that, maybe you need bigger ints, or maybe you only ship a 32-bit libcurl.dll. |
|||
if MY::{'$bloop'}.defined and CORE::{'&abs'}.defined { say abs $bloop } |
|||
The version() routine used by the above can also be called directly and returns a string: |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">version<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- eg "0.8.0" |
|||
<!--</syntaxhighlight>--> |
|||
Normally only really useful for display, but you can of course break that down into an integer triplet with scanf(), as requires does, maybe something works on 0.7.7 and 0.7.9 but not 0.7.8. |
|||
Phix has a builtin abs() routine, which will be auto-included if referenced. |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #000080;font-style:italic;">--include pmaths.e -- (an auto-include, ok but not needed) |
|||
--include complex.e -- (not an auto-include, needed if used)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">r_abs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">routine_id<span style="color: #0000FF;">(<span style="color: #008000;">"abs"<span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">--integer r_abs = routine_id("complex_abs")</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">r_abs<span style="color: #0000FF;">!=<span style="color: #0000FF;">-<span style="color: #000000;">1</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">call_func<span style="color: #0000FF;">(<span style="color: #000000;">r_abs<span style="color: #0000FF;">,<span style="color: #0000FF;">{<span style="color: #0000FF;">-<span style="color: #000000;">42<span style="color: #0000FF;">}<span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if |
|||
<!--</syntaxhighlight>--> |
|||
Using complex_abs() is probably closer to the task requirement in that if complex.e is not included it will not be found/called.<br> |
|||
In this case it happens to give exactly the same result, however under the hood it is first promoting the -42 to -42+0i before returning sqrt((-42)*(-42)+(0)*(0)). |
|||
There is (as yet) no var_id() builtin, the following is a quick cobbling-together of code from builtins\VM\prtnidN.e (routine_id) |
|||
and builtins\VM\pDiagN.e (ex.err file creation), not very pretty but it seems to work, and of course all this sort of stuff is |
|||
normally hidden away out of sight in builtins\VM. |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins<span style="color: #0000FF;">/<span style="color: #000000;">VM<span style="color: #0000FF;">/<span style="color: #000000;">pStack<span style="color: #0000FF;">.<span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- :%opGetST |
|||
-- copies from pglobals.e:</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">S_Name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- const/var/rtn name</span> |
|||
<span style="color: #000000;">S_NTyp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- Const/GVar/TVar/Nspc/Type/Func/Proc</span> |
|||
<span style="color: #000000;">S_FPno</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">3<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- File and Path number</span> |
|||
<span style="color: #000000;">S_Slink</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">6<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- scope/secondary chain (see below)</span> |
|||
<span style="color: #000000;">S_vtype</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">7<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- variable type or namespace fileno</span> |
|||
<span style="color: #000000;">S_GVar2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- global or static variable</span> |
|||
<span style="color: #000000;">T_int</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1<span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">T_EBP</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">22<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- compiled/listing=0, interpreted={ebp4,esp4,sym4} (set at last possible moment)</span> |
|||
<span style="color: #000000;">T_ds4</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">23</span> <span style="color: #000080;font-style:italic;">-- compiled = start of data section, same but /4 when interpreted ([T_EBP]!=0)</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">var_id<span style="color: #0000FF;">(<span style="color: #004080;">object</span> <span style="color: #000000;">s<span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- hacked copy of routine_id(), for local file-level integers only</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">res<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- symidx for string s, else sum(local gvar integers)</span> |
|||
<span style="color: #000000;">rtn<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- routine number of callee, from callstack</span> |
|||
<span style="color: #000000;">cFno<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- calling fileno.</span> |
|||
<span style="color: #000000;">tidx<span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">ds4</span> |
|||
<span style="color: #004080;">object</span> <span style="color: #000000;">symtab<span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">si<span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- copy of symtab[i], speedwise</span> |
|||
<span style="color: #000000;">si_name</span> <span style="color: #000080;font-style:italic;">-- copy of symtab[i][S_name], speedwise/thread-sfaety |
|||
-- get copy of symtab. NB read only! may contain nuts! (unassigned vars)</span> |
|||
<span style="color: #000000;">enter_cs<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;"> #ilASM{ |
|||
[32] |
|||
lea edi,[symtab] |
|||
call :%opGetST -- [edi]=symtab (ie our local:=the real symtab) |
|||
mov edi,[ebp+20] -- prev_ebp |
|||
mov edi,[edi+8] -- calling routine no |
|||
mov [rtn],edi |
|||
[64] |
|||
lea rdi,[symtab] |
|||
call :%opGetST -- [rdi]=symtab (ie our local:=the real symtab) |
|||
mov rdi,[rbp+40] -- prev_ebp |
|||
mov rdi,[rdi+16] -- calling routine no |
|||
mov [rtn],rdi |
|||
[] |
|||
}</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">symtab<span style="color: #0000FF;">[<span style="color: #000000;">T_EBP<span style="color: #0000FF;">]<span style="color: #0000FF;">=<span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- compiled</span> |
|||
<span style="color: #000000;">ds4</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor<span style="color: #0000FF;">(<span style="color: #000000;">symtab<span style="color: #0000FF;">[<span style="color: #000000;">T_ds4<span style="color: #0000FF;">]<span style="color: #0000FF;">/<span style="color: #000000;">4<span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">else</span> <span style="color: #000080;font-style:italic;">-- interpreted</span> |
|||
<span style="color: #000000;">ds4</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">symtab<span style="color: #0000FF;">[<span style="color: #000000;">T_ds4<span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">cFno</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">symtab<span style="color: #0000FF;">[<span style="color: #000000;">rtn<span style="color: #0000FF;">]<span style="color: #0000FF;">[<span style="color: #000000;">S_FPno<span style="color: #0000FF;">]</span> <span style="color: #000080;font-style:italic;">-- fileno of callee (whether routine or toplevel)</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff<span style="color: #0000FF;">(<span style="color: #000000;">s<span style="color: #0000FF;">=<span style="color: #000000;">0<span style="color: #0000FF;">?<span style="color: #000000;">0<span style="color: #0000FF;">:<span style="color: #0000FF;">-<span style="color: #000000;">1<span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i<span style="color: #0000FF;">=<span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length<span style="color: #0000FF;">(<span style="color: #000000;">symtab<span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">si</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">symtab<span style="color: #0000FF;">[<span style="color: #000000;">i<span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #004080;">sequence<span style="color: #0000FF;">(<span style="color: #000000;">si<span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">and</span> <span style="color: #000000;">si<span style="color: #0000FF;">[<span style="color: #000000;">S_NTyp<span style="color: #0000FF;">]<span style="color: #0000FF;">=<span style="color: #000000;">S_GVar2</span> |
|||
<span style="color: #008080;">and</span> <span style="color: #000000;">si<span style="color: #0000FF;">[<span style="color: #000000;">S_FPno<span style="color: #0000FF;">]<span style="color: #0000FF;">=<span style="color: #000000;">cFno</span> |
|||
<span style="color: #008080;">and</span> <span style="color: #000000;">si<span style="color: #0000FF;">[<span style="color: #000000;">S_vtype<span style="color: #0000FF;">]<span style="color: #0000FF;">=<span style="color: #000000;">T_int</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">si_name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">si<span style="color: #0000FF;">[<span style="color: #000000;">S_Name<span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">s<span style="color: #0000FF;">=<span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000080;font-style:italic;">-- cut-down version of pDiagN.e/getGvarValue():</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">gidx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">si<span style="color: #0000FF;">[<span style="color: #000000;">S_Slink<span style="color: #0000FF;">]<span style="color: #0000FF;">,</span> <span style="color: #000000;">novalue<span style="color: #0000FF;">,</span> <span style="color: #000000;">o</span> |
|||
#ilASM{ |
|||
mov [novalue],0 |
|||
[32] |
|||
mov esi,[ds4] |
|||
mov edx,[gidx] |
|||
shl esi,2 |
|||
mov esi,[esi+edx*4+16] -- ([ds+(gidx+4)*4] == gvar[gidx]) |
|||
cmp esi,h4 |
|||
jl @f |
|||
mov [novalue],1 |
|||
xor esi,esi |
|||
@@: |
|||
mov [o],esi |
|||
[64] |
|||
mov rsi,[ds4] |
|||
mov rdx,[gidx] |
|||
shl rsi,2 |
|||
mov rsi,[rsi+rdx*8+24] -- ([ds+(gidx+3)*8] == gvar[gidx]) |
|||
mov r15,h4 |
|||
cmp rsi,r15 |
|||
jl @f |
|||
mov [novalue],1 |
|||
xor rsi,rsi |
|||
@@: |
|||
mov [o],rsi |
|||
[] |
|||
} |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">novalue</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #0000FF;">?<span style="color: #0000FF;">{<span style="color: #000000;">si_name<span style="color: #0000FF;">,<span style="color: #008000;">"no_value"<span style="color: #0000FF;">}</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">o</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">s<span style="color: #0000FF;">=<span style="color: #000000;">si_name</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span> |
|||
<span style="color: #008080;">exit</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #000000;">si_name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #000000;">si</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #000000;">symtab</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #000000;">leave_cs<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #0000FF;">{<span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">routine_id<span style="color: #0000FF;">(<span style="color: #008000;">"blurgzmp"<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- force symtab name population.. |
|||
-- (alt: see rbldrqd in pDiagN.e)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">bloop</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">5<span style="color: #0000FF;">,</span> |
|||
<span style="color: #000080;font-style:italic;">-- barf, -- triggers {"barf","no_value"}</span> |
|||
<span style="color: #000000;">burp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">35</span> |
|||
<span style="color: #000000;">bloop</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">6</span> |
|||
<span style="color: #000000;">burp</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> |
|||
<span style="color: #0000FF;">?<span style="color: #000000;">var_id<span style="color: #0000FF;">(<span style="color: #008000;">"bloop"<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- >0 === exists</span> |
|||
<span style="color: #0000FF;">?<span style="color: #000000;">var_id<span style="color: #0000FF;">(<span style="color: #008000;">"blooop"<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- -1 === does not exist</span> |
|||
<span style="color: #0000FF;">?<span style="color: #000000;">var_id<span style="color: #0000FF;">(<span style="color: #000000;">0<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- bloop+burp = 42</span> |
|||
<span style="color: #0000FF;">?<span style="color: #000000;">bloop<span style="color: #0000FF;">+<span style="color: #000000;">burp</span> <span style="color: #000080;font-style:italic;">-- "", doh |
|||
<!--</syntaxhighlight>--> |
|||
my @ints = ($_ when Int for PROCESS::.values); |
|||
say "Number of PROCESS vars of type Int: ", +@ints; |
|||
say "PROCESS vars of type Int add up to ", [+] @ints;</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
1257 |
|||
Number of PROCESS vars of type Int: 1 |
|||
-1 |
|||
PROCESS vars of type Int add up to 28785</pre> |
|||
42 |
|||
Obviously Perl 6 doesn't maintain a lot of global integer variables... <tt>:-)</tt> |
|||
42 |
|||
</pre> |
|||
As-is, of course, being integer-only-and-no-routine-level-vars, the above represents very limited practical value. |
|||
Other routines of interest include |
|||
Nevertheless, you can use similar code to access all the variables in any package you like, |
|||
such as the GLOBAL package, which typically has absolutely nothing in it. Since the PROCESS package is even more global than GLOBAL, we used that instead. Go figure... |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">platform<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- WINDOWS=2, LINUX=3</span> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">machine_bits<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- 32 or 64</span> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">machine_word<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- 4 or 8</span> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">include_paths<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- eg {"C:\\Program Files (x86)\\Phix\\builtins\\", |
|||
-- "C:\\Program Files (x86)\\Phix\\builtins\\VM\\", |
|||
-- "C:\\Program Files (x86)\\Phix\\"} |
|||
-- (plus other application-specific directories)</span> |
|||
<span style="color: #0000FF;">?<span style="color: #7060A8;">get_interpreter<span style="color: #0000FF;">(<span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- eg "C:\Program Files (x86)\Phix\p.exe" |
|||
-- or perhaps "/home/pete/phix/p" on Linux |
|||
<!--</syntaxhighlight>--> |
|||
Phix supports the absolute bare minimum use of #ifdef, for compatibility with OpenEuphoria, however it is almost always better |
|||
to use platform() and friends as normal hll code, rather than that sort of language-within-a-language stuff, imnsho, and the |
|||
compiler is pretty good at optimising away most such os-specific tests and whole branches of irrelevant code (see EmitON=0). |
|||
=={{header|Phixmonti}}== |
|||
<syntaxhighlight lang="phixmonti">_version 1.0 < if "Interpreter version is old" else "Last version" endif print</syntaxhighlight> |
|||
The program will not be executed if the variable or function has not been defined. |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
< |
<syntaxhighlight lang="php"><?php |
||
if (version_compare(PHP_VERSION, '5.3.0', '<' )) |
if (version_compare(PHP_VERSION, '5.3.0', '<' )) |
||
Line 1,570: | Line 1,869: | ||
echo(array_sum($GLOBALS) . " is the total of variables in global scope.\n"); |
echo(array_sum($GLOBALS) . " is the total of variables in global scope.\n"); |
||
?></ |
?></syntaxhighlight> |
||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang="picolisp">(unless (>= (version T) (3 0 1)) # Check version (only in the 64-bit version) |
||
(bye) ) |
(bye) ) |
||
Line 1,581: | Line 1,880: | ||
(num? bloop) # When 'bloop' is bound to a number |
(num? bloop) # When 'bloop' is bound to a number |
||
(getd 'abs) # and 'abs' defined as a function |
(getd 'abs) # and 'abs' defined as a function |
||
(println (abs bloop)) ) # then print the absolute value</ |
(println (abs bloop)) ) # then print the absolute value</syntaxhighlight> |
||
=={{header|PL/I}}== |
=={{header|PL/I}}== |
||
===Version 1=== |
===Version 1=== |
||
<syntaxhighlight lang="pl/i"> |
|||
<lang PL/I> |
|||
S = SYSVERSION(); |
S = SYSVERSION(); |
||
if substr(S, 6, 6) < '050000' then |
if substr(S, 6, 6) < '050000' then |
||
do; put skip list ('Version of compiler is too old'); stop; end; |
do; put skip list ('Version of compiler is too old'); stop; end; |
||
</syntaxhighlight> |
|||
</lang> |
|||
===Version 2=== |
===Version 2=== |
||
< |
<syntaxhighlight lang="pl/i">*process source attributes options m or(!); |
||
/********************************************************************* |
/********************************************************************* |
||
* 02-11.2013 Walter Pachl |
* 02-11.2013 Walter Pachl |
||
Line 1,612: | Line 1,911: | ||
Else |
Else |
||
Put Skip List('Version is '!!s); |
Put Skip List('Version is '!!s); |
||
End</ |
End</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Version is PL/I for Win* 7.5</pre> |
<pre>Version is PL/I for Win* 7.5</pre> |
||
Line 1,619: | Line 1,918: | ||
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). |
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). |
||
< |
<syntaxhighlight lang="pop11">;;; Exit if version below 15.00 |
||
if pop_internal_version < 150000 then |
if pop_internal_version < 150000 then |
||
sysexit() |
sysexit() |
||
endif;</ |
endif;</syntaxhighlight> |
||
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. |
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. |
||
< |
<syntaxhighlight lang="pop11">;;; We do main task in a procedure |
||
define check_and_call(x, y); |
define check_and_call(x, y); |
||
lvars wx=consword(x), wy=consword(y); |
lvars wx=consword(x), wy=consword(y); |
||
Line 1,642: | Line 1,941: | ||
vars bloop = -5; |
vars bloop = -5; |
||
;;; Now prints 5 |
;;; Now prints 5 |
||
check_and_call('abs' , 'bloop') =></ |
check_and_call('abs' , 'bloop') =></syntaxhighlight> |
||
Note that here bloop is defined as "permanent" variable, Pop11 also have lexical variables which are not available for introspection. |
Note that here bloop is defined as "permanent" variable, Pop11 also have lexical variables which are not available for introspection. |
||
Line 1,652: | Line 1,951: | ||
The compiler directive <code>#COMPILER</code>, introduced with PB/Win 8 and PB/CC <!--uncertain version here--> 4, will fail the compile if the compiler does not match at least one of the listed compilers, and is not at least the (optional) minimum version of that compiler. |
The compiler directive <code>#COMPILER</code>, introduced with PB/Win 8 and PB/CC <!--uncertain version here--> 4, will fail the compile if the compiler does not match at least one of the listed compilers, and is not at least the (optional) minimum version of that compiler. |
||
< |
<syntaxhighlight lang="powerbasic">#COMPILER PBWIN 9 |
||
#COMPILER PBWIN, PBCC 5</ |
#COMPILER PBWIN, PBCC 5</syntaxhighlight> |
||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
< |
<syntaxhighlight lang="powershell"># version is found in $PSVersionTable |
||
if ($PSVersionTable['PSVersion'] -lt '2.0') { |
if ($PSVersionTable['PSVersion'] -lt '2.0') { |
||
exit |
exit |
||
Line 1,669: | Line 1,968: | ||
| Where-Object { $_.Value -is [int] } ` |
| Where-Object { $_.Value -is [int] } ` |
||
| Measure-Object -Sum Value ` |
| Measure-Object -Sum Value ` |
||
| Select-Object Count,Sum</ |
| Select-Object Count,Sum</syntaxhighlight> |
||
=={{header|PureBasic}}== |
=={{header|PureBasic}}== |
||
< |
<syntaxhighlight lang="purebasic">CompilerIf #PB_Compiler_Version<441 |
||
CompilerError "You failed the version check!" |
CompilerError "You failed the version check!" |
||
CompilerEndIf |
CompilerEndIf |
||
Line 1,680: | Line 1,979: | ||
Abs(bloop) |
Abs(bloop) |
||
CompilerEndIf |
CompilerEndIf |
||
CompilerEndIf</ |
CompilerEndIf</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
< |
<syntaxhighlight lang="python"># Checking for system version |
||
import sys |
import sys |
||
major, minor, bugfix = sys.version_info[:3] |
major, minor, bugfix = sys.version_info[:3] |
||
Line 1,704: | Line 2,003: | ||
if defined2('bloop') and defined2('abs') and callable(abs): |
if defined2('bloop') and defined2('abs') and callable(abs): |
||
print abs(bloop)</ |
print abs(bloop)</syntaxhighlight> |
||
You can combine both tests, (But loose sight of which variable in missing/not callable by wrapping the whole function call in a try-except statement: |
You can combine both tests, (But loose sight of which variable in missing/not callable by wrapping the whole function call in a try-except statement: |
||
< |
<syntaxhighlight lang="python">try: |
||
print abs(bloop) |
print abs(bloop) |
||
except (NameError, TypeError): |
except (NameError, TypeError): |
||
print "Something's missing"</ |
print "Something's missing"</syntaxhighlight> |
||
Here is one way to print the sum of all the global integer variables: |
Here is one way to print the sum of all the global integer variables: |
||
< |
<syntaxhighlight lang="python">def sum_of_global_int_vars(): |
||
variables = vars(__builtins__).copy() |
variables = vars(__builtins__).copy() |
||
variables.update(globals()) |
variables.update(globals()) |
||
print sum(v for v in variables.itervalues() if type(v) == int) |
print sum(v for v in variables.itervalues() if type(v) == int) |
||
sum_of_global_int_vars()</ |
sum_of_global_int_vars()</syntaxhighlight> |
||
=={{header|R}}== |
=={{header|R}}== |
||
{{works with|R|2.14.1}} |
{{works with|R|2.14.1}} |
||
<syntaxhighlight lang="r"> |
|||
<lang R> |
|||
if(getRversion() < "2.14.1") |
if(getRversion() < "2.14.1") |
||
{ |
{ |
||
warning("Your version of R is older than 2.14.1") |
warning("Your version of R is older than 2.14.1") |
||
q() # exit R, with the option to cancel |
q() # exit R, with the option to cancel |
||
}</ |
}</syntaxhighlight> |
||
The constants <code>version</code> and <code>R.version</code> give further information about the version that is running. The function <code>R.Version()</code> provides the same information as a list. |
The constants <code>version</code> and <code>R.version</code> give further information about the version that is running. The function <code>R.Version()</code> provides the same information as a list. |
||
We now perform three checks: we want to know if bloop is in the user workspace (global environment), if abs exists somewhere, and if abs is a function. |
We now perform three checks: we want to know if bloop is in the user workspace (global environment), if abs exists somewhere, and if abs is a function. |
||
< |
<syntaxhighlight lang="r">bloop <- -3.4 |
||
if(exists("bloop", envir=globalenv()) && exists("abs") && is.function(abs)) |
if(exists("bloop", envir=globalenv()) && exists("abs") && is.function(abs)) |
||
{ |
{ |
||
abs(bloop) |
abs(bloop) |
||
}</ |
}</syntaxhighlight> |
||
Finally, we count how many integers are in the user workspace, and find their total. Note that a number followed by the letter L is considered to be an integer. See [[Integer_literals#R]] for more information. |
Finally, we count how many integers are in the user workspace, and find their total. Note that a number followed by the letter L is considered to be an integer. See [[Integer_literals#R]] for more information. |
||
< |
<syntaxhighlight lang="r">#Declare some integers |
||
qqq <- 45L |
qqq <- 45L |
||
www <- -3L |
www <- -3L |
||
Line 1,749: | Line 2,048: | ||
the_ints <- mget(varnames[is_int], globalenv()) |
the_ints <- mget(varnames[is_int], globalenv()) |
||
#Add them up |
#Add them up |
||
sum(unlist(the_ints))</ |
sum(unlist(the_ints))</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
The usual hack: |
The usual hack: |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
#lang racket |
#lang racket |
||
(unless (string<=? "5.3" (version)) (error "ancient version")) |
(unless (string<=? "5.3" (version)) (error "ancient version")) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Proper comparison: |
Proper comparison: |
||
<syntaxhighlight lang="racket"> |
|||
<lang Racket> |
|||
(require version/utils) |
(require version/utils) |
||
(unless (version<=? "5.3" (version)) (error "ancient version")) |
(unless (version<=? "5.3" (version)) (error "ancient version")) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>my $bloop = -123; |
|||
if MY::{'$bloop'}.defined and CORE::{'&abs'}.defined { say abs $bloop } |
|||
my @ints = ($_ when Int for PROCESS::.values); |
|||
say "Number of PROCESS vars of type Int: ", +@ints; |
|||
say "PROCESS vars of type Int add up to ", [+] @ints;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>123 |
|||
Number of PROCESS vars of type Int: 1 |
|||
PROCESS vars of type Int add up to 28785</pre> |
|||
Obviously Raku doesn't maintain a lot of global integer variables... <tt>:-)</tt> |
|||
Nevertheless, you can use similar code to access all the variables in any package you like, |
|||
such as the GLOBAL package, which typically has absolutely nothing in it. Since the PROCESS package is even more global than GLOBAL, we used that instead. Go figure... |
|||
=={{header|Raven}}== |
=={{header|Raven}}== |
||
< |
<syntaxhighlight lang="raven">VERSION 0 prefer 20071104 < |
||
if 'version >= 20071104 required' print bye |
if 'version >= 20071104 required' print bye |
||
'bloop' GLOBAL keys in && 'abs' CORE keys in |
'bloop' GLOBAL keys in && 'abs' CORE keys in |
||
if bloop abs print</ |
if bloop abs print</syntaxhighlight> |
||
=={{header|Retro}}== |
=={{header|Retro}}== |
||
This will exit if the |
This will exit if the version is less than 2019.6: |
||
<syntaxhighlight lang="retro">@Version #201906 lt+ &bye if</syntaxhighlight> |
|||
<lang Retro>version ^strings'splitAtChar: . drop toNumber 3 < &bye ifTrue</lang> |
|||
The existence of functions can be checked using '''d:lookup'''. In this, a helper function is provided to improve readability. |
|||
A better way is to check the build number. This will exit if the build is lower than |
|||
the 11.0 release: |
|||
<syntaxhighlight lang="retro"> |
|||
<lang Retro>build toNumber 1309798464 < &bye ifTrue</lang> |
|||
Checks for existence of "bloop" and "n:abs" |
|||
~~~ |
|||
The existance of functions can be checked using find. In this, a helper function is provided to improve readability. |
|||
: executeByName (s-) |
|||
d:lookup [ d:xt fetch ] [ d:class fetch ] bi call ; |
|||
'bloop 'n:abs [ find nip ] bi@ and |
|||
<lang Retro> |
|||
[ 'bloop executeByName 'n:abs executeByName ] if |
|||
( Checks for existance of "bloop" and "abs" ) |
|||
~~~</syntaxhighlight> |
|||
: executeByName ( $- ) |
|||
find drop [ @d->xt ] [ @d->class ] bi withClass ; |
|||
"bloop" "abs" [ find nip ] bi@ and |
|||
[ "bloop" executeByName "abs" executeByName ] ifTrue</lang> |
|||
Retro has no direct way to check for data types of functions. Assuming that a word class is defined for integer variables, we could do something like this: |
Retro has no direct way to check for data types of functions. Assuming that a word class is defined for integer variables, we could do something like this: |
||
<syntaxhighlight lang="retro"> |
|||
<lang Retro> |
|||
#0 #0 [ dup d:class fetch &class:integer eq? [ d:xt fetch + [ n:inc ] dip ] [ drop ] choose ] d:for-each |
|||
</syntaxhighlight> |
|||
</lang> |
|||
After execution the stack will have the number of variables found, and the accumulated sum of their values. |
After execution the stack will have the number of variables found, and the accumulated sum of their values. |
||
Line 1,803: | Line 2,117: | ||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Test to see if the version is at least version 4. |
Test to see if the version is at least version 4. |
||
< |
<syntaxhighlight lang="rexx"> /*output from parse version (almost all REXX versions) */ |
||
/* theREXXinterpreterName level mm Mon yyyy */ |
/* theREXXinterpreterName level mm Mon yyyy */ |
||
parse version . level . |
parse version . level . |
||
if level<4 then exit</ |
if level<4 then exit</syntaxhighlight> |
||
Test to see if the version is at least version 4, another example. |
Test to see if the version is at least version 4, another example. |
||
< |
<syntaxhighlight lang="rexx">parse version x 1 whatLang level dd mon yyyy . |
||
if level<4 then do |
if level<4 then do |
||
say |
say |
||
Line 1,814: | Line 2,128: | ||
say x /*this displays everything.*/ |
say x /*this displays everything.*/ |
||
exit /*or maybe: EXIT 13 */ |
exit /*or maybe: EXIT 13 */ |
||
end</ |
end</syntaxhighlight> |
||
Test to see if the REXX variable "bloop" exists, version 1. |
Test to see if the REXX variable "bloop" exists, version 1. |
||
< |
<syntaxhighlight lang="rexx">if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.'</syntaxhighlight> |
||
Test to see if the REXX variable "bloop" exists, version 2. |
Test to see if the REXX variable "bloop" exists, version 2. |
||
< |
<syntaxhighlight lang="rexx">if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.' |
||
else say 'the "bloop" variable doesn''t exist.'</ |
else say 'the "bloop" variable doesn''t exist.'</syntaxhighlight> |
||
Programming note: note the use of the double apostrophe (<big>''' ' ' '''</big>) which is within a quoted string (with apostrophes) [in the above and below REXX programming examples]. |
Programming note: note the use of the double apostrophe (<big>''' ' ' '''</big>) which is within a quoted string (with apostrophes) [in the above and below REXX programming examples]. |
||
<br>Another test to see if the REXX variable "bloop" exists. |
<br>Another test to see if the REXX variable "bloop" exists. |
||
< |
<syntaxhighlight lang="rexx">bloop=47 |
||
if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.' |
if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.' |
||
else say 'the "bloop" variable doesn''t exist.'</ |
else say 'the "bloop" variable doesn''t exist.'</syntaxhighlight> |
||
In REXX, the ABS function is a built-in function (BIF). |
In REXX, the ABS function is a built-in function (BIF). |
||
< |
<syntaxhighlight lang="rexx">bloop=47 |
||
g=abs(bloop)</ |
g=abs(bloop)</syntaxhighlight> |
||
However, most REXX interpreters will allow this type of test: |
However, most REXX interpreters will allow this type of test: |
||
< |
<syntaxhighlight lang="rexx">if testxyz() then say 'function XYZ not found.' |
||
else say 'function XYZ was found.' |
else say 'function XYZ was found.' |
||
exit |
exit |
||
Line 1,838: | Line 2,152: | ||
return 0 |
return 0 |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
syntax: return 1</ |
syntax: return 1</syntaxhighlight> |
||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
# Project: Introspection |
# Project: Introspection |
||
Line 1,873: | Line 2,187: | ||
func abs(bloop) |
func abs(bloop) |
||
return fabs(bloop) |
return fabs(bloop) |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 1,882: | Line 2,196: | ||
Function 'abc' is not defined |
Function 'abc' is not defined |
||
</pre> |
</pre> |
||
=={{header|RPL}}== |
|||
{{works with|HP|49}} |
|||
≪ '''IF''' VERSION DROP DUP SIZE DUP 3 - SWAP SUB STR→ 2.15 < |
|||
'''THEN''' "Too old RPL version" |
|||
'''ELSE''' |
|||
'<span style="color:green">BLOOP</span>' |
|||
'''IFERR''' RCL |
|||
'''THEN''' ": variable not defined" + |
|||
'''ELSE''' |
|||
ABS |
|||
'''IF''' DUP TYPE 6 == |
|||
'''THEN''' ": function not defined" + NIP |
|||
'''END''' |
|||
'''END''' |
|||
'''END''' |
|||
≫ '<span style="color:blue">INTROSP</span>' STO |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="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)</syntaxhighlight> |
||
'''Extra credit:''' |
'''Extra credit:''' |
||
< |
<syntaxhighlight lang="ruby">def variable_counter(b) |
||
int_vars = [] |
int_vars = [] |
||
sum = 0 |
sum = 0 |
||
Line 1,910: | Line 2,241: | ||
a_float = 3.14 |
a_float = 3.14 |
||
variable_counter(binding)</ |
variable_counter(binding)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,923: | Line 2,254: | ||
Note: The warning is because it accessed the global variable which was made invalid.<br> |
Note: The warning is because it accessed the global variable which was made invalid.<br> |
||
The meaning of these variables can be found many places, including [http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Variables_and_Constants here]. |
The meaning of these variables can be found many places, including [http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Variables_and_Constants here]. |
||
=={{header|Rust}}== |
|||
Checking for the Rust compiler version can be done using external crates, for example using the rustc_version crate. Simply add the rustc_version dependency into your cargo.toml file under the dependencies: |
|||
<syntaxhighlight lang="toml"> |
|||
[dependencies] |
|||
rustc_version = "0.4" |
|||
</syntaxhighlight> |
|||
Then we can write code that can check the rust compiler channel, the rust compiler version and check for a minimum version of the rust compiler: |
|||
<syntaxhighlight lang="rust"> |
|||
use rustc_version::{version_meta, Channel, version, Version}; |
|||
fn main() { |
|||
// We can check the Rust channel currently being used: stable, nightly, etc. |
|||
match version_meta().unwrap().channel { |
|||
Channel::Stable => { |
|||
println!("Rust Stable"); |
|||
} |
|||
Channel::Beta => { |
|||
println!("Rust Beta"); |
|||
} |
|||
Channel::Nightly => { |
|||
println!("Rust Nightly"); |
|||
} |
|||
Channel::Dev => { |
|||
println!("Rust Dev"); |
|||
} |
|||
} |
|||
// We can print the Rust compiler version |
|||
println!("{}",version().unwrap()); |
|||
// We can check for a minimum Rust compiler version |
|||
if version().unwrap() >= Version::parse("1.50.0").unwrap() { |
|||
println!("Rust compiler version is ok."); |
|||
} else { |
|||
eprintln!("Rust compiler version is too old. Please update to a more recent version."); |
|||
std::process::exit(1); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
When running the code using the stable Rust compiler version 1.71.1 it results in: |
|||
<pre> |
|||
Rust Stable |
|||
1.74.1 |
|||
Rust compiler version is ok. |
|||
</pre> |
|||
There are currently no runtime capabilities built into the Rust compiler for checking whether individual variables or individual functions have been declared. Some crates offer specialized, limited and experimental reflection capabilities; for example for introspecting struct fields we can use the crates introspection or bevy_reflect. Macros and build scripts can also be leveraged as a current workaround for specific and limited scenarios. |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
< |
<syntaxhighlight lang="scala">object VersCheck extends App { |
||
val minimalVersion = 1.7 |
val minimalVersion = 1.7 |
||
Line 1,933: | Line 2,318: | ||
val bloop = Option(-42) |
val bloop = Option(-42) |
||
if (bloop.isDefined) bloop.get.abs |
if (bloop.isDefined) bloop.get.abs |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Slate}}== |
=={{header|Slate}}== |
||
No version string included inside the system presently. |
No version string included inside the system presently. |
||
< |
<syntaxhighlight lang="slate">Platform run: StartupArguments first ; ' --version'.</syntaxhighlight> |
||
< |
<syntaxhighlight lang="slate">(lobby hasSlotNamed: #bloop) /\ [(#abs findOn: {lobby bloop}) isNotNil] ifTrue: [inform: bloop abs printString]. |
||
lobby slotValues inject: 0 into: [| :sum :value | (value is: Integer) ifTrue: [sum + value] ifFalse: [sum]].</ |
lobby slotValues inject: 0 into: [| :sum :value | (value is: Integer) ifTrue: [sum + value] ifFalse: [sum]].</syntaxhighlight> |
||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
{{works with|GNU Smalltalk}} |
{{works with|GNU Smalltalk}} |
||
< |
<syntaxhighlight lang="smalltalk">| s v t sum hm | |
||
"uncomment the following to see what happens if bloop exists" |
"uncomment the following to see what happens if bloop exists" |
||
"Smalltalk at: #bloop put: -10." |
"Smalltalk at: #bloop put: -10." |
||
Line 1,980: | Line 2,366: | ||
] . |
] . |
||
Transcript show: 'Num of global numeric vars: '; show: (hm printString); cr ; |
Transcript show: 'Num of global numeric vars: '; show: (hm printString); cr ; |
||
show: 'Sum of global numeric vars: '; show: (sum printString) ; cr.</ |
show: 'Sum of global numeric vars: '; show: (sum printString) ; cr.</syntaxhighlight> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
< |
<syntaxhighlight lang="tcl">package require Tcl 8.4 ; # throws an error if older |
||
if {[info exists bloop] && [llength [info functions abs]]} { |
if {[info exists bloop] && [llength [info functions abs]]} { |
||
puts [expr abs($bloop)] |
puts [expr abs($bloop)] |
||
}</ |
}</syntaxhighlight> |
||
'''Extra credit:''' |
'''Extra credit:''' |
||
< |
<syntaxhighlight lang="tcl">namespace eval ::extra_credit { |
||
variable sum_global_int 0 |
variable sum_global_int 0 |
||
variable n_global_int 0 |
variable n_global_int 0 |
||
Line 2,002: | Line 2,388: | ||
puts "number of global ints = $n_global_int" |
puts "number of global ints = $n_global_int" |
||
puts "their sum = $sum_global_int" |
puts "their sum = $sum_global_int" |
||
}</ |
}</syntaxhighlight> |
||
=={{header|TI-89 BASIC}}== |
=={{header|TI-89 BASIC}}== |
||
< |
<syntaxhighlight lang="ti89b">() |
||
Prgm |
Prgm |
||
Local l, i, vers |
Local l, i, vers |
||
Line 2,029: | Line 2,415: | ||
© There is no way to get a list of global variables. |
© There is no way to get a list of global variables. |
||
EndPrgm</ |
EndPrgm</syntaxhighlight> |
||
=={{header|Toka}}== |
=={{header|Toka}}== |
||
Line 2,036: | Line 2,422: | ||
Starting with Release 1.1, Toka allows for checking the version number: |
Starting with Release 1.1, Toka allows for checking the version number: |
||
< |
<syntaxhighlight lang="toka">VERSION 101 > [ bye ] ifFalse</syntaxhighlight> |
||
Release 1.0 can be detected by doing: |
Release 1.0 can be detected by doing: |
||
< |
<syntaxhighlight lang="toka">` VERSION FALSE = [ bye ] ifTrue</syntaxhighlight> |
||
Basic introspection is possible via '''`''' |
Basic introspection is possible via '''`''' |
||
< |
<syntaxhighlight lang="toka">` bloop FALSE <> ` abs FALSE <> and [ ` bloop invoke @ ` abs invoke ] ifTrue</syntaxhighlight> |
||
=={{header|UNIX Shell}}== |
=={{header|UNIX Shell}}== |
||
{{works with|ksh93}} |
{{works with|ksh93}} |
||
There's no way to introspect the builtin arithmetic functions. We'll just try it and see if there's an error. |
There's no way to introspect the builtin arithmetic functions. We'll just try it and see if there's an error. |
||
< |
<syntaxhighlight lang="bash">case ${.sh.version} in |
||
*93[[:alpha:]]+*) :;; #this appears to be ksh93, we're OK |
*93[[:alpha:]]+*) :;; #this appears to be ksh93, we're OK |
||
*) echo "version appears to be too old" |
*) echo "version appears to be too old" |
||
Line 2,070: | Line 2,456: | ||
done |
done |
||
print "${int_vars[*]}" |
print "${int_vars[*]}" |
||
print -- $sum</ |
print -- $sum</syntaxhighlight> |
||
{{works with|bash}} |
{{works with|bash}} |
||
bash does not have a builtin math function "abs" -- we'll check for a user-defined shell function instead. |
bash does not have a builtin math function "abs" -- we'll check for a user-defined shell function instead. |
||
< |
<syntaxhighlight lang="bash">if [[ $BASH_VERSION < "4.2" ]]; then |
||
echo "version is too old" |
echo "version is too old" |
||
exit |
exit |
||
Line 2,099: | Line 2,485: | ||
echo "${int_vars[*]}" |
echo "${int_vars[*]}" |
||
echo $sum |
echo $sum |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Ursala}}== |
=={{header|Ursala}}== |
||
Line 2,124: | Line 2,510: | ||
1 by the time it's displayed. |
1 by the time it's displayed. |
||
< |
<syntaxhighlight lang="ursala">#import std |
||
#import flo |
#import flo |
||
#import lag |
#import lag |
||
Line 2,136: | Line 2,522: | ||
#cast %e |
#cast %e |
||
bloop = -1.</ |
bloop = -1.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1.000000e+00</pre> |
<pre>1.000000e+00</pre> |
||
Line 2,146: | Line 2,532: | ||
To determine the version of the environment -- typically meaning which version of Microsoft Office is running -- the <code>Application</code> object has a <code>Version</code> property: |
To determine the version of the environment -- typically meaning which version of Microsoft Office is running -- the <code>Application</code> object has a <code>Version</code> property: |
||
< |
<syntaxhighlight lang="vb">If Application.Version < 15 Then Exit Sub</syntaxhighlight> |
||
=={{header|Wren}}== |
|||
{{libheader|Wren-pattern}} |
|||
{{libheader|Wren-math}} |
|||
Note that: |
|||
* Wren doesn't have reflection as such but is able to obtain and analyze the running script's source code. It is assumed for this purpose that the latter is sensibly formatted - only global declarations are not indented. |
|||
* Wren is dynamically typed and has a Num type but not an integer type. As far as the extra credit is concerned, the simplifying assumption has been made that a global variable is an integer if it's assigned an integer literal when it's declared. |
|||
<syntaxhighlight lang="wren">import "os" for Platform, Process |
|||
import "io" for File |
|||
import "meta" for Meta |
|||
import "./pattern" for Pattern |
|||
import "./math" for Nums |
|||
var a = 4 /* 1st integer variable */ |
|||
var b = 0xA /* 2nd integer variable */ |
|||
var c = -8 /* 3rd integer variable */ |
|||
var bloop = -17.3 |
|||
var checkVersion = Fn.new { |
|||
var version = Process.version |
|||
var components = version.split(".") |
|||
if (Num.fromString(components[1]) < 4) { |
|||
Fiber.abort("Wren version (%(version)) is too old.") |
|||
} |
|||
} |
|||
var globalIntVars = Fn.new { |
|||
var sep = Platform.isWindows ? "\r\n" : "\n" |
|||
var lines = File.read(Process.allArguments[1]).split(sep) |
|||
var p = Pattern.new("var+1/s[+1/x]+1/s/=+1/s[0x+1/h|~-+1/d]+0/s", Pattern.whole) |
|||
var q = Pattern.new("[////|//*]+0/z", Pattern.end) |
|||
var vars = [] |
|||
var vals = [] |
|||
for (line in lines) { |
|||
line = q.replaceAll(line, "") // get rid of any comments |
|||
var m = p.find(line) |
|||
if (m) { |
|||
vars.add(m.capsText[0]) |
|||
vals.add(Num.fromString(m.capsText[1])) |
|||
} |
|||
} |
|||
return [vars, vals] |
|||
} |
|||
checkVersion.call() |
|||
var res = globalIntVars.call() |
|||
var d |
|||
Meta.eval("d = bloop.abs") // this won't compile if either 'bloop' or 'abs' not available |
|||
System.print("bloop.abs = %(d)") |
|||
var vars = res[0] |
|||
var vals = res[1] |
|||
System.print("The sum of the %(vars.count) integer variables, %(vars), is %(Nums.sum(vals))")</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
bloop.abs = 17.3 |
|||
The sum of the 3 integer variables, [a, b, c], is 6 |
|||
</pre> |
|||
=={{header|Yabasic}}== |
=={{header|Yabasic}}== |
||
< |
<syntaxhighlight lang="yabasic">if peek("version") < 2.63 error "Interpreter version is too old!"</syntaxhighlight> |
||
=={{header|Zig}}== |
|||
'''Works with:''' 0.10.1, 0.11.0, 0.12.0-dev.1577+9ad03b628 |
|||
Note that errors for compiler version check and @hasDecl/@hasField are usually reported at comptime via @compileError, not at runtime, but for demonstrating purposes output is moved to runtime (introspection is still at comptime). |
|||
<syntaxhighlight lang="zig">const std = @import("std"); |
|||
const builtin = @import("builtin"); |
|||
pub const bloop: i32 = -1_000; |
|||
pub fn abs(a: i32) i32 { |
|||
return if (a < 0) -a else a; |
|||
} |
|||
pub fn main() error{NotSupported}!void { |
|||
if (builtin.zig_version.order(.{ .major = 0, .minor = 11, .patch = 0 }) == .lt) { |
|||
std.debug.print("Version {any} is less than 0.11.0, not suitable, exiting!\n", .{builtin.zig_version}); |
|||
return error.NotSupported; |
|||
} else { |
|||
std.debug.print("Version {any} is more or equal than 0.11.0, suitable, continuing!\n", .{builtin.zig_version}); |
|||
} |
|||
if (@hasDecl(@This(), "bloop") and @hasDecl(@This(), "abs")) { |
|||
std.debug.print("abs(bloop) = {d}\n", .{abs(bloop)}); |
|||
} else { |
|||
std.debug.print("abs and/or bloop are not defined!\n", .{}); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out|case=Zig version 0.10.1}} |
|||
<pre> |
|||
Version 0.10.1 is less than 0.11.0, not suitable, exiting! |
|||
error: NotSupported |
|||
src/instrospection.zig:13:9: 0x211a1e in main (instrospection) |
|||
return error.NotSupported; |
|||
^ |
|||
</pre> |
|||
{{out|case=Zig version 0.11.0}} |
|||
<pre> |
|||
Version 0.11.0 is more or equal than 0.11.0, suitable, continuing! |
|||
abs(bloop) = 1000 |
|||
</pre> |
|||
{{out|case=Zig version 0.12.0-dev.1577+9ad03b628}} |
|||
<pre> |
|||
Version 0.12.0-dev.1577+9ad03b628 is more or equal than 0.11.0, suitable, continuing! |
|||
abs(bloop) = 1000 |
|||
</pre> |
|||
===Extra credit=== |
|||
<syntaxhighlight lang="zig">const std = @import("std"); |
|||
pub const first_integer_constant: i32 = 5; |
|||
pub const second_integer_constant: i32 = 3; |
|||
pub const third_integer_constant: i32 = -2; |
|||
pub const some_non_integer_constant: f32 = 0.0; |
|||
pub const another_non_integer_constant: bool = false; |
|||
pub fn main() void { |
|||
comptime var cnt: comptime_int = 0; |
|||
comptime var sum: comptime_int = 0; |
|||
inline for (@typeInfo(@This()).Struct.decls) |decl_info| { |
|||
const decl = @field(@This(), decl_info.name); |
|||
switch (@typeInfo(@TypeOf(decl))) { |
|||
.Int, .ComptimeInt => { |
|||
sum += decl; |
|||
cnt += 1; |
|||
}, |
|||
else => continue, |
|||
} |
|||
} |
|||
@compileLog(std.fmt.comptimePrint("cnt = {d}, sum = {d}", .{ cnt, sum })); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
src/instrospection.zig:24:5: error: found compile log statement |
|||
@compileLog(std.fmt.comptimePrint("cnt = {d}, sum = {d}", .{ cnt, sum })); |
|||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
Compile Log Output: |
|||
@as(*const [16:0]u8, "cnt = 3, sum = 6") |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
< |
<syntaxhighlight lang="zkl">Language.version //-->L(1,12,8,"2014-04-01") |
||
if (Language.version[1] < 10) System.exit("Too old"); |
if (Language.version[1] < 10) System.exit("Too old"); |
||
var bloop=-123; |
var bloop=-123; |
||
if ((1).resolve("abs",1) and resolve("bloop",8)) bloop.abs().println()</ |
if ((1).resolve("abs",1) and resolve("bloop",8)) bloop.abs().println()</syntaxhighlight> |
||
{{out}}<pre>123</pre> |
{{out}}<pre>123</pre> |
||
The concept of global vars doesn't really exist, only instance data. |
The concept of global vars doesn't really exist, only instance data. |
||
<lang>var n=3, x=1.0, a=5, z="zoo"; |
<syntaxhighlight lang="zkl">var n=3, x=1.0, a=5, z="zoo"; |
||
self.vars; --> L(L("a",5),L("n",3),L("x",1),L("z","zoo")) |
self.vars; --> L(L("a",5),L("n",3),L("x",1),L("z","zoo")) |
||
sum:=self.vars.reduce(fcn(p,[(nm,v)],r){ |
sum:=self.vars.reduce(fcn(p,[(nm,v)],r){ |
||
if((1).isType(v)){r.inc();p+v;} else p},0,num:=Ref(0)); |
if((1).isType(v)){r.inc();p+v;} else p},0,num:=Ref(0)); |
||
println("Num int vars = ",num.value,". Sum = ",sum);</ |
println("Num int vars = ",num.value,". Sum = ",sum);</syntaxhighlight> |
||
{{out}}<pre>Num int vars = 2. Sum = 8</pre> |
{{out}}<pre>Num int vars = 2. Sum = 8</pre> |
||
=={{header|ZX Spectrum Basic}}== |
=={{header|ZX Spectrum Basic}}== |
||
< |
<syntaxhighlight lang="zxbasic">10 LET totram=PEEK 23732 + 256 * PEEK 23733: REM Check that we have a 48k machine |
||
20 IF totram < 65535 THEN PRINT "Your 16k Spectrum is too old": STOP |
20 IF totram < 65535 THEN PRINT "Your 16k Spectrum is too old": STOP |
||
30 REM variables must exist before they are used, otherwise we get an error |
30 REM variables must exist before they are used, otherwise we get an error |
||
Line 2,173: | Line 2,708: | ||
50 REM I haven't implemented this, because I have forgotten the handler address |
50 REM I haven't implemented this, because I have forgotten the handler address |
||
60 LET bloob = -4: REM make sure bloob exists, by creating it. |
60 LET bloob = -4: REM make sure bloob exists, by creating it. |
||
70 PRINT ABS(bloob): REM function will be present, ZX Spectrum Basic is standardized.</ |
70 PRINT ABS(bloob): REM function will be present, ZX Spectrum Basic is standardized.</syntaxhighlight> |
||
{{omit from|6502 Assembly|(1) depends on the hardware, (2) variable names don't exist at runtime, (3) everything is global scope.}} |
|||
{{omit from|68000 Assembly|See 6502 Assembly.}} |
|||
{{omit from|8086 Assembly|See 6502 Assembly.}} |
|||
{{omit from|GUISS}} |
{{omit from|GUISS}} |
||
{{omit from|M4}} |
{{omit from|M4}} |
||
{{omit from|M4}} |
{{omit from|M4}} |
||
{{omit from|ML/I}} |
{{omit from|ML/I}} |
||
{{omit from|Z80 Assembly|See 6502 Assembly.}} |
|||
[[Category:Initialization]] |
[[Category:Initialization]] |
Latest revision as of 21:19, 28 June 2024
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
- 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).
- Extra credit
- Report the number of integer variables in global scope, and their sum.
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:
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;
All Ada compilers recognize obsolete parts of a programs and either automatically recompile them or fail to link the program.
Aikido
The version of the Aikido interpreter is in the global scope variable version. AIkido doesn't have abs
but it does have fabs
. Getting the variables in main involves getting their names and then evaluating them as an expression in order to retrieve their type.
import math
if (version < 144) {
throw "Version of aikido is too old"
}
var bloop = -1.4
// Math package doesn't have 'abs'. We'll use 'fabs' instead.
if ("fabs" in Math) {
if ("bloop" in main) {
println ("fabs(bloop) is " + eval ("Math.fabs(bloop)"))
}
}
var x = 104
var y = 598
var z = "hello"
var a = 1234
function count_ints {
// there are builtin integer variables that we don't want to count. There are
// 3 of them
var intcount = 0
// map of builtin variables we want to ignore
var ignore = {"version":true, "int":true, "integer":true}
var sum = 0
// the 'split' function can be used to split a block into a vector of the names
// of the variables within it
foreach v split (main, 0) {
var varname = v
try {
var value = eval (varname)
if (typeof(value) == "integer") {
if (varname in ignore) {
continue
}
intcount++
sum += value
}
} catch (e) {
// ignore exception
}
}
println ("There are " + intcount + " integer variables in the global scope")
println ("Their sum is " + sum)
}
count_ints()
Here is the result:
fabs(bloop) is 1.4 There are 3 integer variables in the global scope Their sum is 1936
ALGOL 68
ALGOL 68 doesn't allow you to ask about compiler versions, but you can use constants specifying parameters of the target, such as the range of the standard integer type, or the precision of the standard floating point type.
Also: The constant(s) int lengths (real lengths) is the number (+1) of long precision types of int (reals) available at run time.
BEGIN
print (("Integer range: ", -max int, " .. ", max int, new line));
print (("Integer digits: ", int width, new line));
print (("Float range: ", -max real, " .. ", max real, new line));
print (("Float digits: ", real width, new line))
END
- Output:
Integer range: -2147483647 .. +2147483647 Integer digits: +10 Float range: -1.79769313486235e+308 .. +1.79769313486235e+308 Float digits: +15
The types of a value can also - crudely - be determined at run time. This is most useful for ALGOL 68's tagged unions, but it can also be used on any value. Note also that if a type is unioned with a void, then the empty value can be set to indicate that a variable has not been formally initialised to a value.
The following code demonstrates tagged-union introspection:
BEGIN
MODE SSMODES = UNION(SHORT SHORT BITS, SHORT SHORT BYTES, #SHORT SHORT CHAR,#
SHORT SHORT INT, SHORT SHORT REAL, SHORT SHORT COMPL);
MODE SMODES = UNION(SHORT BITS, SHORT BYTES, #SHORT CHAR,#
SHORT INT, SHORT REAL, SHORT COMPL);
MODE NMODES = UNION(BITS, BYTES, CHAR, INT, REAL, COMPL);
MODE LMODES = UNION(LONG BITS, LONG BYTES, #LONG CHAR,#
LONG INT, LONG REAL, LONG COMPL);
MODE LLMODES = UNION(LONG LONG BITS, LONG LONG BYTES, #LONG LONG CHAR,#
LONG LONG INT, LONG LONG REAL, LONG LONG COMPL);
MODE XMODES = UNION(BOOL, SEMA, STRING, VOID, CHANNEL, FILE, FORMAT);
MODE MODES = UNION(SSMODES, SMODES, NMODES, LLMODES, LMODES, XMODES);
OP REPRTYPEOF = (MODES val)STRING:
CASE val IN
(VOID):"VOID",
(INT):"INT",(SHORT INT):"SHORT INT",(SHORT SHORT INT):"SHORT SHORT INT",
(LONG INT):"LONG INT",(LONG LONG INT):"LONG LONG INT",
(REAL):"REAL",(SHORT REAL):"SHORT REAL",(SHORT SHORT REAL):"SHORT SHORT REAL",
(LONG REAL):"LONG REAL",(LONG LONG REAL):"LONG LONG REAL",
(COMPL):"COMPL",(SHORT COMPL):"SHORT COMPL",(SHORT SHORT COMPL):"SHORT SHORT COMPL",
(LONG COMPL):"LONG COMPL",(LONG LONG COMPL):"LONG LONG COMPL",
(BITS):"BITS",(SHORT BITS):"SHORT BITS",(SHORT SHORT BITS):"SHORT SHORT BITS",
(LONG BITS):"LONG BITS",(LONG LONG BITS):"LONG LONG BITS",
(BYTES):"BYTES",(SHORT BYTES):"SHORT BYTES",(SHORT SHORT BYTES):"SHORT SHORT BYTES",
(LONG BYTES):"LONG BYTES",(LONG LONG BYTES):"LONG LONG BYTES",
(CHAR):"CHAR",#(SHORT CHAR):"SHORT CHAR",(SHORT SHORT CHAR):"SHORT SHORT CHAR",
(LONG CHAR):"LONG CHAR",(LONG LONG CHAR):"LONG LONG CHAR",#
(BOOL):"BOOL",
(STRING):"STRING",
(SEMA):"SEMA",
(CHANNEL):"CHANNEL",
(FILE):"FILE",
(FORMAT):"FORMAT"
OUT
"ARRAY, PROC or STRUCT"
ESAC;
[]MODES x = (EMPTY, 1, 2.0, 3I4, SHORT SHORT 5, SHORT 6, LONG 7, LONG LONG 8,
8r666, bytes pack("abc"), TRUE, "xyz", LEVEL 1,
stand in channel, stand in, $ddd$);
STRING sep := "";
print(("Array member types: "));
FOR i TO UPB x DO
print((sep,REPRTYPEOF x[i]));
sep := ", "
OD
END
- Output:
Array member types: VOID, INT, REAL, COMPL, INT, INT, LONG INT, LONG LONG INT, BITS, BYTES, BOOL, STRING, SEMA, CHANNEL, FILE, FORMAT
User defined "typeof" operator:
Algol68 permits the use of "operator overloading" over different types of variables. Hence the user is able to define their own introspecting "typeof" operator.
File: Typeof_operator.a68
#!/usr/local/bin/a68g --script #
OP TYPEOF = (INT skip)STRING: "INT";
OP TYPEOF = (CHAR skip)STRING: "CHAR";
OP TYPEOF = (REAL skip)STRING: "REAL";
OP TYPEOF = (COMPL skip)STRING: "COMPL";
printf(($g" "$,TYPEOF 1, TYPEOF "x", TYPEOF pi, TYPEOF (0 I 1 ), $l$))
- Output:
INT CHAR REAL COMPL
Array bounds can also be inspected:
File: Introspection_array_bounds.a68
#!/usr/local/bin/a68g --script #
[]INT x = (5,4,3,2,1);
print(("x =", x, new line));
print(("LWB x =", LWB x, ", UPB x = ",UPB x, new line))
- Output:
x = +5 +4 +3 +2 +1 LWB x = +1, UPB x = +5
Arturo
if not? sys\version > 0.9.0 -> panic "version too old!"
bloop: 3 - 5
if? set? 'bloop -> "variable 'bloop' is set"
else -> "variable 'bloop' is not set"
if set? 'abs -> print ["the absolute value of bloop is:" abs bloop]
print [
"The sum of all globally defined integers is:"
sum map select keys symbols 'sym -> integer? var sym
'sym -> var sym
]
- Output:
the absolute value of bloop is: 2 The sum of all globally defined integers is: -2
AutoHotkey
if (A_AhkVersion < "1.0.48.03")
{
MsgBox % "you are using" . A_AhkVersion . "`nplease upgrade to" . "1.0.48.03"
ExitApp
}
bloop = -3
if bloop
if IsFunc("abs")
MsgBox % abs(bloop)
return
AWK
PROCINFO is a gawk-extension
# syntax: GAWK -f INTROSPECTION.AWK
BEGIN {
if (PROCINFO["version"] < "4.1.0") {
print("version is too old")
exit(1)
}
bloop = -1
if (PROCINFO["identifiers"]["abs"] == "user" && bloop != "") {
printf("bloop = %s\n",bloop)
printf("abs(bloop) = %s\n",abs(bloop))
}
exit(0)
}
function abs(x) { if (x >= 0) { return x } else { return -x } }
- Output:
bloop = -1 abs(bloop) = 1
BBC BASIC
IF VAL(FNversion) < 5.94 THEN PRINT "Version is too old" : END
ON ERROR LOCAL PRINT "Variable 'bloop' doesn't exist" : END
test = bloop
RESTORE ERROR
ON ERROR LOCAL PRINT "Function 'FNabs()' is not defined" : END
test = ^FNabs()
RESTORE ERROR
PRINT FNabs(bloop)
END
DEF FNversion
LOCAL F%, V$
F% = OPENOUT(@tmp$+"version.txt")
OSCLI "OUTPUT "+STR$F%
*HELP
*OUTPUT 0
PTR #F% = 0
INPUT #F%,V$
CLOSE #F%
= RIGHT$(V$,5)
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.
#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
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.
C#
There has to be some caveats made with C#. There are no truly "global" variables - just publicly exported ones from individual classes/types. I chose to make a couple of public static variables in my program's class. Also, the "version" of the compiler is difficult to impossible to get at. There are no predefined compiler constants that can be compared against as in C/C++ but then again, it's hardly the thing that counts in C#. What really counts is the version of .NET and the framework you're working with since that determines what C++ features you can use and the various calls that can be made. Consequently, I check the .NET version to make sure it's past 4.0 and exit if not.
using System;
using System.Reflection;
namespace Rosetta_Introspection
{
static public class Program
{
static public int bloop = -10;
static public int bloop2 = -20;
public static void Main()
{
var asm = Assembly.GetExecutingAssembly();
var version = int.Parse(asm.ImageRuntimeVersion.Split('.')[0].Substring(1));
if (version < 4)
{
Console.WriteLine("Get with the program! I'm outta here!");
return;
}
FieldInfo bloopField = null;
foreach (var type in asm.GetExportedTypes())
{
foreach (var field in type.GetFields())
{
if (field.Name != "bloop")
{
continue;
}
bloopField = field;
if (bloopField.FieldType != typeof(int))
{
throw new InvalidProgramException("bloop should be an integer");
}
break;
}
if (bloopField != null)
{
break;
}
}
if (bloopField == null)
{
throw new InvalidProgramException("No bloop exported value");
}
foreach (var refAsm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in refAsm.GetExportedTypes())
{
if (type.Name == "Math")
{
var absMethod = type.GetMethod("Abs", new Type[] { typeof(int) });
if (absMethod != null)
{
Console.WriteLine("bloop's abs value = {0}", absMethod.Invoke(null, new object[] { bloopField.GetValue(null) }));
}
}
}
}
int intCount = 0;
int total = 0;
foreach (var type in asm.GetExportedTypes())
{
foreach (var field in type.GetFields())
{
if (field.FieldType == typeof(int))
{
intCount++;
total += (int)field.GetValue(null);
}
}
}
Console.WriteLine("{0} exported ints which total to {1}", intCount, total);
Console.ReadKey();
}
}
}
- Output:
bloop's abs value = 10 2 exported ints which total to -30
C++
Identifying the version of the C++ standard used by the compiler in C++ is syntactically very similar to the way of checking the C standard version (also seen on this page).
#if !defined(__cplusplus) || __cplusplus < 201103L
#pragma error("The following code requires at least C++11.")
#else
// ...
#endif
As in C, the introspective capabilities of C++ are very limited.
Clojure
Partial answer...
; check Java version
(let [version (Double/parseDouble (re-find #"\d*\.\d*" (System/getProperty "java.version")))]
(if (>= version 1.5)
(println "Version ok")
(throw (Error. "Bad version"))))
; check Clojure version
(let [version (Double/parseDouble (re-find #"\d*\.\d*" (clojure-version)))]
(if (>= version 1.0)
(println "Version ok")
(throw (Error. "Bad version"))))
Common Lisp
(let* ((ver (lisp-implementation-version))
(major (parse-integer ver :start 0 :end (position #\. ver))))
#+lispworks (assert (>= 5 major) () "Requires Lispworks version 5 or above")
#+clisp (assert (>= 2 major) () "Requires CLISP 2.n")
)
(defvar bloop -4)
(if (and (fboundp 'abs)
(boundp 'bloop))
(format t "~d~%" (abs bloop)))
The list-all-packages and do-symbols forms enable a lisp program to examine all symbols and these can be tested to identify integer variables.
(let ((sum 0)
(ints '()))
(loop for pkg in (list-all-packages)
do (do-symbols (s pkg)
(when (and (boundp s)
(integerp (symbol-value s)))
(push s ints)
(incf sum (symbol-value s)))))
(format t "there are ~d integer variables adding up to ~d~%"
(length ints) sum))
D
With extra credit.
// Some module-level variables (D doesn't have a global scope).
immutable x = 3, y = 100, z = 3_000;
short w = 1; // Not an int, must be ignored.
immutable s = "some string"; // Not an int, must be ignored.
void main() {
import std.compiler, std.math, std.traits;
// Compile-time constants of the compiler version:
static assert(version_major > 1 && version_minor > 50,
"I can't cope with this compiler version.");
immutable bloop = 10;
// To check if something compiles:
static if (__traits(compiles, bloop.abs)) {
pragma(msg, "The expression is compilable.");
auto x = bloop.abs;
} else {
pragma(msg, "The expression can't be compiled.");
}
import std.stdio;
immutable s = 10_000; // Not at module scope, must be ignored.
int tot = 0;
/*static*/ foreach (name; __traits(allMembers, mixin(__MODULE__)))
static if (name != "object" &&
is(int == Unqual!(typeof(mixin("." ~ name)))))
tot += mixin("." ~ name);
writeln("Total of the module-level ints (could overflow): ", tot);
}
- Output:
The expression is compilable. Total of the module-level ints (could overflow): 3103
E
Version:
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.)
Existence:
escape fail {
def &x := meta.getState().fetch("&bloop", fn { fail("no bloop") })
if (!x.__respondsTo("abs", 0)) { fail("no abs") }
x.abs()
}
This will return either bloop.abs(), "no bloop", or "no abs".
Sum of integers:
{
var sum := 0
for &x in interp.getTopScope() { sum += try { x :int } catch _ { 0 } }
sum
}
try
rather than an ordinary type check is used because in general a slot might be broken; this way we skip over all read failures as well as non-integers. The block around the code ensures that the sum variable itself will not be involved in the computation.
EchoLisp
(version)
→ EchoLisp - 2.50.3
📗 local-db: db.version: 3
(when (< (version) 2.6)
(writeln "Please reload EchoLisp : CTRL-F5, CMD-R or other...")
(exit))
(if (and (bound? 'bloop) (bound? 'abs) (procedure? abs))
(abs bloop) 'NOT-HERE)
→ NOT-HERE
(define bloop -777)
→ bloop
(if (and (bound? 'bloop) (bound? 'abs) (procedure? abs)) (abs bloop) 'NOT-HERE)
→ 777
(for/sum ((kv (environment-bindings user-initial-environment )))
#:when (integer? (second kv))
(writeln kv)
(second kv))
("bloop" -777)
("gee" 555)
("buzz" 333)
→ 111 ;; sum
Erlang
Erlang does not have global variables so I look for a function bloop/0 that returns an integer. Moreover, I sum the available modules, instead of the unavailable global integers.
-module( introspection ).
-export( [task/0] ).
task() ->
exit_if_too_old( erlang:system_info(otp_release) ),
Bloop = lists:keyfind( bloop, 1, ?MODULE:module_info(functions) ),
Abs = lists:keyfind( abs, 1, erlang:module_info(exports) ),
io:fwrite( "abs( bloop ) => ~p~n", [call_abs_with_bloop(Abs, Bloop)] ),
io:fwrite( "Number of modules: ~p~n", [erlang:length(code:all_loaded())] ).
bloop() -> -1.
call_abs_with_bloop( {abs, 1}, {bloop, 0} ) -> erlang:abs( bloop() );
call_abs_with_bloop( _Missing, _Not_here ) -> abs_and_bloop_missing.
exit_if_too_old( Release ) when Release < "R13A" -> erlang:exit( too_old_release );
exit_if_too_old( _Release ) -> ok.
- Output:
18> introspection:task(). abs( bloop ) => 1 Number of modules: 110
Factor
Check for build number and execute a quotation if it's too old. (There are no such things as versions for Factor yet.)
: if-older ( n true false -- )
[ build > ] 2dip if ; inline
: when-older ( n true -- )
[ ] if-older ; inline
: unless-older ( n false -- )
[ [ ] ] dip if-older ; inline
900 [ "Your version of Factor is too old." print 1 exit ] when-older
It is possible to test if a function or a variable exists (search
), but that shouldn't be used outside of parsing.
"bloop" search [
get [
"abs" search [ execute( n -- n' ) ] when*
] [ 0 ] if*
] [ 0 ] if*
On the other hand, it is possible to search the global namespace for integer variables:
USING: assocs formatting kernel math namespaces ;
0 0
global [
nip dup integer? [ + [ 1 + ] dip ] [ drop ] if
] assoc-each
"There are %d integer variables, the sum is %d\n" printf
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]
4tH is able to fulfill all requirements. Note that since only one variable has been declared, the sum of all integer (user)variables is consequently the value of that variable.
[hex] 362 [decimal] 4TH# - [if] [abort] [then]
-32 value bloop
[defined] bloop [if]
[defined] abs [if]
bloop abs . cr
[then]
[then]
0 last cell+ first over over - .( User variables: ) .
?do i @ + loop .( Sum: ) . cr
- Output:
32 User variables: 1 Sum: -32
FreeBASIC
Version 1:
' FB 1.05.0 Win64
#If __FB_VERSION__ < "1.06.0"
#Error "Compiler version is too old - needs to be 1.06.0 or later"
#EndIf
Dim bloop As Integer = -15
#IfDef bloop
#IfDef Abs
Print "Abs(bloop) = "; Abs(bloop)
#Else
Print "Abs is not available"
#EndIf
#Else
Print "bloop does not exist"
#EndIf
Sleep
- Output:
introspection.bas(4) error: Compiler version is too old - needs to be 1.06.0 or later
Version 2:
' FB 1.05.0 Win64
#If __FB_VERSION__ < "1.05.0" '' version 1.05.0 is now OK
#Error "Compiler version is too old - needs to be 1.05.0 or later"
#EndIf
Dim bloop As Integer = -15
#IfDef bloop
#IfDef Abs
Print "Abs(bloop) = "; Abs(bloop)
#Else
Print "Abs is not available"
#EndIf
#Else
Print "bloop does not exist"
#EndIf
Sleep
- Output:
Abs(bloop) = 15
Version 3 (version code omitted for brevity):
#Undef Abs '' undefine Abs keyword
Dim bloop As Integer = -15
#IfDef bloop
#IfDef Abs
Print "Abs(bloop) = "; Abs(bloop)
#Else
Print "Abs is not available"
#EndIf
#Else
Print "bloop does not exist"
#EndIf
Sleep
- Output:
Abs is not available
Version 4 (version code omitted for brevity):
#Undef Abs '' undefine Abs keyword
'Dim bloop As Integer = -15 '' bloop declaration commented out
#IfDef bloop
#IfDef Abs
Print "Abs(bloop) = "; Abs(bloop)
#Else
Print "Abs is not available"
#EndIf
#Else
Print "bloop does not exist"
#EndIf
Sleep
- Output:
bloop does not exist
Frink
if FrinkVersion[] < "2024-01-01"
{
println["Version of Frink is too old."]
exit[]
}
if isVariableDefined["bloop"]
{
func = getFunction["abs",1]
if func != undef
println[func[bloop]]
}
GAP
# Apply a function to a value, given variable names for both function and value
CheckEval := function(fun, val)
local f, x;
if IsBoundGlobal(fun) and IsBoundGlobal(val) then
f := ValueGlobal(fun);
x := ValueGlobal(val);
return f(x);
fi;
end;
bloop := -1;
CheckEval("AbsInt", "bloop");
# 1
# Sum of integer variables
GlobalIntegers := function()
local s, x, name;
s := 0;
for name in SortedList(NamesGVars()) do
if IsBoundGlobal(name) then
x := ValueGlobal(name);
if IsInt(x) then
Print(name, " ", x, "\n");
s := s + x;
fi;
fi;
od;
return s;
end;
Go
Task variance: "exit if it is too old" is not done here. Go version strings do not present an easily interpreted chronology. This version of the program simply prints the version string.
package main
import (
"debug/elf"
"debug/gosym"
"fmt"
"log"
"math"
"os"
"runtime"
)
var bloop = -3.4
func main() {
fmt.Println("task 1: verify version")
fmt.Println(" program compiled with", runtime.Version())
fmt.Println("task 2: check for presence of variable and function")
// inspect ELF symbol table
f, err := elf.Open(os.Args[0])
if err != nil {
log.Fatal(err)
}
defer f.Close()
symSection := f.Section(".gosymtab")
lineSection := f.Section(".gopclntab")
textSection := f.Section(".text")
if symSection == nil || lineSection == nil || textSection == nil {
log.Fatal("symbolic information not found")
}
symData, err := symSection.Data()
if err != nil {
log.Fatal(err)
}
lineData, err := lineSection.Data()
if err != nil {
log.Fatal(err)
}
table, err := gosym.NewTable(symData,
gosym.NewLineTable(lineData, textSection.Addr))
if err != nil {
log.Fatal(" ", err)
}
var foundBloop, foundFabs bool
for _, s := range table.Syms {
if s.Name == "main.bloop" {
foundBloop = true
fmt.Println(" bloop symbol table entry:", s)
} else if s.Name == "math.Abs" {
foundFabs = true
fmt.Println(" abs symbol table entry:", s)
}
}
if foundBloop && foundFabs {
fmt.Println(" bloop: ", bloop)
fmt.Println(" abs(bloop): ", math.Abs(bloop))
}
}
- Output:
task 1: verify version program compiled with go1.0.2 task 2: check for presence of variable and function bloop symbol table entry: {5468424 68 main.bloop 273827584 <nil>} abs symbol table entry: {4404832 84 math.Abs 943802368 0xf8401fc190} bloop: -3.4 abs(bloop): 3.4
Work to do for extra credit involves not just locating symbols, but decoding the fields of the the symbol table entries. Note that once this is done, the basic task could be improved to compute abs(bloop) by accessing values located from symbol table data only, and the expression math.Abs(bloop) would not have to appear in the source code. This would seem in the spirit of the task.
Haskell
import Data.Version
import Control.Monad
import System.Info
minGHCVersion = Version [6, 8] []
main = when (compilerName == "ghc" && compilerVersion < minGHCVersion) $
fail "Compiler too old."
No means exists of checking whether a variable exists at runtime. The set of variables that exist in any given scope is fixed at compile-time.
Icon and Unicon
global bloop
procedure main(A)
if older(11,7) then stop("Must have version >= 11.7!")
bloop := -5 # global variable
floop := -11.3 # local variable
write(proc("abs")(variable("bloop")))
write(proc("abs")(variable("floop")))
end
procedure older(maj,min)
&version ? {
(tab(find("Version ")),move(*"Version "))
major := 1(tab(upto('.')),move(1))
minor := tab(upto('.'))
return (major < maj) | ((major = maj) & (minor < min))
}
end
Sample run:
->introspect 5 11.3 ->
Inform 7
Inform 7 doesn't have built-in functionality for checking the runtime version number, but the version number is available and can be read by including a snippet of Inform 6 code. The address and format of the version number vary according to the virtual machine being targeted.
Home is a room.
When play begins:
let V be the current runtime version;
if V is less than the required runtime version:
say "Version [required runtime version] required, but [V] found.";
otherwise:
say "Your interpreter claims version [V].";
end the story.
A version is a kind of value.
Section - Checking the version (for Glulx only)
1.255.255 specifies a version with parts major, minor (without leading zeros), and subminor (without leading zeros).
To decide which version is current runtime version: (- (0-->1) -).
To decide which version is required runtime version: decide on 3.1.2.
Section - Checking the version (for Z-machine only)
1.255 specifies a version with parts major and minor (without leading zeros).
To decide which version is current runtime version: (- ($32-->0) -).
To decide which version is required runtime version: decide on 1.1.
It's not possible to check for the existence of functions (invoking a nonexistent phrase causes a compile-time error) or list global variables.
Io
if(System version < 20080000, exit)
if(hasSlot("bloop") and bloop hasSlot("abs"), bloop abs)
Io can also inspect the source code of methods written in Io:
getSlot("arbitraryMethod") code
IS-BASIC
100 IF VERNUM<2.1 THEN PRINT "Version is too old.":STOP
110 WHEN EXCEPTION USE ERROR
120 PRINT ABS(BLOOP)
130 END WHEN
140 HANDLER ERROR
150 PRINT EXSTRING$(EXTYPE)
160 CONTINUE
170 END HANDLER
J
Exit if we're running an old version of J (earlier than version 6, which is current as of this writing), giving version number as the exit status:
6 (2!:55@:]^:>) 0 ". 1 { 9!:14''
Compute abs(bloop) if abs is a function and bloop is data:
".(#~3 0*./ .=4!:0@;:)'abs bloop'
Extra credit: report the number of integer variables in global scope, and their sum:
((],&(+/);@#~)((=<.)@[^:](''-:$)*.0=0{.@#,)&>)".&.>4!:1]0
This last expression is longer than the others, because it has a couple of extra guard checks; in J, the programmer doesn't need to care if the data is a single number or an array, or what hardware representation is used for numbers (32-bit int, IEEE float, etc).
So this expression takes pains to emulate solutions in other languages (i.e. only reports globals that are single numbers, and whose value = floor(value), so that even if the number is represented as a float in the machine, you still get the right answer).
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:
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");
}
}
}
JavaScript
It is generally out of favor to explicitly test versions in JavaScript, due to the immense variety of implementations; instead, one should use “feature testing”, executing code to check for the desired behavior. Checking for “abs” as in this task is an example of feature testing.
Testing whether the variable “bloop” exists:
if (typeof bloop !== "undefined") { ... }
The typeof
operator explicitly does not throw an error when given an undeclared variable.
Test whether Math.abs()
is available:
if ("abs" in Math) { ... }
abs
is a method of the Math object, methods are properties, and the in
operator tests whether an object has the named property.
jq
Works with jq, the C implementation of jq
Works with gojq, the Go implementation of jq
jq's support for introspection is limited. For example, jq's version number is available from the command-line but not as a built-in; and it is not in general possible to check whether a variable has been defined without causing an error. However, jq does make it possible for a program to check whether a variable has been defined globally, so we'll go with that.
Note that jq's `builtins` function provides details about jq's built-in functions, and similarly the `modulemeta` function provides some support for introspection within modules, but otherwise there is no support for determining the functions that have been user-defined.
Assuming JQ has been defined appropriately as a shell variable, one could invoke jq with a global "bloop" variable as follows:
$JQ -n --arg version "$($JQ --version)" --argjson bloop -3 -f introspection.jq
The following program has been tested with recent versions of both jq and gojq, but may fail with earlier versions. Note also that jq's `length` has the semantics of `abs` when applied to numbers, so if your jq does not support `abs` by that name, you could use `length`.
def checkVersion:
$version
| capture("^[^- ]*(?<jq>[- ])(?<major>[0-9]*)[.](?<minor>[0-9]*)") // {jq: 0}
| if .jq == 0 then "unrecognized version identification: \($version)" | error
elif .jq == "-" # jq
and (.major < "1" or (.major == "1" and .minor < "5"))
then "version \($version) is too old" | error
elif .jq == " " # gojq
and (.major == "0" and (.minor | tonumber) < 12)
then "version \($version) is too old" | error
else .
end;
checkVersion
# Check that abs/0 is defined
| (builtins | index("abs/0")) as $ix
| if $ix == null then "abs/0 not available" | error else . end
# Is bloop a global variable?
| if ($ARGS.named | has("bloop")) then $ARGS.named["bloop"] | abs
else "There is no globally defined variable name $bloop." | error
end
Examples:
- Output:
$ gojq -n --arg version "$(gojq --version)" --argjson bloop -3 -f introspection.jq 3 $ jq -n --arg version "$(jq --version)" -f introspection.jq jq: error (at <unknown>): There is no globally defined variable name bloop.
Jsish
/* Introspection, in jsish */
if (Info.version() < Util.verConvert('2.8.6')) {
puts("need at least version 2.8.6 of jsish for this application");
exit(1);
}
/* Check for "abs()" as function and "bloop" as defined value, call if both check true */
if ((bloop != undefined) && (typeof Math.abs == 'function')) {
puts(Math.abs(bloop));
}
/* ECMAScript, this will sum all numeric values, not just strict integers */
var nums = 0, sums = 0, v;
for (v of Info.vars(this)) {
if (isFinite(this[v])) {
nums++;
sums += this[v];
}
}
printf("%d numerics with sum of: %d\n", nums, sums);
- Output:
prompt$ jsish introspection.jsi 2 numerics with sum of: 2
Julia
@show VERSION
VERSION < v"0.4" && exit(1)
if isdefined(Base, :bloop) && !isempty(methods(abs))
@show abs(bloop)
end
a, b, c = 1, 2, 3
vars = filter(x -> eval(x) isa Integer, names(Main))
println("Integer variables: ", join(vars, ", "), ".")
println("Sum of integers in the global scope: ", sum(eval.(vars)), ".")
- Output:
VERSION = v"1.2.0" Integer variables: a, b, c. Sum of integers in the global scope: 6.
Kotlin
We will use Java reflection for this task as Kotlin's own reflection facilities do not appear to be able to deal generically with top-level entities at the present time (i.e. ::class isn't yet supported):
// version 1.0.6 (intro.kt)
import java.lang.reflect.Method
val bloop = -3
val i = 4
val j = 5
val k = 6
fun main(args: Array<String>) {
// get version of JVM
val version = System.getProperty("java.version")
if (version >= "1.6") println("The current JVM version is $version")
else println("Must use version 1.6 or later")
// check that 'bloop' and 'Math.abs' are available
// note that the class created by the Kotlin compiler for top level declarations will be called 'IntroKt'
val topLevel = Class.forName("IntroKt")
val math = Class.forName("java.lang.Math")
val abs = math.getDeclaredMethod("abs", Int::class.java)
val methods = topLevel.getDeclaredMethods()
for (method in methods) {
// note that the read-only Kotlin property 'bloop' is converted to the static method 'getBloop' in Java
if (method.name == "getBloop" && method.returnType == Int::class.java) {
println("\nabs(bloop) = ${abs.invoke(null, method.invoke(null))}")
break
}
}
// now get the number of global integer variables and their sum
var count = 0
var sum = 0
for (method in methods) {
if (method.returnType == Int::class.java) {
count++
sum += method.invoke(null) as Int
}
}
println("\nThere are $count global integer variables and their sum is $sum")
}
- Output:
The current JVM version is 1.8.0_121 abs(bloop) = 3 There are 4 global integer variables and their sum is 12
Lasso
var(bloob = -26)
decimal(lasso_version(-lassoversion)) < 9.2 ? abort
var_defined('bloob') and $bloob -> isa(::integer) and lasso_tagexists('math_abs') ? math_abs($bloob)
-> 26
Lassos equivalence of global variables are thread variables. They have scope that lasts for the entire call in contrast to local variables that are confined to the page or method they are created within.
var(
bloob = -26,
positive = 450
)
local(total = integer)
with v in var_keys
// Lasso creates a number of thread variables that all start with an underscore. We don't want those
where not(string(#v) -> beginswith('_')) and var(#v) -> isa(::integer)
do {
#total += var(#v)
}
#total
-> 424
Lingo
- 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.
put _player.productVersion
-- "11.5.9"
_player.itemDelimiter="."
if integer(_player.productVersion.item[1])<11 then _player.quit()
- check whether the variable "bloop" exists and whether the math-function "abs()" is available and if yes compute abs(bloop).
-- check existence of bloop in local scope
bloopExists = not voidP(value("bloop"))
-- or for global scope:
-- bloopExists = not voidP(_global.bloop)
absExists = value("abs(1)")=1
if bloopExists and absExists then put abs(bloop) -- or abs(_global.bloop)
- Report the number of integer variables in global scope, and their sum.
cnt = 0
sum = 0
repeat with v in the globals
if integerP(v) then
cnt = cnt + 1
sum = sum + v
end if
end repeat
put cnt
put sum
Locomotive Basic
To get the BASIC ROM version number, we need to use a Z80 machine code routine which copies the version number (major/minor/patchlevel) to RAM where BASIC can then read it. Here is the assembly:
org &4000 ; program start address
push bc
push de
push hl
push af
ld bc,&df00 ; select BASIC ROM
out (c),c ; (ROM 0)
ld bc,&7f86 ; make ROM accessible at &c000
out (c),c ; (RAM block 3)
ld hl,&c001 ; copy ROM version number to RAM
ld de,&4040
ld bc,3
ldir
ld bc,&7f8e ; turn off ROM
out (c),c
pop af
pop hl
pop de
pop bc
ret
The following BASIC program POKEs that routine into memory and quits prematurely if BASIC 1.0 is detected (meaning the machine is a CPC464), as opposed to the more standard 1.1 or later:
10 s=&4000:SYMBOL AFTER 256:MEMORY s-1
20 FOR i=0 to 34:READ a:POKE s+i,a:NEXT
30 DATA &c5,&d5,&e5,&f5,&01,&00,&df,&ed,&49,&01,&86,&7f,&ed,&49
40 DATA &21,&01,&c0,&11,&40,&40,&01,&03,&00,&ed,&b0
50 DATA &01,&8e,&7f,&ed,&49,&f1,&e1,&d1,&c1,&c9
60 CALL s
70 PRINT "BASIC ROM version is ";PEEK(&4040);".";PEEK(&4041);".";PEEK(&4042)
80 IF PEEK(&4041)=0 THEN PRINT "Uh oh, you are still using BASIC 1.0":END
90 PRINT "You are using BASIC 1.1 or later, program can continue"
The second subtask, testing for the presence of a variable, is done here by trying to get the memory address of the variable. If that fails, it is obviously is not yet defined:
1 ' decide randomly whether to define the variable:
10 IF RND>.5 THEN bloop=-100*RND
20 ON ERROR GOTO 100
30 a=@bloop ' try to get a pointer
40 PRINT "Variable bloop exists and its value is",bloop
50 PRINT "ABS of bloop is",ABS(bloop)
90 END
100 IF ERL=30 THEN PRINT "Variable bloop not defined":RESUME 90
(Like the Spectrum version, we have omitted checking for ABS because it is a builit-in function of the BASIC interpreter and therefore always present.)
Extra credit: Finally, we can traverse the memory area where BASIC stores its integer, real, and string variables and add together all integers (type 1):
10 ' The program should find and add those three integers (%), ignoring reals:
20 foo%=-4:bar%=7:baz%=9:somereal=3.141
30 varstart=&ae68 ' for CPC 664 and 6128
40 ' varstart=&ae85 ' (use this line instead on the CPC 464)
50 start=PEEK(varstart)+256*PEEK(varstart+1)
60 WHILE start<HIMEM
70 j=2:WHILE j<43 ' skip variable name
80 IF PEEK(start+j)=0 GOTO 170
90 IF PEEK(start+j)>127 THEN ptr=start+j+1:j=100
100 j=j+1:WEND
110 vartype=PEEK(ptr) ' integer=1, string=2, real=4
120 IF vartype=1 THEN sum=sum+UNT(PEEK(ptr+1)+256*PEEK(ptr+2)):num=num+1:nvar=ptr+3
130 IF vartype=2 THEN nvar=ptr+4
140 IF vartype=4 THEN nvar=ptr+6
150 start=nvar
160 WEND
170 PRINT "There are"num"integer variables."
180 PRINT "Their sum is"sum
- Output:
There are 3 integer variables. Their sum is 12
Logo
show logoversion ; 5.6
if logoversion < 6.0 [print [too old!]]
if and [name? "a] [number? :a] [
print ifelse procedure? "abs [abs :a] [ifelse :a < 0 [minus :a] [:a]]
]
Logtalk
:- object(my_application).
:- initialization((
check_logtalk_version,
compute_predicate_if_available
)).
check_logtalk_version :-
% version data is available by consulting the "version_data" flag
current_logtalk_flag(version_data, logtalk(Major,Minor,Patch,_)),
( (Major,Minor,Patch) @< (3,0,0) ->
write('Logtalk version is too old! Please upgrade to version 3.0.0 or later'), nl,
halt
; true
).
% Logtalk is not a functional language and thus doesn't support user-defined functions; we
% use instead a predicate, abs/2, with a return argument to implement the abs/1 function
compute_predicate_if_available :-
( % check that the variable "bloop" is defined within this object
current_predicate(bloop/1),
% assume that the abs/2 predicate, if available, comes from a "utilities" object
utilities::current_predicate(abs/2) ->
bloop(Value),
utilities::abs(Value, Result),
write('Function value: '), write(Result), nl
; write('Could not compute function!'), nl
).
% our "bloop" variable value as per task description
bloop(-1).
:- end_object.
Lua
if _VERSION:sub(5) + 0 < 5.1 then print"too old" end --_VERSION is "Lua <version>".
if bloop and math.abs then print(math.abs(bloop)) end
Maple
The "version" kernel option returns a string similar to
> kernelopts( 'version' );
Maple 16.00, SUN SPARC SOLARIS, Mar 3 2012, Build ID 732982
The following does the trick for the first bit.
> if sscanf( (StringTools:-Split(kernelopts(version))[2]), "%d.%d" )[1] < 300 then `quit`(1) end;
(There is also an internal "version" procedure, which returns a build ID, but this is less obvious to use, as you'd need a table mapping versions to build IDs. Besides, it prints stuff.)
It doesn't really make sense to ask whether a variable "exists"; it springs into existence by uttering it in code. So I'll interpret the problem as asking whether it is assigned some kind of numeric value to which abs() can be applied.
> if type( bloop, complex( extended_numeric ) ) and type( abs, mathfunc ) then print( abs( bloop ) ) end:
1/2
13
Note that it is not necessary to check that the name "bloop" is assigned (though it is possible to do so), since an unassigned name is a first-class value in Maple. Another possible interpretation is that the symbolic expression
> abs( bloop );
| bloop |
is a perfectly good expression in Maple, so checking for the the "existence" of "bloop" isn't necessary in the first place. (One probably would not bother to check that abs() was actually there either, unless one expected that the standard library was broken.)
Here are the number and sum of the assigned integer globals in my current (fresh) session.
> nops([anames](integer));
3
> eval(`+`(anames(integer)));
17
If I change it, I get:
> foo := 25:
> nops([anames](integer));
4
> eval(`+`(anames(integer)));
42
Mathematica /Wolfram Language
If[$VersionNumber < 8, Quit[]]
If[NameQ["bloop"] && NameQ["Abs"],
Print[Abs[bloop]]]
- Output:
7
globalintegers = Symbol /@ Select[Names["Global`*"], IntegerQ[Symbol[#]] &];
Print [ globalintegers //Length, " global integer(s) and their sum is: ", globalintegers // Total]
- Output:
2 global integer(s) and their sum is: 9
MATLAB / Octave
% convert version into numerical value
v = version;
v(v=='.')=' ';
v = str2num(v);
if v(2)>10; v(2) = v(2)/10; end;
ver = v(1)+v(2)/10;
if exist('OCTAVE_VERSION','builtin')
if ver < 3.0,
exit
end;
else
if ver < 7.0,
exit
end;
end
% test variable bloob, and test whether function abs is defined as m-function, mex-function or builtin-function
if exist('bloob','var') && any(exist('abs')==[2,3,5])
printf('abs(bloob) is %f\n',abs(bloob));
return;
end;
Extra credit task:
% find all integers
varlist = whos;
ix = [strmatch('int', {varlist.class}),strmatch('uint', {varlist.class})];
intsumall = 0;
intsum = 0;
for k=1:length(ix)
if prod(varlist(ix).size)==1,
intsum = intsum + eval(varlist.name); % sum only integer scalars
elseif prod(varlist(ix).size)>=1,
tmp = eval(varlist.name);
intsumall = intsumall + sum(tmp(:)); % sum all elements of integer array.
end;
end;
printf('sum of integer scalars: %i\n',intsum);
printf('sum of all integer elements: %i\n',intsumall);
Maxima
/* Get version information */
build_info();
/* build_info("5.27.0", "2012-05-08 11:27:57", "i686-pc-mingw32", "GNU Common Lisp (GCL)", "GCL 2.6.8") */
%@lisp_version;
/* "GCL 2.6.8" */
/* One can only check for user-defined objects: functions, variables, macros, ...
Hence we won't check for 'abs, which is built-in, but for 'weekday, defined elsewhere on RosettaCode.
Here year, month and day are 2012, 05, 29. */
if subsetp({'year, 'month, 'day}, setify(values))
and member('weekday, map(op, functions))
then weekday(year, month, day)
else 'bad\ luck;
/* Sum of integer variables */
lreduce("+", sublist(map(ev, values), integerp));
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
NetRexx
Like Java, NetRexx will not successfully compile a program if a variable or method is accessed before it has been defined.
The language does however return a string identifying the version of NetRexx in effect when the current class was last processed. This information can be retrieved through the version special variable.
/* NetRexx */
options replace format comments java crossref symbols binary
runSample(arg)
return
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) private static
parse arg minVersion .
if minVersion = '' then minVersion = 2.0
parse version lang ver bdate
if ver < minVersion then do
say -
lang 'version' ver -
'[Build date:' bdate']' -
'is less than' minVersion.format(null, 2)'; exiting...'
exit
end
else do
say -
lang 'version' ver -
'[Build date:' bdate']' -
'meets minimum requirements of' minVersion.format(null, 2)
end
return
- Output:
$ java RIntrospection NetRexx version 3.02 [Build date: 25 Jun 2013] meets minimum requirements of 2.00 $ java RIntrospection 4 NetRexx version 3.02 [Build date: 25 Jun 2013] is less than 4.00; exiting...
Nim
In Nim, many checks are done at compile time. So, you have the choice to emit an error or warning at compile time or exit at runtime.
when NimVersion < "1.2":
error "This compiler is too old" # Error at compile time.
assert NimVersion >= "1.4", "This compiler is too old." # Assertion defect at runtime.
var bloop = -12
when compiles abs(bloop):
echo abs(bloop)
- Output:
12
OCaml
# Sys.ocaml_version;;
- : string = "3.10.2"
# Scanf.sscanf (Sys.ocaml_version) "%d.%d.%d"
(fun major minor micro -> major, minor, micro) ;;
- : int * int * int = (3, 10, 2)
Checking if an identifier (a value or a function) is bound doesn't make any sens in OCaml, which is strongly staticaly typed.
For optionnal values we would rather use a structure to contain them, for example an association lists for a small amount of items, or an hash table for a huge amount of data. Both can contain expressions or functions.
Oforth
Oforth does not have global variables, only global constants.
: bloopAbs
| bl m |
System.VERSION println
Word find("bloop") ->bl
bl isA(Constant) ifFalse: [ "bloop constant does not exist" println return ]
"abs" asMethod ->m
m ifNull: [ "abs method does not exist" println return ]
System.Out "bloop value is : " << bl value << cr
System.Out "bloop abs is : " << bl value m perform << cr ;
- Output:
>bloopAbs V0.9.17 bloop constant does not exist ok >-2.3 Constant new: bloop ok >bloopAbs V0.9.17 bloop value is : -2.3 bloop abs is : 2.3 ok
OxygenBasic
Compile time introspection
$ rtlversion "0.4.0"
'
#if not match(rtlversion,o2version)
#error "This RTL version mismatches o2 version "+o2version
#else
print o2version
#endif
float bloop=-1618
#ifdef bloop
#ifdef abs
print abs(bloop)
#endif
#endif
Oz
We cannot check whether a variable is in scope (static property). We can check whether a module exports a certain value. However, for system modules the compiler will refuse to compile if we try to use a non-existing value.
declare
Version = {Property.get 'oz.version'}
%% Version is an atom like '1.4.0'. So we can not compare it directly.
%% Extract the version components:
[Major Minor Release] = {Map {String.tokens {Atom.toString Version} &.} String.toInt}
in
if Major >= 1 andthen Minor >= 4 then
%% check whether module Number exports a value 'abs':
if {HasFeature Number abs} then
{Show {Number.abs ~42}}
end
else
{System.showInfo "Your Mozart version is too old."}
end
PARI/GP
if(lex(version(), [2,4,3]) < 0, quit()); \\ Compare the version to 2.4.3 lexicographically
if(bloop!='bloop && type(abs) == "t_CLOSURE", abs(bloop))
Perl
require v5.6.1; # run time version check
require 5.6.1; # ditto
require 5.006_001; # ditto; preferred for backwards compatibility
To check if a variable exists, do a name lookup of it in the package symbol table:
#$bloop = -123; # uncomment this line to see the difference
no strict 'refs'; # referring to variable by name goes against 'strict' pragma
if (defined($::{'bloop'})) {print abs(${'bloop'})} else {print "bloop isn't defined"};
To check if certain built-in function is available (maybe you are using a stripped down build of perl binary, for example), one can use eval, but make sure the statement you are eval'ing doesn't have side effect:
eval('abs(0)'); # eval("") instead of eval{}; the latter is not for run-time check
print "abs() doesn't seem to be available\n" if $@;
To check if a package or object provides certain method name, use 'can':
use Math::Complex;
my $cpl = Math::Complex->new(1,1);
print "package Math::Complex has 'make' method\n"
if Math::Complex->can('make');
print "object \$cpl does not have 'explode' method\n"
unless $cpl->can('explode');
Keep in mind that what a package has as method names are not equal to what method names can be called on this package, due to things like AUTOLOAD. For most uses, introspection is meaningless, just call the method (and catch exceptions if it's important).
An example that solves the task:
use 5.010;
our $bloop = -12;
if (defined $::bloop) {
if (eval { abs(1) }) {
say 'abs($bloop) is ' . abs($::bloop);
}
else {
say 'abs() is not available';
}
}
else {
say '$bloop is not defined';
}
Note that this program will exit with a message "Perl v5.10.0 required" if run under perl version lower than 5.10 and it actually uses a feature introduced in that version (say
).
The program checks whether the variable is actually defined and not if it just exists.
In Perl a variable can exist and have an undefined value, and checking for existence is problematic because many read-only operations may create an empty slot in the global namespace as a side effect. It doesn't make sense to calculate absolute values of existent but undefined variables so it doesn't matter in this task.
It can be tested by commenting out the our $bloop
line.
The existence of abs()
function is tested using eval
that returns false if the abs(1)
cannot be invoked which can be tested by changing the name of the function in the eval
test.
Extra task:
use 5.010;
package test;
use Regexp::Common;
use List::Util qw(sum);
our $a = 7;
our $b = 1;
our $c = 2;
our $d = -5;
our $e = 'text';
our $f = 0.25;
my @ints = grep { /^$RE{num}{int}$/ } map { $$_ // '' } values %::test::;
my $num = @ints;
my $sum = sum @ints;
say "$num integers, sum = $sum";
It prints:
4 integers, sum = 5
This example uses the test
namespace instead of the default, because there already are some integer numbers in the main
namespace like the PID, etc.
The program to sum those numbers would be:
use 5.010;
use Regexp::Common;
use List::Util qw(sum);
my @ints = grep { /^$RE{num}{int}$/ } map { $$_ // '' } values %::;
my $num = @ints;
my $sum = sum @ints;
say "$num integers, sum = $sum";
4 integers, sum = 74717
Phix
The requires procedure behaves like a compiler directive, although it is in fact just a normal executable routine.
requires("0.8.2") -- crashes on 0.8.1 and earlier
requires(WINDOWS) -- crashes on Linux
requires(64) -- crashes on 32-bit
If passed a string it compares it (intelligently) against the interpreter/compiler version and terminates in error with a suitable message should it be too old to cope. Otherwise the parameter must be an integer: <32 checks the platform, >=32 checks the word size. In the latter case when (interpreting and) it needs to, it hunts for a suitable alternative runtime and offers to re-run with that, maybe you need bigger ints, or maybe you only ship a 32-bit libcurl.dll.
The version() routine used by the above can also be called directly and returns a string:
?version() -- eg "0.8.0"
Normally only really useful for display, but you can of course break that down into an integer triplet with scanf(), as requires does, maybe something works on 0.7.7 and 0.7.9 but not 0.7.8.
Phix has a builtin abs() routine, which will be auto-included if referenced.
--include pmaths.e -- (an auto-include, ok but not needed) --include complex.e -- (not an auto-include, needed if used) integer r_abs = routine_id("abs") --integer r_abs = routine_id("complex_abs") if r_abs!=-1 then ?call_func(r_abs,{-42}) end if
Using complex_abs() is probably closer to the task requirement in that if complex.e is not included it will not be found/called.
In this case it happens to give exactly the same result, however under the hood it is first promoting the -42 to -42+0i before returning sqrt((-42)*(-42)+(0)*(0)).
There is (as yet) no var_id() builtin, the following is a quick cobbling-together of code from builtins\VM\prtnidN.e (routine_id) and builtins\VM\pDiagN.e (ex.err file creation), not very pretty but it seems to work, and of course all this sort of stuff is normally hidden away out of sight in builtins\VM.
include builtins/VM/pStack.e -- :%opGetST -- copies from pglobals.e: constant S_Name = 1, -- const/var/rtn name S_NTyp = 2, -- Const/GVar/TVar/Nspc/Type/Func/Proc S_FPno = 3, -- File and Path number S_Slink = 6, -- scope/secondary chain (see below) S_vtype = 7, -- variable type or namespace fileno S_GVar2 = 2, -- global or static variable T_int = 1, T_EBP = 22, -- compiled/listing=0, interpreted={ebp4,esp4,sym4} (set at last possible moment) T_ds4 = 23 -- compiled = start of data section, same but /4 when interpreted ([T_EBP]!=0) function var_id(object s) -- hacked copy of routine_id(), for local file-level integers only integer res, -- symidx for string s, else sum(local gvar integers) rtn, -- routine number of callee, from callstack cFno, -- calling fileno. tidx, ds4 object symtab, si, -- copy of symtab[i], speedwise si_name -- copy of symtab[i][S_name], speedwise/thread-sfaety -- get copy of symtab. NB read only! may contain nuts! (unassigned vars) enter_cs() #ilASM{ [32] lea edi,[symtab] call :%opGetST -- [edi]=symtab (ie our local:=the real symtab) mov edi,[ebp+20] -- prev_ebp mov edi,[edi+8] -- calling routine no mov [rtn],edi [64] lea rdi,[symtab] call :%opGetST -- [rdi]=symtab (ie our local:=the real symtab) mov rdi,[rbp+40] -- prev_ebp mov rdi,[rdi+16] -- calling routine no mov [rtn],rdi [] } if symtab[T_EBP]=0 then -- compiled ds4 = floor(symtab[T_ds4]/4) else -- interpreted ds4 = symtab[T_ds4] end if cFno = symtab[rtn][S_FPno] -- fileno of callee (whether routine or toplevel) res = iff(s=0?0:-1) for i=1 to length(symtab) do si = symtab[i] if sequence(si) and si[S_NTyp]=S_GVar2 and si[S_FPno]=cFno and si[S_vtype]=T_int then si_name = si[S_Name] if s=0 then -- cut-down version of pDiagN.e/getGvarValue(): integer gidx = si[S_Slink], novalue, o #ilASM{ mov [novalue],0 [32] mov esi,[ds4] mov edx,[gidx] shl esi,2 mov esi,[esi+edx*4+16] -- ([ds+(gidx+4)*4] == gvar[gidx]) cmp esi,h4 jl @f mov [novalue],1 xor esi,esi @@: mov [o],esi [64] mov rsi,[ds4] mov rdx,[gidx] shl rsi,2 mov rsi,[rsi+rdx*8+24] -- ([ds+(gidx+3)*8] == gvar[gidx]) mov r15,h4 cmp rsi,r15 jl @f mov [novalue],1 xor rsi,rsi @@: mov [o],rsi [] } if novalue then ?{si_name,"no_value"} else res += o end if elsif s=si_name then res = i exit end if end if end for si_name = 0 si = 0 symtab = 0 leave_cs() return res end function {} = routine_id("blurgzmp") -- force symtab name population.. -- (alt: see rbldrqd in pDiagN.e) integer bloop = 5, -- barf, -- triggers {"barf","no_value"} burp = 35 bloop = 6 burp += 1 ?var_id("bloop") -- >0 === exists ?var_id("blooop") -- -1 === does not exist ?var_id(0) -- bloop+burp = 42 ?bloop+burp -- "", doh
- Output:
1257 -1 42 42
As-is, of course, being integer-only-and-no-routine-level-vars, the above represents very limited practical value.
Other routines of interest include
?platform() -- WINDOWS=2, LINUX=3
?machine_bits() -- 32 or 64
?machine_word() -- 4 or 8
?include_paths() -- eg {"C:\\Program Files (x86)\\Phix\\builtins\\",
-- "C:\\Program Files (x86)\\Phix\\builtins\\VM\\",
-- "C:\\Program Files (x86)\\Phix\\"}
-- (plus other application-specific directories)
?get_interpreter() -- eg "C:\Program Files (x86)\Phix\p.exe"
-- or perhaps "/home/pete/phix/p" on Linux
Phix supports the absolute bare minimum use of #ifdef, for compatibility with OpenEuphoria, however it is almost always better to use platform() and friends as normal hll code, rather than that sort of language-within-a-language stuff, imnsho, and the compiler is pretty good at optimising away most such os-specific tests and whole branches of irrelevant code (see EmitON=0).
Phixmonti
_version 1.0 < if "Interpreter version is old" else "Last version" endif print
The program will not be executed if the variable or function has not been defined.
PHP
<?php
if (version_compare(PHP_VERSION, '5.3.0', '<' ))
{
echo("You are using PHP Version " . PHP_VERSION . ". Please upgrade to Version 5.3.0\n");
exit();
}
$bloop = -3;
if (isset($bloop) && function_exists('abs'))
{
echo(abs($bloop));
}
echo(count($GLOBALS) . " variables in global scope.\n");
echo(array_sum($GLOBALS) . " is the total of variables in global scope.\n");
?>
PicoLisp
(unless (>= (version T) (3 0 1)) # Check version (only in the 64-bit version)
(bye) )
# (setq bloop -7) # Uncomment this to get the output '7'
(and
(num? bloop) # When 'bloop' is bound to a number
(getd 'abs) # and 'abs' defined as a function
(println (abs bloop)) ) # then print the absolute value
PL/I
Version 1
S = SYSVERSION();
if substr(S, 6, 6) < '050000' then
do; put skip list ('Version of compiler is too old'); stop; end;
Version 2
*process source attributes options m or(!);
/*********************************************************************
* 02-11.2013 Walter Pachl
* I modified this to run on my Windows PL/I
*********************************************************************/
v: Proc Options(main);
%version: Proc Returns(char);
Dcl res char;
res=sysversion;
Return(''''!!res!!'''');
%End;
%Act version;
Dcl s char(31) Init('');
s=version;
if substr(S,15,3) < '7.5' then Do;
put Skip list('Version of compiler ('!!substr(S,15,3)!!
') is too old');
stop;
End;
Else
Put Skip List('Version is '!!s);
End
- Output:
Version is PL/I for Win* 7.5
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.
PowerBASIC
PowerBASIC has no way of determining if a variable "exists" in code. If variable declaration is required (using #DIM ALL
), then any attempt to use a variable without declaring it will result in a failed compile; if variable declaration is not required, then the first time the program accesses the variable it is automatically created with the default data type (which is set using DEFtype
).
The compiler directive #COMPILER
, introduced with PB/Win 8 and PB/CC 4, will fail the compile if the compiler does not match at least one of the listed compilers, and is not at least the (optional) minimum version of that compiler.
#COMPILER PBWIN 9
#COMPILER PBWIN, PBCC 5
PowerShell
# version is found in $PSVersionTable
if ($PSVersionTable['PSVersion'] -lt '2.0') {
exit
}
if ((Test-Path Variable:bloop) -and ([Math]::Abs)) {
[Math]::Abs($bloop)
}
# find integer variables and their sum
Get-Variable -Scope global `
| Where-Object { $_.Value -is [int] } `
| Measure-Object -Sum Value `
| Select-Object Count,Sum
PureBasic
CompilerIf #PB_Compiler_Version<441
CompilerError "You failed the version check!"
CompilerEndIf
CompilerIf Defined(bloop,#PB_Variable)
CompilerIf Defined(Abs(),#PB_Function)
Abs(bloop)
CompilerEndIf
CompilerEndIf
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)
You can combine both tests, (But loose sight of which variable in missing/not callable by wrapping the whole function call in a try-except statement:
try:
print abs(bloop)
except (NameError, TypeError):
print "Something's missing"
Here is one way to print the sum of all the global integer variables:
def sum_of_global_int_vars():
variables = vars(__builtins__).copy()
variables.update(globals())
print sum(v for v in variables.itervalues() if type(v) == int)
sum_of_global_int_vars()
R
if(getRversion() < "2.14.1")
{
warning("Your version of R is older than 2.14.1")
q() # exit R, with the option to cancel
}
The constants version
and R.version
give further information about the version that is running. The function R.Version()
provides the same information as a list.
We now perform three checks: we want to know if bloop is in the user workspace (global environment), if abs exists somewhere, and if abs is a function.
bloop <- -3.4
if(exists("bloop", envir=globalenv()) && exists("abs") && is.function(abs))
{
abs(bloop)
}
Finally, we count how many integers are in the user workspace, and find their total. Note that a number followed by the letter L is considered to be an integer. See Integer_literals#R for more information.
#Declare some integers
qqq <- 45L
www <- -3L
#Retrieve the name of all the variables in the user workspace
var_names <- ls()
#Retrieve the actual variables as a list
all_vars <- mget(var_names, globalenv())
#See which ones are integers
is_int <- sapply(all_vars, is.integer)
#Count them
sum(is_int)
#Retrieve the variables that were integers
the_ints <- mget(varnames[is_int], globalenv())
#Add them up
sum(unlist(the_ints))
Racket
The usual hack:
#lang racket
(unless (string<=? "5.3" (version)) (error "ancient version"))
Proper comparison:
(require version/utils)
(unless (version<=? "5.3" (version)) (error "ancient version"))
Raku
(formerly Perl 6)
my $bloop = -123;
if MY::{'$bloop'}.defined and CORE::{'&abs'}.defined { say abs $bloop }
my @ints = ($_ when Int for PROCESS::.values);
say "Number of PROCESS vars of type Int: ", +@ints;
say "PROCESS vars of type Int add up to ", [+] @ints;
- Output:
123 Number of PROCESS vars of type Int: 1 PROCESS vars of type Int add up to 28785
Obviously Raku doesn't maintain a lot of global integer variables... :-)
Nevertheless, you can use similar code to access all the variables in any package you like, such as the GLOBAL package, which typically has absolutely nothing in it. Since the PROCESS package is even more global than GLOBAL, we used that instead. Go figure...
Raven
VERSION 0 prefer 20071104 <
if 'version >= 20071104 required' print bye
'bloop' GLOBAL keys in && 'abs' CORE keys in
if bloop abs print
Retro
This will exit if the version is less than 2019.6:
@Version #201906 lt+ &bye if
The existence of functions can be checked using d:lookup. In this, a helper function is provided to improve readability.
Checks for existence of "bloop" and "n:abs"
~~~
: executeByName (s-)
d:lookup [ d:xt fetch ] [ d:class fetch ] bi call ;
'bloop 'n:abs [ find nip ] bi@ and
[ 'bloop executeByName 'n:abs executeByName ] if
~~~
Retro has no direct way to check for data types of functions. Assuming that a word class is defined for integer variables, we could do something like this:
#0 #0 [ dup d:class fetch &class:integer eq? [ d:xt fetch + [ n:inc ] dip ] [ drop ] choose ] d:for-each
After execution the stack will have the number of variables found, and the accumulated sum of their values.
REXX
Test to see if the version is at least version 4.
/*output from parse version (almost all REXX versions) */
/* theREXXinterpreterName level mm Mon yyyy */
parse version . level .
if level<4 then exit
Test to see if the version is at least version 4, another example.
parse version x 1 whatLang level dd mon yyyy .
if level<4 then do
say
say 'version' level "is too old!"
say x /*this displays everything.*/
exit /*or maybe: EXIT 13 */
end
Test to see if the REXX variable "bloop" exists, version 1.
if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.'
Test to see if the REXX variable "bloop" exists, version 2.
if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.'
else say 'the "bloop" variable doesn''t exist.'
Programming note: note the use of the double apostrophe ( ' ' ) which is within a quoted string (with apostrophes) [in the above and below REXX programming examples].
Another test to see if the REXX variable "bloop" exists.
bloop=47
if symbol('bloop')=='VAR' then say 'the "bloop" variable exists.'
else say 'the "bloop" variable doesn''t exist.'
In REXX, the ABS function is a built-in function (BIF).
bloop=47
g=abs(bloop)
However, most REXX interpreters will allow this type of test:
if testxyz() then say 'function XYZ not found.'
else say 'function XYZ was found.'
exit
/*──────────────────────────────────────────────────────────────────────────────────────*/
testxyz: signal on syntax
call XYZ
return 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
syntax: return 1
Ring
# Project: Introspection
if version() < 1.8
see "Version is too old" + " (" + version() + ")" + nl
else
see "Version is uptodate" + " (" + version() + ")" + nl
ok
bloop = 5
if isglobal("bloop") = 1
see "Variable " + "'bloop'" + " exists" + nl
else
see "Variable " + "'bloop'" + " doesn't exist" + nl
ok
if isglobal("bleep") = 1
see "Variable " + "'bleep'" + " exists" + nl
else
see "Variable " + "'bleep'" + " doesn't exist" + nl
ok
if isfunction("abs") = 1
see "Function " + "'abs'" + " is defined" + nl
else
see "Function " + "'abs'" + " is not defined" + nl
ok
if isfunction("abc") = 1
see "Function " + "'abc'" + " is defined" + nl
else
see "Function " + "'abc'" + " is not defined" + nl
ok
func abs(bloop)
return fabs(bloop)
Output:
Version is uptodate (1.8) Variable 'bloop' exists Variable 'bleep' doesn't exist Function 'abs' is defined Function 'abc' is not defined
RPL
≪ IF VERSION DROP DUP SIZE DUP 3 - SWAP SUB STR→ 2.15 < THEN "Too old RPL version" ELSE 'BLOOP' IFERR RCL THEN ": variable not defined" + ELSE ABS IF DUP TYPE 6 == THEN ": function not defined" + NIP END END END ≫ 'INTROSP' STO
Ruby
exit if RUBY_VERSION < '1.8.6'
puts bloop.abs if defined?(bloop) and bloop.respond_to?(:abs)
Extra credit:
def variable_counter(b)
int_vars = []
sum = 0
check_var = lambda do |name, value|
if value.is_a?(Integer)
int_vars << name
sum += value
end
end
global_variables.each {|varname| check_var.call(varname, eval(varname.to_s))}
eval('local_variables', b).each {|varname| check_var.call(varname, eval(varname.to_s, b))}
puts "these #{int_vars.length} variables in the global scope are integers:"
puts int_vars.inspect
puts "their sum is: #{sum}"
end
an_int = 5
a_string = 'foo'
a_float = 3.14
variable_counter(binding)
- Output:
(eval):1: warning: variable $= is no longer effective (eval):1: warning: variable $KCODE is no longer effective (eval):1: warning: variable $KCODE is no longer effective these 5 variables in the global scope are integers: [:$SAFE, :$., :$$, :$-W, :an_int] their sum is: 18630
Note: The warning is because it accessed the global variable which was made invalid.
The meaning of these variables can be found many places, including here.
Rust
Checking for the Rust compiler version can be done using external crates, for example using the rustc_version crate. Simply add the rustc_version dependency into your cargo.toml file under the dependencies:
[dependencies]
rustc_version = "0.4"
Then we can write code that can check the rust compiler channel, the rust compiler version and check for a minimum version of the rust compiler:
use rustc_version::{version_meta, Channel, version, Version};
fn main() {
// We can check the Rust channel currently being used: stable, nightly, etc.
match version_meta().unwrap().channel {
Channel::Stable => {
println!("Rust Stable");
}
Channel::Beta => {
println!("Rust Beta");
}
Channel::Nightly => {
println!("Rust Nightly");
}
Channel::Dev => {
println!("Rust Dev");
}
}
// We can print the Rust compiler version
println!("{}",version().unwrap());
// We can check for a minimum Rust compiler version
if version().unwrap() >= Version::parse("1.50.0").unwrap() {
println!("Rust compiler version is ok.");
} else {
eprintln!("Rust compiler version is too old. Please update to a more recent version.");
std::process::exit(1);
}
}
When running the code using the stable Rust compiler version 1.71.1 it results in:
Rust Stable 1.74.1 Rust compiler version is ok.
There are currently no runtime capabilities built into the Rust compiler for checking whether individual variables or individual functions have been declared. Some crates offer specialized, limited and experimental reflection capabilities; for example for introspecting struct fields we can use the crates introspection or bevy_reflect. Macros and build scripts can also be leveraged as a current workaround for specific and limited scenarios.
Scala
object VersCheck extends App {
val minimalVersion = 1.7
val vers = System.getProperty("java.specification.version");
println(if (vers.toDouble >= minimalVersion) "YAY!" else s"Must use Java >= $minimalVersion");
val bloop = Option(-42)
if (bloop.isDefined) bloop.get.abs
}
Slate
No version string included inside the system presently.
Platform run: StartupArguments first ; ' --version'.
(lobby hasSlotNamed: #bloop) /\ [(#abs findOn: {lobby bloop}) isNotNil] ifTrue: [inform: bloop abs printString].
lobby slotValues inject: 0 into: [| :sum :value | (value is: Integer) ifTrue: [sum + value] ifFalse: [sum]].
Smalltalk
| s v t sum hm |
"uncomment the following to see what happens if bloop exists"
"Smalltalk at: #bloop put: -10."
s := Smalltalk version.
(s =~ '(\d+)\.(\d+)\.(\d+)')
ifMatched: [:match |
v := (( (match at: 1) asInteger ) * 100) +
(( (match at: 2) asInteger ) * 10) +
( (match at: 3) asInteger )
].
( v < 300 )
ifTrue: [
Transcript show: 'I need version 3.0.0 or later' ; cr ]
ifFalse: [
Transcript show: 'Ok! I can run!' ; cr .
"does bloop exists as global var?"
t := Smalltalk at: #bloop
ifAbsent: [
Transcript show: 'bloop var does not exist as global!' ; cr .
^nil
].
(t respondsTo: #abs)
ifTrue:
[ Transcript show: 'Absolute value of bloop: ' ;
show: (t abs) printString ; cr ].
] .
"how many 'numbers' in global scope, and compute their sums"
hm := 0.
sum := 0.
(Smalltalk keys) do: [ :els |
( (Smalltalk at: els) isKindOf: Number )
ifTrue: [ hm := hm + 1.
sum := sum + (Smalltalk at: els).
"Transcript show: (els asString) ; cr" ]
] .
Transcript show: 'Num of global numeric vars: '; show: (hm printString); cr ;
show: 'Sum of global numeric vars: '; show: (sum printString) ; cr.
Tcl
package require Tcl 8.4 ; # throws an error if older
if {[info exists bloop] && [llength [info functions abs]]} {
puts [expr abs($bloop)]
}
Extra credit:
namespace eval ::extra_credit {
variable sum_global_int 0
variable n_global_int 0
foreach var [info vars ::*] {
if {[array exists $var]} continue
if {[string is int -strict [set $var]]} {
puts "$var = [set $var]"
incr sum_global_int [set $var]
incr n_global_int
}
}
puts "number of global ints = $n_global_int"
puts "their sum = $sum_global_int"
}
TI-89 BASIC
()
Prgm
Local l, i, vers
getConfg() → l
For i,1,dim(l),2
If l[i] = "OS Version" or l[i] = "Version" Then
l[i + 1] → vers
Disp "Version: " & vers
If expr(right(vers, 4)) < 2005 Then © Lousy parsing strategy
Disp vers & " is too old"
Stop
EndIf
EndIf
EndFor
If isVar(bloop) Then © Dynamic name check can be done with isVar(#aString)
© Builtin functions cannot be tested for.
Disp abs(bloop)
Else
Disp "No bloop"
EndIf
© There is no way to get a list of global variables.
EndPrgm
Toka
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
UNIX Shell
There's no way to introspect the builtin arithmetic functions. We'll just try it and see if there's an error.
case ${.sh.version} in
*93[[:alpha:]]+*) :;; #this appears to be ksh93, we're OK
*) echo "version appears to be too old"
exit # otherwise, bail out
;;
esac
if [[ -z ${bloop+bloop has a value} ]]; then
print "no bloop variable"
elsif (( abs(1) )); then
print -- $(( abs(bloop) ))
fi
typeset -a int_vars
set | while IFS='=' read -r var value; do
if [[ $value == +([[:digit:]]) ]]; then
int_vars[n++]=$var
let sum += $value
fi
done
print "${int_vars[*]}"
print -- $sum
bash does not have a builtin math function "abs" -- we'll check for a user-defined shell function instead.
if [[ $BASH_VERSION < "4.2" ]]; then
echo "version is too old"
exit
fi
if [[ ! -v bloop ]]; then
echo "no bloop variable"
elif [[ $(type -t abs 2>/dev/null) != function ]]; then
echo "abs is not a shell function"
else
echo $(abs $bloop)
fi
# need to populate the variables and use them within the same subshell in a pipeline.
set | {
shopt -s extglob
int_vars=()
while IFS='=' read -r var value; do
if [[ $value == +([[:digit:]]) ]]; then
int_vars+=($var)
(( sum += value ))
fi
done
echo "${int_vars[*]}"
echo $sum
}
Ursala
When the user defined function maybe_abs(x) is evaluated, a run time check is performed for the availability of the system library's absolute value function (fabs), and if found, it is used. If not, the function tries to invoke a replacement function named 'abs' from the imported floating point function library, flo. (The search for a replacement is performed at the time maybe_abs is compiled, and is possible because any imported library is presented as a list of (identifier:value) pairs.) If no imported absolute value function is available either, maybe_abs returns a copy of the argument x unchanged.
The #preprocess directive allows arbitrary user defined transformations to be applied to the abstract syntax trees created by the compiler (assuming a knowledge of the compiler internals). This example of a preprocessor aborts compilation if the run time system version differs from 0.10.2. Otherwise, a search is performed for any declared symbol named 'bloop' whose evaluation has been resolved, and its value is replaced with the absolute value as given by maybe_abs.
On platforms where at least one of the absolute value functions is available, the -1. shown in the source text will have been changed to 1 by the time it's displayed.
#import std
#import flo
#import lag
maybe_abs = math.|fabs (%QI flo)-:~&! 'abs'
#preprocess version==-[0.10.2]-?\<'wrong version'>!% *^0 ||~& -&
-&~&vitB,~&d.lexeme=='=',~&vhd.lexeme=='bloop',~&vthd.lexeme=='(evaluated)'&-,
&vthd.semantics:= !+ !+ maybe_abs+ ~&vthd.semantics.&iNHiNH&-
#cast %e
bloop = -1.
- Output:
1.000000e+00
VBA
Under VBA (and most, if not all, variations of Visual Basic), accessing an undeclared variable will automatically create it as a Variant, unless declaration is required (via Option Explicit
), in which case a compile-time error is generated and the compile fails (or in the case of interpreted varieties, the code will not run).
To determine the version of the environment -- typically meaning which version of Microsoft Office is running -- the Application
object has a Version
property:
If Application.Version < 15 Then Exit Sub
Wren
Note that:
- Wren doesn't have reflection as such but is able to obtain and analyze the running script's source code. It is assumed for this purpose that the latter is sensibly formatted - only global declarations are not indented.
- Wren is dynamically typed and has a Num type but not an integer type. As far as the extra credit is concerned, the simplifying assumption has been made that a global variable is an integer if it's assigned an integer literal when it's declared.
import "os" for Platform, Process
import "io" for File
import "meta" for Meta
import "./pattern" for Pattern
import "./math" for Nums
var a = 4 /* 1st integer variable */
var b = 0xA /* 2nd integer variable */
var c = -8 /* 3rd integer variable */
var bloop = -17.3
var checkVersion = Fn.new {
var version = Process.version
var components = version.split(".")
if (Num.fromString(components[1]) < 4) {
Fiber.abort("Wren version (%(version)) is too old.")
}
}
var globalIntVars = Fn.new {
var sep = Platform.isWindows ? "\r\n" : "\n"
var lines = File.read(Process.allArguments[1]).split(sep)
var p = Pattern.new("var+1/s[+1/x]+1/s/=+1/s[0x+1/h|~-+1/d]+0/s", Pattern.whole)
var q = Pattern.new("[////|//*]+0/z", Pattern.end)
var vars = []
var vals = []
for (line in lines) {
line = q.replaceAll(line, "") // get rid of any comments
var m = p.find(line)
if (m) {
vars.add(m.capsText[0])
vals.add(Num.fromString(m.capsText[1]))
}
}
return [vars, vals]
}
checkVersion.call()
var res = globalIntVars.call()
var d
Meta.eval("d = bloop.abs") // this won't compile if either 'bloop' or 'abs' not available
System.print("bloop.abs = %(d)")
var vars = res[0]
var vals = res[1]
System.print("The sum of the %(vars.count) integer variables, %(vars), is %(Nums.sum(vals))")
- Output:
bloop.abs = 17.3 The sum of the 3 integer variables, [a, b, c], is 6
Yabasic
if peek("version") < 2.63 error "Interpreter version is too old!"
Zig
Works with: 0.10.1, 0.11.0, 0.12.0-dev.1577+9ad03b628
Note that errors for compiler version check and @hasDecl/@hasField are usually reported at comptime via @compileError, not at runtime, but for demonstrating purposes output is moved to runtime (introspection is still at comptime).
const std = @import("std");
const builtin = @import("builtin");
pub const bloop: i32 = -1_000;
pub fn abs(a: i32) i32 {
return if (a < 0) -a else a;
}
pub fn main() error{NotSupported}!void {
if (builtin.zig_version.order(.{ .major = 0, .minor = 11, .patch = 0 }) == .lt) {
std.debug.print("Version {any} is less than 0.11.0, not suitable, exiting!\n", .{builtin.zig_version});
return error.NotSupported;
} else {
std.debug.print("Version {any} is more or equal than 0.11.0, suitable, continuing!\n", .{builtin.zig_version});
}
if (@hasDecl(@This(), "bloop") and @hasDecl(@This(), "abs")) {
std.debug.print("abs(bloop) = {d}\n", .{abs(bloop)});
} else {
std.debug.print("abs and/or bloop are not defined!\n", .{});
}
}
- Output — Zig version 0.10.1:
Version 0.10.1 is less than 0.11.0, not suitable, exiting! error: NotSupported src/instrospection.zig:13:9: 0x211a1e in main (instrospection) return error.NotSupported; ^
- Output — Zig version 0.11.0:
Version 0.11.0 is more or equal than 0.11.0, suitable, continuing! abs(bloop) = 1000
- Output — Zig version 0.12.0-dev.1577+9ad03b628:
Version 0.12.0-dev.1577+9ad03b628 is more or equal than 0.11.0, suitable, continuing! abs(bloop) = 1000
Extra credit
const std = @import("std");
pub const first_integer_constant: i32 = 5;
pub const second_integer_constant: i32 = 3;
pub const third_integer_constant: i32 = -2;
pub const some_non_integer_constant: f32 = 0.0;
pub const another_non_integer_constant: bool = false;
pub fn main() void {
comptime var cnt: comptime_int = 0;
comptime var sum: comptime_int = 0;
inline for (@typeInfo(@This()).Struct.decls) |decl_info| {
const decl = @field(@This(), decl_info.name);
switch (@typeInfo(@TypeOf(decl))) {
.Int, .ComptimeInt => {
sum += decl;
cnt += 1;
},
else => continue,
}
}
@compileLog(std.fmt.comptimePrint("cnt = {d}, sum = {d}", .{ cnt, sum }));
}
- Output:
src/instrospection.zig:24:5: error: found compile log statement @compileLog(std.fmt.comptimePrint("cnt = {d}, sum = {d}", .{ cnt, sum })); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Compile Log Output: @as(*const [16:0]u8, "cnt = 3, sum = 6")
zkl
Language.version //-->L(1,12,8,"2014-04-01")
if (Language.version[1] < 10) System.exit("Too old");
var bloop=-123;
if ((1).resolve("abs",1) and resolve("bloop",8)) bloop.abs().println()
- Output:
123
The concept of global vars doesn't really exist, only instance data.
var n=3, x=1.0, a=5, z="zoo";
self.vars; --> L(L("a",5),L("n",3),L("x",1),L("z","zoo"))
sum:=self.vars.reduce(fcn(p,[(nm,v)],r){
if((1).isType(v)){r.inc();p+v;} else p},0,num:=Ref(0));
println("Num int vars = ",num.value,". Sum = ",sum);
- Output:
Num int vars = 2. Sum = 8
ZX Spectrum Basic
10 LET totram=PEEK 23732 + 256 * PEEK 23733: REM Check that we have a 48k machine
20 IF totram < 65535 THEN PRINT "Your 16k Spectrum is too old": STOP
30 REM variables must exist before they are used, otherwise we get an error
40 REM we can poke a new error handler and check for variable not found.
50 REM I haven't implemented this, because I have forgotten the handler address
60 LET bloob = -4: REM make sure bloob exists, by creating it.
70 PRINT ABS(bloob): REM function will be present, ZX Spectrum Basic is standardized.
- Programming Tasks
- Programming environment operations
- Ada
- Aikido
- ALGOL 68
- Arturo
- AutoHotkey
- AWK
- BBC BASIC
- C
- C sharp
- C++
- Clojure
- Common Lisp
- D
- E
- EchoLisp
- Erlang
- Factor
- Forth
- FreeBASIC
- Frink
- GAP
- Go
- Haskell
- Icon
- Unicon
- Inform 7
- Io
- IS-BASIC
- J
- Java
- JavaScript
- Jq
- Jsish
- Julia
- Kotlin
- Lasso
- Lingo
- Locomotive Basic
- Logo
- Logtalk
- Lua
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- Octave
- Maxima
- MAXScript
- NetRexx
- Nim
- OCaml
- Oforth
- OxygenBasic
- Oz
- PARI/GP
- Perl
- Phix
- Phixmonti
- PHP
- PicoLisp
- PL/I
- Pop11
- PowerBASIC
- PowerShell
- PureBasic
- Python
- R
- Racket
- Raku
- Raven
- Retro
- REXX
- Ring
- RPL
- Ruby
- Rust
- Scala
- Slate
- Smalltalk
- Tcl
- TI-89 BASIC
- Toka
- UNIX Shell
- Ursala
- VBA
- Wren
- Wren-pattern
- Wren-math
- Yabasic
- Zig
- Zkl
- ZX Spectrum Basic
- 6502 Assembly/Omit
- 68000 Assembly/Omit
- 8086 Assembly/Omit
- GUISS/Omit
- M4/Omit
- ML/I/Omit
- Z80 Assembly/Omit
- Initialization