As you know, 4tH has two stages: compilation and execution. _ANY_ variable declaration _WHEREVER_ it's made is picked up by the compiler and results _ALWAYS_ in a _GLOBAL_ variable. In some cases, (like VALUE) initialization is done during execution. You can _LIMIT_ the scope of any symbol in 4tH by using the keyword 'HIDE', but that doesn't mean the variable isn't there anymore. It's just that when you define it again, another global variable now carries its name.
And yes, one should limit the number of variables - "STAMP OUT THE VARIABLES" is one of Forth's dogma's. v3.64's R@, R'@ and R"@ words help you to achieve that easier as you can see in e.g. the GCIRCLE.4TH library member - which uses _NO_ variables at all. As does GBEZIER, DDA. On the other hand if you have routines which lots of variables, like GELLIPSE, sometimes it's better to use a few extra globals - for speed, clarity, etc. But it should be your last resort.
E.g. GBURST already manages FIVE variables on the stack. The DEFER is IMHO therefore "defensible". GELLIPSE has a "full house" with FOUR values on the datastack and THREE on the return stack. Of course, lots of predefined variables may result in a clogged namespace. By enclosing those internal variables with parenthesis and discarding their symbols by HIDE, 4tH tries to prevent this.
---8<---
Bonus material
Of course, there have been so many other people saying that concepts like dynamic memory, associative arrays, local variables, regexps, OOP, etc. "make Forth so much easier to use" that these concepts have been incorporated. However, NONE OF IT IS STANDARD (exaggerated - you catch my drift).
Of course, you can use it. 4tH has something of every single thing mentioned above. IMHO you just burden your language with a lot of stuff that doesn't really improve neither your program nor your programming. I never use associative arrays, locals, regexps or OOP. For regexps I'd rather use CHMATCH - which discards the use of compiling and executing your regexp. I think locals are just a horror - I'd rather use an extra stack (which is faster). OOP just results in bloatware and lasagna code IMHO. Thank you: it was hard enough to get away from spaghetti code forthy years ago ;-)
In short - yes, you can bolt all those "modern" things to 4tH (or Forth), but why don't you just program in C(++) where all this stuff is standard? Or do you want to show off a program in Forth that can be converted to C in a heartbeat - because it's using all the strengths of C and none of Forth?
Why do you think the preprocessor was written in 4tH? I shudder at the thought of converting it to C, because it uses all the strengths of 4tH.
The bottomline of Forth - which you have to internalize immediately: IT DOES NOTHING FOR YOU. Everything is exposed - and you've got to handle it yourself. The is no magic nanny that cleans up after you or checks things for you. You allocated it, now you're stuck with it. You have to make it work for you and you have to clean it up.
4tH is a bit nicer (therefore - the "friendly" Forth compiler), because not everything is exposed, most things are checked (in a very basic way) and some things are handled for you in the background. But there's enough left to give you loads of freedom to mess things up.
Also see:
Hans Bezemer