Naming conventions
larsbrinkhoff opened this issue · 28 comments
This comes up every now and then. Here's a summary I made:
Word | Explanation |
---|---|
0foo | Clear foo, reset foo |
foo0 | Initial state of foo |
+foo | Add to foo |
-foo | Remove from foo, or disable foo |
foo! | Store a foo at an address |
foo@ | Fetch a foo from an address |
!foo | Set foo, or enable foo |
@foo | Get foo (sorry GitHub user @foo) |
>foo | Convert to foo, or push onto foo |
foo> | Pop from foo |
?foo | Optionally do foo |
foo? | Return a boolean value |
foo' | Accept an address or xt as input |
'foo | Address or xt of foo |
foo" | Parse a string and do foo |
"foo | Accept a string as input |
foo, | Compile a foo, or assemble foo instruction |
#foo | Number of foos |
foo# | Foo index |
/foo | Size of foo |
foo: | Define a foo |
.foo | Print a foo |
[foo] | Do foo at compile time |
(foo) | Internal implementation of foo, runtime action of foo |
\foo | Foo with argument order reversed or permuted |
Adding @rdrop-exit's \foo
.
Nice list. The only one I have any comment on is /foo
, which sort of flies in the face of /string
. I always see /word
as a kind of slicing/dropping operation.
Here are a few more for your consideration:
- `foo Under foo
- {foo Beginning of foo, first foo
- foo} End of foo, last foo
- foo| Limit of foo
- ~foo Toggle or invert foo
- foo~ Synchronize, refresh, or update foo
- foo% Foo mask
- %foo Binary logarithm of foo
- _foo Transient foo
- foo; Exiting foo (as in
then;
) - foo^ Bailing foo
- foo' Foo cache or foo prime
- +foo Enable foo
- xfoo Foo exception
- fooo With overflow checking (as in
u*o
) - ufoo Unsigned foo
- bfoo Byte foo
- ?foo Foo on non-zero
- 0foo Foo on zero
- foo0 Initialize or reset foo
- fooz zero (as in
doz
difference or zero)
I probably have more but I'd need to go through my code to refresh my memory.
Nice idea to make a list of various naming conventions found in the wild. Many of them was also mentioned in "Thinking Forth", Appendix E, "Naming conventions" section — with examples.
On the other hand, excessive use of the special characters in the names produces a kind of gobbledygook. This effect also increases on using special syntaxes (via "recognizers" or something alike). Also a text become less predictable regarding where is a special syntax and where is a word name.
For example, when using wordlist::word syntax for qualified names, x::foo-size
is far better readable than x::/foo
or x::|foo|
.
When using 'word syntax to quote a word — the expressions like 'foo"
become too cryptic.
When using "foo bar" syntax for string literals — the words with names like "foo
become ambiguous.
So, I would not recommend to use the special characters in the names of API level, maybe except a few stable variants like foo?
or foo!
.
This effect also increases on using special syntaxes (via "recognizers" or something alike). Also a text become less predictable regarding where is a special syntax and where is a word name.
Special syntaxes are best avoided in my opinion. Forth is by choice semantics driven rather than syntax driven, this is a key to Forth's simplicity, hence Thinking Forth's enjoinder to "Let commands perform themselves".
"Let commands perform themselves" is a corollary to "Avoid expectations (in the input stream)". But actually we have [']
, POSTPONE
, S"
,etc, parsing words that do expectation (i.e. look ahead into the input stream) and violate the latter principle. And though they look like ordinary words, they implement a special syntax in the form of a prefix keyword with the set of well known problems. Actually it is an off-topic in this thread. It is better to start the new one to continue.
Yes, Forth already has a handful of simple prefix words that should only be used judiciously and with care. That does not invalidate the point of "Let commands perform themselves", which extols the benefits of not being syntax driven. The Forth approach is more akin to a sophisticated interactive assembler than a traditional parsed language compiler/interpreter.
It would be nice if you could add a column with pronunciation.
Nice thread.
I made a reference table for my own conventions in Ramen -
I like that 0word
convention. I've been using /word
for initializing things, which I learned from SwiftForth, but it's been conflicting lately with the sizeof convention which I also use... :/
As your projects get bigger, conventions become more and more important.
I'd like to propose that word!
be for setting foo as well as storing a foo somewhere when foo is a numeric datatype. And that !word
be used for indirect stores, i.e. where the data stack doesn't contain the source and/or destination.
word+
is missing - indirectly increase something.
I also kinda like the convention set by >in
- variables holding offsets. But I don't think a lot of people will agree with me ;)
I don’t see your reference table in a quick glance. Can you post a link to it?
Sorry! Bit out of it today. Here it is. https://docs.google.com/spreadsheets/d/1TDGwB0WVFC9nuAOQ2-o6ifNpvb8OILJtZK2zFm6ONxc/edit?ouid=104440289541124611001&usp=sheets_home&ths=true
Nice thread.
I made a reference table for my own conventions in Ramen -
I like that
0word
convention. I've been using/word
for initializing things, which I learned from SwiftForth, but it's been conflicting lately with the sizeof convention which I also use... :/
I prefer to use the foo0
convention for "foo reset/initialize", leaving 0foo
for "foo conditional on zero", i.e. the counterpart of ?foo
"foo conditional on not zero".
As your projects get bigger, conventions become more and more important.
I'd like to propose that
word!
be for setting foo as well as storing a foo somewhere when foo is a numeric datatype. And that!word
be used for indirect stores, i.e. where the data stack doesn't contain the source and/or destination.
@! ( x a -- )
would be a typical indirect store instruction, indirectly store cell x
through address a
, i.e. a contraction of @ !
. The analog for indirectly storing a byte would be @b! ( b a -- )
.
word+
is missing - indirectly increase something.I also kinda like the convention set by
>in
- variables holding offsets. But I don't think a lot of people will agree with me ;)
I need to start being more consistent with >foo
, sometimes I use it for offsets, sometimes for "convert to foo", and sometimes for "send to foo".
I prefer to use the
foo0
convention for "foo reset/initialize", leaving0foo
for "foo conditional on zero", i.e. the counterpart of?foo
"foo conditional on not zero".
?foo
is enough for me. You don't want to pack the code with too much information. If you think about it though, an on-true word and an on-false word are essentially the same thing, because 0= evaluates to true. ;)
But seriously, should the condition on which the word is executed change from non-zero to zero or vice versa, you'd have to change the name of the word! So I don't think that's all that useful.
@! ( x a -- )
would be a typical indirect store instruction, indirectly store cellx
through addressa
, i.e. a contraction of@ !
.
I tend not to like to use pointers of that kind so it's no wonder, I don't have a word like that!
Maybe indirect was the wrong term. I find myself saying, let's store (or fetch) something, but where it comes from or where it goes isn't necessarily on the stack. So if some concept such as a working buffer exists, !buffer
might save that to disk and @buffer
would read it. Maybe it would take a filename, or maybe that's in a string variable and there aren't any args.
I need to start being more consistent with
>foo
, sometimes I use it for offsets, sometimes for "convert to foo", and sometimes for "send to foo".
The first two to me are essentially the same. It's a transformation. That's a great concept for a single symbol to represent. I used to use it for "send to" too, but I stopped, instead using foo!
or coming up with a more creative name.
I try to limit the punctuation on the whole. If every word has punctuation from a vast set of conventions you get to a point where you're writing in something closer to C just more cryptic.
I prefer to use the
foo0
convention for "foo reset/initialize", leaving0foo
for "foo conditional on zero", i.e. the counterpart of?foo
"foo conditional on not zero".
?foo
is enough for me. You don't want to pack the code with too much information. If you think about it though, an on-true word and an on-false word are essentially the same thing, because 0= evaluates to true. ;)
But seriously, should the condition on which the word is executed change from non-zero to zero or vice versa, you'd have to change the name of the word! So I don't think that's all that useful.
I perfectly understand where you're coming from for high level words, but at the lowest level of a Forth though you're dealing with primitives, i.e. instructions for either a real or a virtual Forth stack machine. If the machine has "branch conditional on 0", "exit conditional on 0", "break conditional on 0" or any other "foo conditional on 0" instructions, 0foo
is the traditional Forth convention.
I don't deny a certain amount of finnickyness comes into the equation. My code is a weird mix of tidy and whatever-works. ;)
I'm very much enjoying this discussion. ;-) I will say that I have - partly - always been rather mystified by the Forth propensity for obscuring what's taking place. While it may make sense to the author that
0foo
means X andfoo0
means Y (and those meanings being orthogonal to each other), words likeinit-foo
,new-foo
, andfoo-zero?
are unambiguous and the code is now universally understood. Some symbols do have historical meaning in Forth (e.g.>foo
for "convert to foo" or "as foo"), but often times Forth code can be just as read-only as Perl code making use of $_ everywhere. When even short word definitions can require a significant cognitive load to parse and reason about, something's probably gone wrong along the way. Many of these short-hand word names came about due to space limitations and the word names actually being stored in ROM, less data to transfer serially, etc. And while there are likely still some space-limiting systems out there, certainly there's room (pun intended) for expansion. Anyway, IMHO, a legend at the top of the source code file should not be required. ;-) My 2p. Jeff
…
Forth programmers usually know their Forth systems and Forth code base inside and out, it's natural that over time they would develop shorthand naming conventions and idioms. I'd much prefer being provided a list of the shorthands that frequently occur in a code base then to have to wade through reams Cobol-esque looking source code. Just imagine if processor instruction sets used long hyphenated instruction names instead of short mnemonics, rotate-through-carry-right
, jump-on-not-zero
, convert-word-to-extended-doubleword
. It would drive me batty. :-)
So, I would not recommend to use the special characters in the names of API level, maybe except a few stable variants like
foo?
orfoo!
.
I like the distinction you make with API level words. If Forth programmers are going to start sharing more code we definitely need some amount of protocol. I wouldn't expect another programmer to adopt a library I've written that was filled with short words and punctuation marks due not only to the fact that punctuation isn't always obvious (in the case of uses of /
, '
, and nonstandard datatype symbols) but also to the high likelihood of name collision and/or limiting their own lexical expressiveness.
(A framework is different, Ramen is effectively a new language.)
Just imagine if processor instruction sets used long hyphenated instruction names instead of short mnemonics, rotate-through-carry-right, jump-on-not-zero, convert-word-to-extended-doubleword. It would drive me batty. :-)
It’s possible to get this right, as well, see Common Lisp (ahem, make-load-form-saving-slots
). Unlike Java and your hypothetical assembly, it compensates for this by being extremely concise. The factoring style is quite different from idiomatic Forth, though.
(What surprises me most in CL’s style, perhaps, is that it also unapologetically introduces extended versions of functions, but with descriptive name suffixes like -saving-slots
it’s not actually the hell that the Win32 *Ex
functions are.)
With Open Firmware, I adopted the convention of spelling-out-with-hyphens-without-abbreviations everything except extremely-commonly-used core words. The system had to be used by a lot of people, only a few of whom were going to use it so heavily that they could memorize cryptic shorthand...
(off-topic) @MitchBradley:
Thanks
I remember OpenBoot/FCode wistfully every time PC BIOS f*cks something...