6.1.1345 ENVIRONMENT? environment-query CORE

( c-addr u -- false | i * x true )

c-addr is the address of a character string and u is the string's character count. u may have a value in the range from zero to an implementation-defined maximum which shall not be less than 31. The character string should contain a keyword from 3.2.6 Environmental queries or the optional word sets to be checked for correspondence with an attribute of the present environment. If the system treats the attribute as unknown, the returned flag is false; otherwise, the flag is true and the i * x returned is of the type specified in the table for the attribute queried.

See:

Rationale:

In a Standard System that contains only the Core word set, effective use of ENVIRONMENT? requires either its use within a definition, or the use of user-supplied auxiliary definitions. The Core word set lacks both a direct method for collecting a string in interpretation state (11.6.1.2165 S" is in an optional word set) and also a means to test the returned flag in interpretation state (e.g. the optional 15.6.2.2532 [IF]).

Testing:

\ should be the same for any query starting with X:
T{ S" X:deferred" ENVIRONMENT? DUP 0= XOR INVERT -> <TRUE>  }T
T{ S" X:notfound" ENVIRONMENT? DUP 0= XOR INVERT -> <FALSE> }T

ContributeContributions

AidanPitt-Brookeavatar of AidanPitt-Brooke [284] First testcase brokenSuggested Testcase2023-02-16 07:07:08

By my reading, the phrase DUP 0= XOR INVERT should transform the flag returned by ENVIRONMENT? into a false flag, regardless of what it started as. The first test case (querying "X:deferred") is thus guaranteed to fail.

I spent some time coming up with a testcase that I thought was sure to be useful, but then I read the specification here and at 3.2.6 Environmental queries more carefully. There appears to be nothing that prevents a standard-compliant system from simply responding false, "unknown", to all queries; the only restriction is that an attribute cannot cease to be known (and cannot change once known, if it is specified to be constant). With that in mind, ENVIRONMENT? is well and truly untestable.

AntonErtlavatar of AntonErtl

Confirmed: The X:deferred test case is wrong.

And yes, the lack of guarantees from ENVIRONMENT? means that writing discerning test cases for ENVIRONMENT? is a problem. What is possible is to write test cases that test the result if the environmental query succeeds.

Reply New Version

JimPetersonavatar of JimPeterson [425] Implementation Query?Request for clarification2026-02-20 15:44:56

Should there be a standard environmental query that returns a string specifying which Forth implementation is present? Of course, current implementations could already decide to provide such a query on their own, but guiding implementors into a standardized query could make things prettier, in general:

: which-impl
  ." Implementation: "
  S" IMPLEMENTATION" ENVIRONMENT? 0= IF S" unknown" THEN TYPE CR
;

: is-gforth
  S" IMPLEMENTATION" ENVIRONMENT? IF 6 MIN S" Gforth" COMPARE 0= IF TRUE EXIT THEN THEN FALSE
;

Or maybe it would be even better to encourage implementors to return a boolean based on "IMPLEMENTATION=<impl>" queries:

S" IMPLEMENTATION=GFORTH" ENVIRONMENT? [IF]
  \ Gforth-specific stuff
[ELSE]
  \ more generalized variant
[THEN]

The ability to determine the particular implementation seems very useful for optimization purposes, and ENVIRONMENT? feels like the facility in which to place such an ability.

Some implementations may already have added their own, implementation-specific queries, in which case adding more queries in the standard could have the potential for collisions. Should the standard encourage that, if an implementation adds their own specific queries that they prefix the string like "<impl>:<query>", for example: "GFORTH:NATIVE-FLOATING-POINT", and subsequently promise to never add standard queries containing a colon?

ruvavatar of ruv

Should there be a standard environmental query that returns a string specifying which Forth implementation is present?

Probably yes, similar to User-Agent string in browsers, but it should be used only for logs/messages, and never in place of feature detection.

Therefore, to avoid misuse, a mechanism for detection features should be established first. This will allow checking specific components rather than the system name/version.

The idea is that instead of is-gforth [if] ... [else] ... [then] we should use "some-gforth-feature" provided [if] ... [else] ... [then]. Note that "some-gforth-feature" can be provided by any forth system, not only by Gforth.

Typically, we would like to check for a specific word (or several words), or for a specific set of words. But we cannot rely on word names due to potential conflicts. Therefore, we need globally unique namespace identifiers, and we must check for the presence of a word name only in a specific namespace.

It is well known that URIs work well as namespace identifiers, because they are human-readable, unique, and don't need any additional central repository. So, a possible approach is as follows:

begin-using-namespaces \ turn on the corresponding recognizer

: sf ( -- sd.namespace ) "https://gforth.org/ns/some-feature" ;  \ sf -- for "some-feature"

\ check for a namespace
sf namespace-available [if] ... [else] ... [then]

\ make sure that the corresponding module is available
sf import-module

\ check for a specific word
[defined] sf:some-word [if]
  \ use the feature
  : my-word  ... sf:some-word ... ;
[else]
  \ Use some workaround
[then]


end-using-namespaces

JimPetersonavatar of JimPeterson

I definitely see how it is best to switch based on particular features, rather than implementations, but that only works when the implementer has successfully guessed, ahead of time, what the user is concerned about. The situation I'm trying to address (the situation I'm in) is when the implementer has not provided a method for querying about a particular quirk/feature and the user is left to try to work around it. For instance, no implementer is going to (generally) implement the query "fsqrt-is-buggy" successfully, but if the user finds himself in that situation, the only way to write portable code will be to check implementation and version.

All that said, I think we agree that both aspects are good to have. And when the feature-specific query exists, that's the better switch to use.

ruvavatar of ruv

but that only works when the implementer has successfully guessed, ahead of time, what the user is concerned about.

I don't see that.

A lazy approach is to provide all stable system-specific words under a single namespace. For example, Gforth specific words in the "https://gforth.org/" namespace. A better approach is to split them into modules whose implementations are independent of the implementation of other modules, and assign each module its own namespace.

It's worth nothing that, conceptually, the name of a word together with its namespace constitutes a fully qualified name, and a fully qualified name identifies an API (contract). For example, the seal word in the https://gforth.org/ namespace (or perhaps https://gforth.org/ns/search-order), provided by any implementation, must behave as specified in the Gforth documentation.

The situation I'm trying to address (the situation I'm in) is when the implementer has not provided a method for querying about a particular quirk/feature and the user is left to try to work around it.

If your choice is based on the Forth system name/version, you can use methods specific to that system without any loss. For example:

s" gforth" environment? [if] "000.007." starts-with [else] false [then]
[if] \ An implementation based on Gforth v0.7.* 
...
[else] \ A standard based implementation
...
[then]

For instance, no implementer is going to (generally) implement the query "fsqrt-is-buggy" successfully, but if the user finds himself in that situation, the only way to write portable code will be to check implementation and version.

For some bugs or capabilities it is true (see examples for web-browsers), but not for a known bug in fsqrt.

If you know that some system provides fsqrt with some known bug, it is better to detect this bug, not the system name/version. For example, check for precision loss in Newton’s method:

1e-38 fsqrt 1e-19 f- f0= invert [if] \ the bug exists
\ Use your implementation
include ./fsqrt-fix.fth
[then]
Reply New Version