Digest #14 2016-12-13
In order to write cross platform and cross system libraries it is essential to have means to traverse a systems file structure. This proposal is based upon the only known (by the authors) widly adopted implementation in Gforth.
Authors: Ulrich Hoffmann & Gerald Wodni
Add new Type wdirid (or the like) to section 3.x
Words for traversal:
open-dir ( c-addr u – wdirid wior )
Open the directory specified by c-addr, u and return dir-id for futher access to it.
read-dir ( c-addr u1 wdirid – u2 flag wior )
Attempt to read the next entry from the directory specified by dir-id to the buffer of length u1 at address c-addr. If the attempt fails because there is no more entries, ior=0, flag=0, u2=0, and the buffer is unmodified. If the attempt to read the next entry fails because of any other reason, return ior<>0. If the attempt succeeds, store file name to the buffer at c-addr and return ior=0, flag=true and u2 equal to the size of the file name. If the length of the file name is greater than u1, store first u1 characters from file name into the buffer and indicate "name too long" with ior, flag=true, and u2=u1.
close-dir ( wdirid – wior )
Close the directory specified by dir-id.
mkdir ( c-addr u – wior )
create the directory c-addr u and all its parents Remark: renamed mkdir-parents to mkdir, removed unix-specific umask
Words for pathes:
Description take from the Node.js manual:
path-normalize ( c-addr-1 u1 -- c-addr-1 u-2 )
Normalize a string path, taking care of '..' and '.' parts. When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved.
path-basename ( c-addr-1 u1 -- c-addr-2 u-2 )
Return the last portion of a path. Similar to the Unix basename command.
path-dirname ( c-addr-1 u1 -- c-addr-2 u-2 )
Return the directory name of a path. Similar to the Unix dirname command.
path-extname ( c-addr-1 u1 -- c--addr-2 u-2 )
Return the extension of the path, from the last '.' to end of string in the last portion of the path. If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string.
path-absolute? ( c-addr-1 u1 -- f )
Determines whether path is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory.
path.join ( c-addr-1 u1 c-addr2 u2 -- c-addr-3 u3 )
Join all arguments together and normalize the resulting path. Arguments must be strings. Use implicit allocation?
That's an interesting point. Your example works on my system, as does the following variation:
: foo does> drop ." foo" ; create a foo a \ Displays foo : bar does> drop ." bar" ; synonym a a a \ Displays foo bar a \ Displays bar foo a \ Displays foo
bar is defined after
a is created. If this usage is deemed standard it provides a way of changing the action of a
create ... does> word retrospectively without the need for
defer. This is something I have wanted to do in the past. It works on GForth too.
If nothing else ISTM that this could be useful when debugging. For example, during development
: could be redefined to generate a
create does> drop ... definition. When something goes wrong
synonym could be used to alter a word's action to provide debugging information without having to recompile the system. I've not tried it but I don't see in principle why it wouldn't work. So I would support standardising the use of
does> for synonyms.
As noted recently on comp.lang.forth
is for deferred words also needs to be considered and probably
I was a bit premature with my suggestion - it only works on my system. If my example is amended to include a definition calling
a before the use of synonym i.e.
: foo does> drop ." foo" ; create a foo : baz a ; baz \ Displays foo : bar does> drop ." bar" ; synonym a a bar baz \ Displays bar on my system but not on GForth
bar Modifies the behaviour of
baz on my system but not GForth or VFX Forth.
In your original example:
: foo does> drop ." foo" ; : bar does> drop ." bar" ; create a foo synonym b a bar a
bar doesn't change the behaviour of
band so is different compared to Gforth. Win32 Forth is different as it crashes. So four systems with four different behaviours using
does> on synonyms.
I guess my example works (as in "does not produce an error") in many systems, but what is the effect? Is A changed or is it not? Do we want to standardize one of these behaviours, or not. One reason not to guarantee changing A is that it disallows optimizing DOES>. E.g.,
: method create ... does> ... ; method draw : foo ... draw ... ;
Here the compiler can inline DRAW. That's no longer possible if DRAW can be changed later.
Currently only interpretation and compilation semantics is copied by SYNONYM, so the property of being defined by CREATE is not guaranteed to be copied, and the example is non-standard.
Yes, synonyms of DEFERed words is another good point.
Another issue: Consider
wordlist constant W1 wordlist constant W2 W1 set-current create A1 W2 set-current W1 >order synonym A2 A1 :noname name>string type true ; W2 traverse-wordlist
Will this output A2 or A1? It seems to me that a basic invariant for traverse-wordlist is that, if you SEARCH-WORDLIST for the name produced by NAME>STRING in the traversed wordlist, you will find a word with that name, so it should output A2.
We also want to guarantee to convert 123e, 12.3e, 123e3 etc., so the specification is not a mistake. What I wonder about is if we should not also allow ".123e".
mtrute, it seems that you meant
WORDLIST CONSTANT gui gui IN : init-gl ( .. -- .. ) ... ; gui IN VARIABLE foo gui IN DEFER bar
CONSTANTit is quite awkward:
10 gui IN CONSTANT ten
- In some Forth-systems CURRENT wordlist should no be changed while a word is being defined, or it should be the same on
Which Forth systems do not put the word in the wordlist current during ":" if the current wordlist ist changed before ";"?
It seems to me that WLSCOPE requires at least as much effort to work as the requirement above. Therefore, standardizing that requirement is preferable to standardizing WLSCOPE.
I used something like this in my JenX XML parser (EuroForth 2001) by defining CREATION and DEF: as versions of CREATE and : respectively that took a wid as a parameter.
It wasn't strictly necessary, but it did mean I could easily control where particular types of words were defined without explicitly having to use SET-CURRENT.
: CENTITY entity? creation c, DOES> ... ;
All words defined with Centity go on the Entity wordlist.
Like IN, DEF: doesn't work if ; reads the Current wordlist, so I also would like that behaviour to be standardised.
If you make a synonym of a word with private data (e.g. a VALUE, a DEFER, or something with CREATE DOES>) then the two words share that data. Any change in the original is reflected in the synonym. If you don't want that, then instead you create a new instance with the same defining word.
So, if that is what you want, do you also need words like TO and IS to be applicable to the synonym as to the original?
That's fairly easy for user-defined definers, I think: All you need do is state that ticking or FINDing a synonym returns the xt of the original. But I think we've already decided not to go that route, and Synonyms may return a different xt from their originals. In any case, the xt of a DEFER or a VALUE is no use for changing the data, so all the Standard data - setting words might have to be modified to allow for the possibility of synonyms.
In short, a Synonym has the same interpretation and compilation behaviour of the original, affecting the same internal data. Any other behaviour that the original may have result from it being defined using a particular defining word, and are not inherited by the synonym.
"Will this output A2 or A1? It seems to me that a basic invariant for traverse-wordlist is that, if you SEARCH-WORDLIST for the name produced by NAME>STRING in the traversed wordlist, you will find a word with that name, so it should output A2."
Of course. A synonym may have the same xt as the original, but I don't see how it could have the same name token and still be a different word.
I don't think optimisation should be a significant driver in the functionality of a word - it may help swing the balance in some cases.
What do we mean by
synonym B A
Ba snapshot or clone of
Athat then has a future independent of what happens to
Ba reference to
Aso that it shadows whatever happens to
- or something in between.
Cloning is easy and doesn't require the use of
synonym so meaning 2 should be the desired aim.
We have identified issues with values, deferred words, children of
create ... does> ... words, inheritance of ambiguous conditions, and possibly wordlists.
Dealing with the latter first, I don't see what the issue is in your example -
A2 is clearly defined in wordlist
W2, the invokation of
traverse-wordlist is only looking in
W2 so why would anybody argue that
A1 whould be displayed?
Putting that aside and considering
synonym B A again:
For synonyms of colon definitions, variables and constants it seems clear that if
A is later redefined then
B still refers to the old definition of
A as the alternative would go against Forth tradition.
For values the question is whether
to A affects the value of both
A alone. Similarly
If we want consistency with variables and constants then
to A should change the value of both
B and that is what I would expect.
The situation with deferred words doesn't seem so clear. It could be argued that if the action of
A is changed by
defer! then that is equivalent to redefinition of
A and so should not change the action of
B, and vice versa. Alternatively it could be argued that
A is not really being redefined, it is more like a variable or value being changed and the change in behaviour is incidental, so both
B should remain in step. I would favour the latter.
For children of
create ... does> it seems to me that the best argument is that after
A has been created and there have been later definitions then the action of
A cannot be changed by an execution of
synonym B A is such a later definition which should, therefore prevent the action of
A being changed by
does>. My feeling is that we should probably make applying
does> to a synonym either ambiguous or forbid it. Changing the action of
A could easily lead to obscure bugs in a program. Of course the same could be said for deferred words.
opendir / readdir / closedir reminds me to old DOS ages. What exactly is the benefit of that transactional (?) model? Why not use simply traverse-dir? It in the the traverse-wordlist pattern, already known in the standard.
@ruv: my IN is a parsing word (uses tick), so I think, my example is valid. But that is not the point I am after. What I find strange is the use of vocabularies when we have wordlists at hand that are simpler to use and to understand.
For values the question is whether to A affects the value of both A and B or A alone. Similarly to B. If we want consistency with variables and constants then to A should change the value of both A and B and that is what I would expect.
I agree with that, but the question I was asking was rather:
Value A Synonym B A
TO B guaranteed to work?
I think it would naturally for a flag-setting TO but it may fail on some systems with a parsing TO,
Perhaps the most logical way to think of a
Synonym is that it creates a header that returns the same values for
NAME>COMPILE as the original. (I'm not saying this is the only way it can be done, but it is a way that the Standard allows - I think).
These are the only values (apart from the
NAME) that a Standard application can derive from the dictionary structure.
They are also set by:
DOES> associates the xt with an action that uses the data space address that it previously returned
IMMEDIATE sets the compilation action to execute the xt
SET-COMPILER whatever else we decide to set a particular non-default compiliation action.)
In each case they can only be set for the current definition, and are invariant once that definition is complete.
Given this a synonym is an exact substitute for the original, with the same Standard behaviour in all situations. For example, if the original can be ticked, then ticking the synonym returns the same xt. If ticking the original is an ambiguous condition, then a Standard program cannot tick the synonym, it may or may not respond in the same fashion as the the original (which may for example have been marked as 'compile-only') but that is beyond the scope of he Standard.
It doesn't seem to make much sense to combine SYNONYM with any of the other behaviour-setting words, because that implies you want something other than a synonym - something that can be provided in other ways:
Synonym B A DOES> C probably wouldn't work, or would change the definition of A, but the intention can be achieved by:
' A >BODY CONSTANT D : B D C ;
Synonym B A IMMEDIATE is trivially
: B A ; IMMEDIATE
And these definitions, not being synonyms of the original, do not share its xt.
Where A is defined by a user-defined
CREATE …DOES> word (there must be a shorter way of saying that) any word that uses
>BODY to manipulate its data will naturally also work on its synonym, which returns the same data and therefore references the same data.
I'm assuming that words manipulate DEFER and the like (which need not use
CREATE … DOES>) also access their data solely through their xt and therefore will work for a synonym that return the same xt. It's possible that IS, TO etc. need access to some other information in the dictionary header, so
SYNOYNYM would need to be smart enough to build the appropriate header for words defined by each of the Standard defining words.
That's another reason why the definition of SYNONYM is implementation-dependent, but I can't quite believe that any implementation would do things in such a roundabout way.