Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I beleive that forth could supplant ruby and perl and python if it wanted to

280 views
Skip to first unread message

quiet_lad

unread,
May 16, 2012, 2:27:52 AM5/16/12
to
and java too

stuff I see at work takes dozens fo gigs ram and still can only fo 18 responses a second, whiel backups take 5 hours

marko

unread,
May 16, 2012, 3:50:43 AM5/16/12
to
We await the release of gavforth


Rod Pemberton

unread,
May 16, 2012, 6:51:59 AM5/16/12
to
"quiet_lad" <gavc...@gmail.com> wrote in message
news:2243442.558.1337149672996.JavaMail.geo-discussion-forums@pbbnx3...
> and java too
>
> stuff I see at work takes dozens fo gigs ram and still can only fo 18
> responses a second, whiel backups take 5 hours

18/s ...? Are you joking? Something is seriously wrong.


Rod Pemberton


BruceMcF

unread,
May 16, 2012, 10:59:25 AM5/16/12
to
On May 16, 2:27 am, quiet_lad <gavcom...@gmail.com> wrote:
> and java too
>
> stuff I see at work takes dozens fo gigs ram and still can only fo 18 responses a second, whiel backups take 5 hours

but gavino, forth doesn't want to, so the belief is untestable.

Jason Damisch

unread,
May 16, 2012, 12:28:21 PM5/16/12
to

> > stuff I see at work takes dozens fo gigs ram and still can only fo 18 responses a second, whiel backups take 5 hours

I'd like to see Forth become more successful. I think that it is
possible for some applications to run faster in Forth than in more
popular languages. This would probably be as a result of the program
being better composed due to Forth's interactive nature. Except I
suppose that Java is just going to be slow because of all of it's
internal machinery which make it Java.

Jason

Rod Pemberton

unread,
May 17, 2012, 4:08:12 AM5/17/12
to
"Jason Damisch" <jasond...@yahoo.com> wrote in message
news:11e6995a-c86c-41d8...@ki5g2000pbb.googlegroups.com...
>
> I'd like to see Forth become more successful. I think that it is
> possible for some applications to run faster in Forth than in more
> popular languages. This would probably be as a result of the program
> being better composed due to Forth's interactive nature. Except I
> suppose that Java is just going to be slow because of all of it's
> internal machinery which make it Java.
>

IMO, without change of some sort, Forth isn't going to become "more
successful." As is, it's as successful as it's ever going to be. Perhaps,
it should've been more successful, but wasn't justly recognized. That's a
matter of debate. Some of the changes needed to make Forth "more
successful" could very well be antithetical to the desires of current Forth
users... In order to see Forth become "more successful," you must have some
ideas about what to change first. Do you? Having some ideas implies
something frustrated you at some point in time with Forth. I'm sure that's
probably true for most Forth programmers, but they've accepted the pain or
avoid it. I think many of Forth's original problems have been preserved via
various justifications. If you don't have some ideas, maybe some questions
will inspire or jog the memory...


What would you change about Forth to make Forth more successful?

What syntax would you change to make Forth more successful?

Are the number of stacks in Forth adequate or insufficient?

Would you prefer a way to use registers directly?

How far would you go with such changes?

Would you suggest C's assignment operators as being useful to encourage more
usage of variables in Forth?

Would you introduce minimal syntax to Forth's parser? E.g., braces {} .

Would you suggest changing the parser so standard Forth notation, e.g., []
to mark compiling words, is required by Forth?

Would you introduce a type system for Forth?

Would you allow a pointer for >IN instead of an offset?

Would you allow null terminated strings instead of counted strings?

Would you rework Forth so that there were no IMMEDIATE words, but an
immediate operator?

Would you rename Forth's words to what they should be called?

etc


Rod Pemberton


Elizabeth D. Rather

unread,
May 17, 2012, 4:22:21 AM5/17/12
to
On 5/16/12 10:08 PM, Rod Pemberton wrote:
> "Jason Damisch"<jasond...@yahoo.com> wrote in message
> news:11e6995a-c86c-41d8...@ki5g2000pbb.googlegroups.com...
>>
>> I'd like to see Forth become more successful....
>
>
> What would you change about Forth to make Forth more successful?
>
> What syntax would you change to make Forth more successful?
>
> Are the number of stacks in Forth adequate or insufficient?
>
> Would you prefer a way to use registers directly?
>
> How far would you go with such changes?
>
> Would you suggest C's assignment operators as being useful to encourage more
> usage of variables in Forth?
>
> Would you introduce minimal syntax to Forth's parser? E.g., braces {} .
>
> Would you suggest changing the parser so standard Forth notation, e.g., []
> to mark compiling words, is required by Forth?
>
> Would you introduce a type system for Forth?
>
> Would you allow a pointer for>IN instead of an offset?
>
> Would you allow null terminated strings instead of counted strings?
>
> Would you rework Forth so that there were no IMMEDIATE words, but an
> immediate operator?
>
> Would you rename Forth's words to what they should be called?

It is a common fallacy among engineers to assume that failure to be
popular is due to inherent product flaws and can be remedied by fixing
said flaws.

Products succeed in a marketplace for a variety of reasons, of which
technical excellence isn't nearly as great a component as we would like.
More powerful influences include timing (right product at the right
time), product placement (e.g. Bell Labs introducing Unix via
universities), and marketing (a complex combination of promotion,
pricing, distribution channels, etc., all of which are well illustrated
by comparing Windows with MacOS).

I am quite sure that if you did any or all of these things it wouldn't
change Forth's image in the marketplace one iota, largely because not
many people would know about it except Forthers, who would prefer what
they already know.

Forth got off on the wrong foot in the marketplace in the 80's because
of factors I discussed in a different post. It's hard at this point to
change perceptions.

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com

"Forth-based products and Services for real-time
applications since 1973."
==================================================

A. K.

unread,
May 17, 2012, 5:43:12 AM5/17/12
to
So true. And there is no real market for programming languages per se,
unless you tie it to a commercial system or product. See the IBM
ecosphere, or ABAP for SAP, or MATLAB, to name a few.

Besides Forth has a strong foothold in its "niche". Change it too much
and it would be just another mee-too-thing. Factor and Joy (although
coming from another background) tried and failed.

Rod Pemberton

unread,
May 17, 2012, 10:22:58 AM5/17/12
to
"Elizabeth D. Rather" <era...@forth.com> wrote in message
news:_76dne-Wl4qiKCnS...@supernews.com...
...

> It is a common fallacy among engineers to assume that failure to be
> popular is due to inherent product flaws and can be remedied by fixing
> said flaws.
>

I wouldn't attribute that specifically to engineers, but otherwise true.

> Products succeed in a marketplace for a variety of reasons, of which
> technical excellence isn't nearly as great a component as we would like.
> More powerful influences include timing (right product at the right
> time), product placement (e.g. Bell Labs introducing Unix via
> universities), and marketing (a complex combination of promotion,
> pricing, distribution channels, etc., all of which are well illustrated
> by comparing Windows with MacOS).
>

Yes, but the hindight of history also usually reveals which products were in
fact technologically superior, even if they were failures at the time.
History has also shown that bringing back the failed product at the right
time, or introducing a similar product with excellent marketing will prove a
success. So, if timing and marketing were factors in the failure, the
product has a second chance. Forth has been around for a long time, but
hasn't found success as compared to some other languages. To me, what
you're saying is that Forth still hasn't managed to get the correct
combination of technical excellence, timing, marketing, and the other
factors correct despite being around for such a long time. Given that, at
some point, one must admit that maybe the product isn't so technically
perfect and needs fixing to appeal to others.

> I am quite sure that if you did any or all of these things it wouldn't
> change Forth's image in the marketplace one iota [...]

How do you know that for sure? Forth is a backend for itself, yes?
(meta-compilation) So, what if only modest changes were needed for Forth to
be the backend of Java or C? What if those changes were also some of the
changes needed to change attitudes about programming in Forth? Overnight,
things would be different for Forth.


Rod Pemberton



A. K.

unread,
May 17, 2012, 11:03:05 AM5/17/12
to
On 17.05.2012 16:22, Rod Pemberton wrote:

> How do you know that for sure? Forth is a backend for itself, yes?
> (meta-compilation) So, what if only modest changes were needed for Forth to
> be the backend of Java or C? What if those changes were also some of the
> changes needed to change attitudes about programming in Forth? Overnight,
> things would be different for Forth.

So in the end Forth could be the selfcompiling backend for any of those
languages used here?

http://rosettacode.org/wiki/Man_or_boy_test


How come that Forth isn't even among them?

van...@vsta.org

unread,
May 17, 2012, 12:02:47 PM5/17/12
to
Elizabeth D. Rather <era...@forth.com> wrote:
> It is a common fallacy among engineers to assume that failure to be
> popular is due to inherent product flaws and can be remedied by fixing
> said flaws.

It's a also common mental mechanism ("denial") to not accept that reality
provides a meaningful feedback mechanism.

At the high level, Forth lacks the amenities which are used by most modern
programmers. Fine, so we claim Forth is for the low level. But remember
that when I asked for a Forth implementation superior to:

void
memcopy(char *src, char *dest, int count)
{
while (count--) {
*dest++ = *src++;
}
}

I got lots of hand waving, but no Forth code (actually, I posted my tries in
both Forth and c18 code, but didn't outdo the C version). Because we all
know that Forth's great at doing something to one value, OK at two, and then
drops off a cliff when an algorithm involves three (or, God help us, more)
values used roughly equally.

So Forth isn't good for high level, it's for low level. But, no, not *that*
kind of low level. It's good at the kind it's good at. You owe it to Forth
to learn it, and if it's sucky, it's you, not the language.

That kind of argument really doesn't hold up when the rest of the world has
adopted languages at both the high and low level which have blown past Forth
and can barely see it in the rear view mirror. Which, in a vibrant
technology usually is the catalyst for an agonizing reappraisal followed by
fundamental changes. In a senescent technology, it's the time when you
circle the wagons and hunker down.

--
Andy Valencia
Home page: http://www.vsta.org/andy/
To contact me: http://www.vsta.org/contact/andy.html

A. K.

unread,
May 17, 2012, 12:08:16 PM5/17/12
to
On 17.05.2012 18:02, van...@vsta.org wrote:
> Elizabeth D. Rather<era...@forth.com> wrote:
>> It is a common fallacy among engineers to assume that failure to be
>> popular is due to inherent product flaws and can be remedied by fixing
>> said flaws.
>
> It's a also common mental mechanism ("denial") to not accept that reality
> provides a meaningful feedback mechanism.
>
> At the high level, Forth lacks the amenities which are used by most modern
> programmers. Fine, so we claim Forth is for the low level. But remember
> that when I asked for a Forth implementation superior to:
>
> void
> memcopy(char *src, char *dest, int count)
> {
> while (count--) {
> *dest++ = *src++;
> }
> }
>
>

You want a superior Forth program? Here it is:

CMOVE


van...@vsta.org

unread,
May 17, 2012, 12:58:39 PM5/17/12
to
A. K. <a...@nospam.org> wrote:
> CMOVE

So you admit Forth is a *user* of a low level language, not one itself.
That's fine so far as it goes, but what Forth primitive will provide:

int
movesum(char *src, char *dest, int count)
{
int result = 0;

while (count--) {
result += (*dest++ = *src++);
}
return result;
}

If you're always jumping out to C to do your coding, the obvious question is
whether it's worth the bother of driving it from Forth.

Nomen Nescio

unread,
May 17, 2012, 1:03:10 PM5/17/12
to
van...@vsta.org wrote:

> Elizabeth D. Rather <era...@forth.com> wrote:
> > It is a common fallacy among engineers to assume that failure to be
> > popular is due to inherent product flaws and can be remedied by fixing
> > said flaws.
>
> It's a also common mental mechanism ("denial") to not accept that reality
> provides a meaningful feedback mechanism.

I'll not speak for Elizabeth since she is quite capable of doing that.
Reading your rant, however, I believe you have missed the point.

Not everyone cares about advocacy nor does everyone think popularity is
something valuable. Elizabeth makes a living selling and teaching Forth. She
is in a much better position than you to know whether Forth is good enough
for what it's for, or not. If your arguments were valid, Elizabeth or Steven
or some of the other experts would discuss things with you. The careful
reader will understand the negative from the positive.

Elizabeth is very helpful to people who come with a positive attitude
and want to learn about Forth. And she offers a very nice evaluation version
for people to learn Forth with, and some really excellent doc, excellent by
all standards.

Nobody here is on your payroll and nobody is obligated to meet your little
challenges, indeed they use Forth because they like it and if you like it,
welcome, and if not, don't let the door hit you on the ass on the way out.

Your posts don't seem to have any productive purpose and most of the people
here are too intelligent not to realize that and you'll be talking to
yourself before very long. However, you probably will find Clod Flipperton
open to your tangents since that's right up his alley. Perhaps you're twins
or even the same person. Regardless, I'm certain nobody cares.

Have a nice day! Bye!

Andrew Haley

unread,
May 17, 2012, 1:27:35 PM5/17/12
to
van...@vsta.org wrote:
> Elizabeth D. Rather <era...@forth.com> wrote:
>> It is a common fallacy among engineers to assume that failure to be
>> popular is due to inherent product flaws and can be remedied by fixing
>> said flaws.
>
> It's a also common mental mechanism ("denial") to not accept that reality
> provides a meaningful feedback mechanism.
>
> At the high level, Forth lacks the amenities which are used by most modern
> programmers. Fine, so we claim Forth is for the low level. But remember
> that when I asked for a Forth implementation superior to:
>
> void
> memcopy(char *src, char *dest, int count)
> {
> while (count--) {
> *dest++ = *src++;
> }
> }
>
> I got lots of hand waving, but no Forth code (actually, I posted my
> tries in both Forth and c18 code, but didn't outdo the C version).

Forth programs use MOVE for that. Can you imagine any circumstances
in which any sane person would actually *want* to use an open-coded
memcopy? I doubt it. Just about every Forth (and indeed every C
library) in the universe uses a hand-coded loop for that, optimized
for byte/word/etc. copies.

But since you ask, it's:

over + swap ?do dup c@ i c! 1+ loop drop

> Because we all know that Forth's great at doing something to one
> value, OK at two, and then drops off a cliff when an algorithm
> involves three (or, God help us, more) values used roughly equally.
>
> So Forth isn't good for high level, it's for low level. But, no,
> not *that* kind of low level. It's good at the kind it's good at.
> You owe it to Forth to learn it, and if it's sucky, it's you, not
> the language.
>
> That kind of argument really doesn't hold up when the rest of the
> world has adopted languages at both the high and low level which
> have blown past Forth and can barely see it in the rear view mirror.

I'm not so sure. For many things, Forth is a very neat environment in
which you can get things done.

As a recent example that I can speak of, I wrote an experimental
software transactional memory system. I know how hard it is to do
this in other languages. For example, the GCC people have spent a
long time working on STM, and it requires big changes in the guts of
the compiler. And they aren't writing a transaction engine, this is
just what it took to do the language support. In an extensible
language, you can do this by writing a program: you don't have to
touch the compiler. I did the whole thing in about 400 lines of Forth
in a couple of weekends. As you might expect, the Forth version
doesn't have all the bells and whistles of the C version, so it's not
exactly comparable. But that's the Forth way: just do what's needed.

Andrew.

BruceMcF

unread,
May 17, 2012, 1:59:57 PM5/17/12
to
On May 17, 4:08 am, "Rod Pemberton" <do_not_h...@notemailntt.cmm>
wrote:
> IMO, without change of some sort, Forth isn't going to become "more
> successful."

The most likely change, though, would be to find some niche with
substantial future growth prospects for which Forth's advantages are
strong and where there it can either render some established source
code base more usable, or move into a niche for which there is not yet
an established course code base.

What that niche would be? No idea. Its not a job that I'd suggest
taking on based on hope for revenue or profit shares.

van...@vsta.org

unread,
May 17, 2012, 2:52:48 PM5/17/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> wrote:

>> void
>> memcopy(char *src, char *dest, int count)
>> {
>> while (count--) {
>> *dest++ = *src++;
>> }
>> }
>> ...

( Presumably:
: memcopy ( src dest count -- )
> over + swap ?do dup c@ i c! 1+ loop drop
( ; )

Andrew, you're one of the top "real" Forth coders on the group, and
yes, this is probably the best one can do WRT Forth style. Because
of the stack gymnastics I would've added some stack comments too.
As somebody pretty familiar with both C and Forth, it took me quite a bit
longer to convince myself of the Forth code.

> I'm not so sure. For many things, Forth is a very neat environment in
> which you can get things done.

How would you modify your version of the code to carry a sum? (Let's assume
we want to keep the code reentrant, so no global variable.) I'm guessing
it'd be time to break out locals.

> As a recent example that I can speak of, I wrote an experimental
> software transactional memory system. I know how hard it is to do
> this in other languages.

That seems like apples and oranges. The GCC stuff is to integrate shared
memory semantics into basic memory references. You seem to be talking about
something more like Python Durus? Where you have your own level of objects
which are used to fetch and store values?

Paul Rubin

unread,
May 17, 2012, 3:40:50 PM5/17/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
> ... the GCC people have spent a long time working on STM, and it
> requires big changes in the guts of the compiler... In an extensible
> language, you can do this by writing a program: you don't have to
> touch the compiler.

But it looks like there are several C library implementations:

http://en.wikipedia.org/wiki/Software_transactional_memory#C.2FC.2B.2B

I'd imagine it imposing some style constraints, but otherwise just
needing a few asm intrinsics rather than serious compiler hacking. I'm
not sure but I don't think Haskell's implementation required changing
the compiler. It's just some FFI calls to assembly language routines,
I'd imagine (I haven't looked).

Peter Knaggs

unread,
May 17, 2012, 4:38:38 PM5/17/12
to
Andrew Haley wrote:
>
> But since you ask, it's:
>
> over + swap ?do dup c@ i c! 1+ loop drop

This makes the, very common, assumption that a character is one
address unit wide. A portable version would be:

chars over + swap ?do count i c! [ 1 chars ] literal +loop drop

and we also have

: movesum ( src dest count -- sum )
chars over + 0 swap rot ?do
swap count dup i c! rot +
[ 1 chars ] literal +loop nip
;

Of course if you make sum a local variable it is a little easer.

--
Peter Knaggs

van...@vsta.org

unread,
May 17, 2012, 5:17:36 PM5/17/12
to
Peter Knaggs <p...@bcs.org.uk> wrote:
> : movesum ( src dest count -- sum )
> chars over + 0 swap rot ?do
> swap count dup i c! rot +
> [ 1 chars ] literal +loop nip
> ;

I suspect only the most fervent Forth'er would argue that the Forth version
is easier to read or to write. The source would bulk up a bit--but probably
be easier to follow--if local variables were used. As it is, the stack
gymnastics are about par for the course.

Also, can anybody feed that into their compiler and get better code than gcc
produced? Omitting the procedure call noise, at -O2 the code is:

(count in EBX, src in EDI, dest in ESI)

xorl %edx, %edx
testl %ebx, %ebx
je .L3
.L6:
movsbl (%edi,%edx),%ecx
movb %cl, (%esi,%edx)
addl $1, %edx
addl %ecx, %eax
cmpl %ebx, %edx
jne .L6
.L3:

Albert van der Horst

unread,
May 17, 2012, 6:30:31 PM5/17/12
to
In article <a1klp7...@mid.individual.net>, <van...@vsta.org> wrote:
>Elizabeth D. Rather <era...@forth.com> wrote:
>> It is a common fallacy among engineers to assume that failure to be
>> popular is due to inherent product flaws and can be remedied by fixing
>> said flaws.
>
>It's a also common mental mechanism ("denial") to not accept that reality
>provides a meaningful feedback mechanism.
>
>At the high level, Forth lacks the amenities which are used by most modern
>programmers. Fine, so we claim Forth is for the low level. But remember
>that when I asked for a Forth implementation superior to:
>
>void
>memcopy(char *src, char *dest, int count)
>{
> while (count--) {
> *dest++ = *src++;
> }
>}

What you show is is of course, not the c-code that is actually used
for a production memcpy() as per libc.

In fact it is a standard function that nobody bothers to write.
In Forth too it is an standard word : CMOVE.

If I had to add it to my Forth it would be a code word.

CODE CMOVE \ (source, dest, count)
MOV, X| T| BX'| SI| \ Save interpreter pointer
POP|X, CX| \ count
POP|X, DI| \ dest
POP|X, SI| \ source
REP: MOVS, B|
MOV, X| F| BX'| SI| \ Restore
NEXT,
END-CODE

Fast and practical. It is all about solutions, not whether it can be
written in high level code, and altogether not whether it can be
written in high level purely standard code.

[If you think that assembler code is involved, look at some actual
c-code from e.g. the gnu libc for memcpy().]

>
>I got lots of hand waving, but no Forth code (actually, I posted my tries in
>both Forth and c18 code, but didn't outdo the C version). Because we all
>know that Forth's great at doing something to one value, OK at two, and then
>drops off a cliff when an algorithm involves three (or, God help us, more)
>values used roughly equally.
>
>So Forth isn't good for high level, it's for low level. But, no, not *that*
>kind of low level. It's good at the kind it's good at. You owe it to Forth
>to learn it, and if it's sucky, it's you, not the language.
>
>That kind of argument really doesn't hold up when the rest of the world has
>adopted languages at both the high and low level which have blown past Forth
>and can barely see it in the rear view mirror. Which, in a vibrant
>technology usually is the catalyst for an agonizing reappraisal followed by
>fundamental changes. In a senescent technology, it's the time when you
>circle the wagons and hunker down.

My Forth does a good job in solving some though problems at
projecteuler. But I admit sometimes I use Python because I need
higher levels of abstraction that is hard to obtain using Forth.
(Like hash tables of objects.)
So yes, you have a point. Meanwhile I enjoy having absolute control
and knowing how my compiler looks from the bottom up.

>--
>Andy Valencia

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Bernd Paysan

unread,
May 17, 2012, 6:17:14 PM5/17/12
to
Rod Pemberton wrote:
> How do you know that for sure? Forth is a backend for itself, yes?
> (meta-compilation) So, what if only modest changes were needed for
> Forth to
> be the backend of Java or C? What if those changes were also some of
> the
> changes needed to change attitudes about programming in Forth?
> Overnight, things would be different for Forth.

Forth is already part of some more popular JavaScript engines, as
backend for JavaScript. Oh, as usual, it is a well-hidden secret, and
no JavaScript programmer is ever exposed to this Forth part. We all
benefit significantly, because our browsers are running JavaScript much
faster now.

The academic answer to this fact was "The Firefox JavaScript engine is
an utter mess!!!! There's even a Forth inside!!1111!!!eleven!1!!"

Forth has quite a hard time in computer science. It's not considered a
language, as it has no grammar (no abstract syntax apart from the simple
fact that all words are separated by white space). I went to the
"compiler" lecture, it took one semester. It did not go as far as to
code generation (that would have been "advanced compilers", and the
professor was so bad that I considered not to listen to him on this
topic), but the entire semester was dealing with grammars, with parser
generators (called "compiler compilers") and all that stuff that is - in
Forth - done by WORD. Or nowadays by PARSE-NAME. Hey, nobody would
spent more than 30 seconds explaining what PARSE-NAME does, and nobody
would go to a lecture to understand this thing.

My conclusion of this and other things I've seen is that many people can
only think in winded, complex ways. Forth is brutal simplicity. It's a
lot of "you don't need this" and "you don't need that". People start
with wrong assumptions, and their ego is too small to correct (or admit)
their mistakes. So they don't change things, they rather continue to
follow the winded path they took.

People have a hard time thinking out of the box. If you give them the
task "you have 9 dots on a sheet of paper, in a 3 by 3 array. Connect
them by straight lines, and find the minimum number of lines to do
this". Few people achieve it with less than five lines. The solution
is one single line. You have to wrap the paper around a bottle or some
other round thing to achieve this, but while the single line in 3D space
now is no longer straight, it is still straight on the paper (2D), the
problem space.

IMHO Forth was too early. Forth was created almost at the same time
when Algol 68 was designed (by committee). Algol 68 is utterly complex,
so complex that it took years to write compilers for it, but when you
look at it in the hindsight, it is no way as complex as C++. And C++ is
one of the most popular languages around. However, its popularity seems
to fade, because people actually are overwhelmed by C++'s complexity.
Including the compiler writers who have a hard time implementing all the
fancy ideas the standard committee has (they don't work on a "we want a
reference implementation" base as we do).

So there is now a movement away from Algol and its brain-childs, towards
more agile, more interactive, and simpler programming languages, but
they are all still way more complex than Forth.

The other problem of Forth is the toolbox approach programmers are
taught. All the popular languages like Java, Perl, Python, etc. have a
huge set of libraries that do what they are designed to. It took a long
time to write each library, and it takes some time to learn how to use
them. People believe that "all the complexity to do the complex tasks"
are hidden inside the library. The Forth approach to not use such
libraries, but just solve the problem at hand is just as alien as RPN.

We have done this Google Code Jam thing with the alien language, which
shows you how the mainstream thinks. They designed a programming
exercise (a really simple one), and they desigend it around *the* tool
people use these days: regular expressions. Aparently everything can be
solved by regexps (well, there is a formal proof that this is true ;-).
Forth is a language where you are told "no, we don't use regexps". Hey,
come on, a language without regexp is not a serious language. You can't
sell this, not at the moment.

It's like selling a bicycle in California as means of transportation
(not as sports utility). The target audience tells you that anything
less than a 6m long pickup is unacceptable, and you ask "what do you
achieve? You sit alone in your pickup, and go 5 miles with an average
speed of 10mph, because it's all clogged up? The bike will be faster,
and come on, it does *not* rain that often here", and then you get all
these arguments about the dog ("hey, you walk a dog, you don't drive a
dog"), about cup holders ("you'll wake up when you start pushing the
pedals, and actually, you can put a bottle here¹"), and finally about
bike lanes. There are bike lanes in California. One is in San
Francisco, the other is in San Diego (I'm exaggerating a little). And
there are actually people who use a bike to drive to work. I counted 10
bikes in the parking lot of Infinite Loop Drive 1, Cupertino; one was
even a recumbent. There are more Forthers working there than bikers,
but chances are high that there is an intersection between the two
groups.

¹) you can even have breakfast on your bike while riding.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/

Bernd Paysan

unread,
May 17, 2012, 6:43:30 PM5/17/12
to
Andrew Haley wrote:

> over + swap ?do dup c@ i c! 1+ loop drop

A bit simpler, use all idioms you have:

: move ( src dest len -- )
bounds ?do count i c! loop drop ;

Looks perfect, just 7 words.

The c18 unfortunately has a small flaw, it can only increment A, not B.
Otherwise, a move would be dead easy - one of the registers would have a
@+, the other a !+ instruction (so in total, the number of instructions
are the same). The incrementer is shared with the program counter
incrementer, no big deal for hardware.

: move
push b! a! @b+ !+ unext ;

I don't know why Chuck didn't do it that way. You need one register to
auto-increment on store, the other to auto-increment on load, then you
can do read-loops, write-loops, and copy-loops. Probably moving things
within one core is not that useful, anyways, since there are only 64
words - if you move, you move from one core to the next, and that's
possible - the move code is the same, just one of the two ports doesn't
increment - it's an IO port.

van...@vsta.org

unread,
May 17, 2012, 7:10:43 PM5/17/12
to
Bernd Paysan <bernd....@gmx.de> wrote:
> A bit simpler, use all idioms you have:
> : move ( src dest len -- )
> bounds ?do count i c! loop drop ;
> Looks perfect, just 7 words.

How about with the sum running? I just tried to retrofit it onto your
example and it wasn't looking very good.

> The c18 unfortunately has a small flaw, it can only increment A, not B.
> Otherwise, a move would be dead easy - one of the registers would have a
> @+, the other a !+ instruction (so in total, the number of instructions
> are the same). The incrementer is shared with the program counter
> incrementer, no big deal for hardware.

I can't remember if he had any spare opcode values. And, as you say, a great
mem copy on a 64 word machine is probably not very important.

Bernd Paysan

unread,
May 17, 2012, 7:15:54 PM5/17/12
to
A. K. wrote:
> How come that Forth isn't even among them?

Because real men don't do public penis size competitions.

We had a man-or-boy program here in c.l.f. a while ago (Gerry Jackson,
Jan 4), using a mini-oof based closure implementation. That's his code
(without the support stuff to implement lambda expressions):

include xmini_oof.fth
include lambda.fth

:lam func {< n >} [: drop n ;] constant ;lam
1 func one
0 func zero
-1 func -one

defer A

:lam (A) {< k x1 x2 x3 x4 x5 >}
[: {< B >}
k 1- to k
k B x1 x2 x3 x4 A
;]
k 0> if dup exec else drop x4 dup exec x5 dup exec + then
;lam
' (A) is A

Andrew Haley

unread,
May 17, 2012, 7:18:46 PM5/17/12
to
van...@vsta.org wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> wrote:
>
>>> void
>>> memcopy(char *src, char *dest, int count)
>>> {
>>> while (count--) {
>>> *dest++ = *src++;
>>> }
>>> }
>>> ...
>
> ( Presumably:
> : memcopy ( src dest count -- )
>> over + swap ?do dup c@ i c! 1+ loop drop
> ( ; )
>
> Andrew, you're one of the top "real" Forth coders on the group, and
> yes, this is probably the best one can do WRT Forth style. Because
> of the stack gymnastics I would've added some stack comments too.

Maybe. This is pretty vanilla Forth, really.

> As somebody pretty familiar with both C and Forth, it took me quite a bit
> longer to convince myself of the Forth code.
>
>> I'm not so sure. For many things, Forth is a very neat environment in
>> which you can get things done.
>
> How would you modify your version of the code to carry a sum? (Let's assume
> we want to keep the code reentrant, so no global variable.) I'm guessing
> it'd be time to break out locals.

Could be. Maybe do it on the stack. Locals are there to be useful.
But I rather think you're moving the goalposts. :-)

>> As a recent example that I can speak of, I wrote an experimental
>> software transactional memory system. I know how hard it is to do
>> this in other languages.
>
> That seems like apples and oranges. The GCC stuff is to integrate
> shared memory semantics into basic memory references. You seem to
> be talking about something more like Python Durus? Where you have
> your own level of objects which are used to fetch and store values?

No, I redefined @ ! and so on, so that you can just write normal Forth
(with some restrictions such as no I/O operations) and it works
transactionally. It's a matter of recompiling and it's a transaction.

Andrew.

Rod Pemberton

unread,
May 17, 2012, 7:19:28 PM5/17/12
to
"A. K." <a...@nospam.org> wrote in message
news:4fb51309$0$6557$9b4e...@newsspool4.arcor-online.net...
If someone wanted it to be, yes. I think some changes, or additions of
certain words would help.

> How come that Forth isn't even among them?
>

Most likely because the test's intended purpose is to test certain language
features that languages like Forth and C don't have as native components of
the language. You can read about that on Wikipedia's page. Even so, you
can see that C solutions are available, and C doesn't have those language
features. AISI, it should be easier for Forth than C, since's Forth doesn't
have C's typesystem. So, someone just needs to find or code a Forth
solution and post it.

From what I understand, the "Man or Boy test" tests the "inheritance" of
procedure local variables of a nested function during recursive function
calls, which generates numerous nested stackframes. The test checks whether
the saved locals reference the proper saved stackframe, or not. The more
powerful compiler, i.e., "Man" would generate references to the proper
stackframe. Of course, Forth doesn't have procedure local variables. It's
0-operand. I'd think this would require copying large numbers of stack
items, repeatedly, to duplicate them. This would probably be done with
Forth's MOVE. Does Forth have nestable words? In the context the test uses
them, I think that's a: "No." You'd need to be able to define one word
inside of another and be able to use both within:

: not-nested ... : nested ... ; ... nested ... not-nested ... ;

RECURSE allows for "not-nested" to be used within itself. But, AIUI, Forth
does not allow defining and using "nested" inside of "not-nested". Does
Forth have "dualism" (Wikipedia's term) for constants and functions (i.e.,
words)? Yes. The CFA or XT provided by ' (tick) is the same size integer
as constants on the data stack. Forth also has stacks. I'm not sure what
the other constraint about function references is exactly. It seems to be
the same as the "duality" to me. AIUI, Forth is as Turing complete as the
other programming languages, with the constraint that it's limited by the
machine's resources - as are all programming languages. I.e., the program
to implement the "Man or Boy test" will correctly solve for smaller values,
and then overflow the stack with larger values. This is true of all
languages. AIUI, infinite resources are required for true Turing
completeness.

Of course, I'm not from a CompSci background, and am not as familiar with
Turing completeness as I would like to be.

HTH,


Rod Pemberton


Doug Hoffman

unread,
May 17, 2012, 7:24:41 PM5/17/12
to
On 5/17/12 6:43 PM, Bernd Paysan wrote:
> Andrew Haley wrote:
>
>> over + swap ?do dup c@ i c! 1+ loop drop
>
> A bit simpler, use all idioms you have:
>
> : move ( src dest len -- )
> bounds ?do count i c! loop drop ;

An observation, not a criticism:

From Thinking Forth, chapter Factoring.
"Moore:
That particular phrase 'over + swap' is one that's right on the margin
of being a useful word. ... You can't see the manipulation in your
mind. 'over + swap' has greater mneumonic value than 'bounds'."

I will admit to not always agreeing with Charles Moore's thinking.

-Doug

Andrew Haley

unread,
May 17, 2012, 7:32:06 PM5/17/12
to
Paul Rubin <no.e...@nospam.invalid> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>> ... the GCC people have spent a long time working on STM, and it
>> requires big changes in the guts of the compiler... In an extensible
>> language, you can do this by writing a program: you don't have to
>> touch the compiler.
>
> But it looks like there are several C library implementations:
>
> http://en.wikipedia.org/wiki/Software_transactional_memory#C.2FC.2B.2B

There are, yes, if you want to do it all with library calls. (And
they're complicated: feel free to compare and contrast.) Language
binding and the way it fits with everything else is important. You
really want to be able to say something like

atomic {
node.next = head; head = node;
}

or

also atomic
: insert ( node) head @ over ! head ! ;
only forth

> I'd imagine it imposing some style constraints, but otherwise just
> needing a few asm intrinsics rather than serious compiler hacking.
> I'm not sure but I don't think Haskell's implementation required
> changing the compiler.

I'm pretty sure it did, but then Haskell has to do its shared
persistent storage through state monads anyway.

Andrew.

Andrew Haley

unread,
May 17, 2012, 7:33:47 PM5/17/12
to
Peter Knaggs <p...@bcs.org.uk> wrote:
> Andrew Haley wrote:
>>
>> But since you ask, it's:
>>
>> over + swap ?do dup c@ i c! 1+ loop drop
>
> This makes the, very common, assumption that a character is one
> address unit wide.

Yes. Elsewhere lies madness.

Andrew.

Andrew Haley

unread,
May 17, 2012, 7:38:15 PM5/17/12
to
Bernd Paysan <bernd....@gmx.de> wrote:
> Andrew Haley wrote:
>
>> over + swap ?do dup c@ i c! 1+ loop drop
>
> A bit simpler, use all idioms you have:
>
> : move ( src dest len -- )
> bounds ?do count i c! loop drop ;
>
> Looks perfect, just 7 words.

I'm a great believer in what Brodie called "cliches". OVER + SWAP is
one such: I just know what it does, I don't see it as three words with
a stack action. As for the abuse of COUNT... :-)

Andrew.

marko

unread,
May 17, 2012, 9:46:26 PM5/17/12
to
quiet_lad wrote:

> and java too
>
> stuff I see at work takes dozens fo gigs ram and still can only fo 18
> responses a second, whiel backups take 5 hours


Ruby, perl, python, java etc are basically interchangable. You choose
one of these languages for your project, hopefully getting the one best
suited to your application. If you pick the wrong one, it really does
not matter. You then get an interchangeable development infrastructure
based on rcs, cvs, git etc and host your app on apache or another
interchangble web server (or win/linux/mac desktop). Hire and fire
developers as necessary to get something that works enough to derive
enough income to survive.

The current flavours of forth are not suited to developing these kinds
of applications - all of the gurus here say so, and have said so many
times before. They have also pretty clearly stated what forth is good
for.

There are two fundemental reasons why forth cannot replace these
languages, development and delivery infrastructures.

1. The company you work for with gigs of ram and 18 responses per
second is making money. They are still in business. Why would they
change?

2. If you were to convince them to change to forth, how long would it
take to change over? Lets assume a typical server LAMP stack (linux,
apache, mysql and php) was 1 million lines of code. If you got 10:1
forth efficiency compression, you would have 100,000 lines of code to
develop. How long would this take to write, debug, deliver and deploy?


If you want forth to supplant ruby, perl, python and java then you have
3 options.

1. Write gavforth with the necessary features to do it. You will make
a fortune if you are sucessfull.
2. Propose a detailed plan as to what features gavforth needs to be
competitive and maybe manage and code an open source project. You will
atleast be famous.
3. Wait. Then wait some more while the rest of the world continues to
fly past.


What is it going to be?



Elizabeth D. Rather

unread,
May 18, 2012, 2:10:36 AM5/18/12
to
On 5/17/12 3:46 PM, marko wrote:
> quiet_lad wrote:
>
>> and java too
>>
>> stuff I see at work takes dozens fo gigs ram and still can only fo 18
>> responses a second, whiel backups take 5 hours
>
>
> Ruby, perl, python, java etc are basically interchangable. You choose
> one of these languages for your project, hopefully getting the one best
> suited to your application. If you pick the wrong one, it really does
> not matter. You then get an interchangeable development infrastructure
> based on rcs, cvs, git etc and host your app on apache or another
> interchangble web server (or win/linux/mac desktop). Hire and fire
> developers as necessary to get something that works enough to derive
> enough income to survive.
>
> The current flavours of forth are not suited to developing these kinds
> of applications - all of the gurus here say so, and have said so many
> times before. They have also pretty clearly stated what forth is good
> for.

Correct. It was an ignorant question.

> There are two fundemental reasons why forth cannot replace these
> languages, development and delivery infrastructures.
>
> 1. The company you work for with gigs of ram and 18 responses per
> second is making money. They are still in business. Why would they
> change?
>
> 2. If you were to convince them to change to forth, how long would it
> take to change over? Lets assume a typical server LAMP stack (linux,
> apache, mysql and php) was 1 million lines of code. If you got 10:1
> forth efficiency compression, you would have 100,000 lines of code to
> develop. How long would this take to write, debug, deliver and deploy?
>
>
> If you want forth to supplant ruby, perl, python and java then you have
> 3 options.
>
> 1. Write gavforth with the necessary features to do it. You will make
> a fortune if you are sucessfull.
> 2. Propose a detailed plan as to what features gavforth needs to be
> competitive and maybe manage and code an open source project. You will
> atleast be famous.
> 3. Wait. Then wait some more while the rest of the world continues to
> fly past.
>
>
> What is it going to be?

Languages developed for a specific purpose that include the appropriate
infrastructure for that purpose will always be a better choice than one
developed for something else.

However, before consigning Forth to the
very-very-low-end-no-infrastructure bucket, please note that by design
Standard Forth is intended as the basis for an *application-oriented
language* (Chucks term, from late 70's). Forth systems used in
particular application domains develop (quite quickly) appropriate
infrastructure for *that* application domain.

What you see in Standard Forth is rarely what you work with on an
application, at least in professional shops. These developers start by
choosing a Forth with an appropriate orientation (e.g. for Windows,
Linux, Mac, or one of the many cross-compilers offered by MPE and FORTH,
Inc.) and it will come with a lot of suitable extensions. Then they
start adding those features that they will need for what they're doing.
In this environment, the purpose a Standard serves is to help these
programmers identify where they are dependent on the implementation and
platform they chose, and (if they wish) segregate
implementation-specific code in well-identified places so as to
facilitate moving to a different platform should that become necessary.

The end result is a system that is as well-tailored to their application
as Ruby, perl, python, etc., are to their target application domains.

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com

"Forth-based products and Services for real-time
applications since 1973."
==================================================

Andrew Haley

unread,
May 18, 2012, 2:45:54 AM5/18/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> wrote:
> Paul Rubin <no.e...@nospam.invalid> wrote:

>>
>> But it looks like there are several C library implementations:
>>
>> http://en.wikipedia.org/wiki/Software_transactional_memory#C.2FC.2B.2B
>
> There are, yes, if you want to do it all with library calls. (And
> they're complicated: feel free to compare and contrast.) Language
> binding and the way it fits with everything else is important. You
> really want to be able to say something like
>
> atomic {
> node.next = head; head = node;

Oops, should be

node->next = head; head = node;

> }
>
> or
>
> also atomic
> : insert ( node) head @ over ! head ! ;
> only forth

FYI, I think a C library call version might look like

{
sigjmp_buf retry;
sigsetjmp (&retry);

TxStart (self, retry, false);
TxStore (self, &(node->next), TxLoad (self, &head));
TxStore (self, &head, node);
TxCommit (self);
}

Andrew.

Hugh Aguilar

unread,
May 18, 2012, 4:49:20 AM5/18/12
to
On May 17, 4:33 pm, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:
Straight Forth will assume that characters are one byte in size. I
won't have anything like CHARS etc..

I will have something similar to CELLS and all of that, so that
Straight Forth can support both 16-bit and 32-bit processors though.

Hugh Aguilar

unread,
May 18, 2012, 4:39:21 AM5/18/12
to
On May 17, 11:52 am, van...@vsta.org wrote:
> Andrew Haley <andre...@littlepinkcloud.invalid> wrote:
> >> void
> >> memcopy(char *src, char *dest, int count)
> >> {
> >>    while (count--) {
> >>        *dest++ = *src++;
> >>    }
> >> }
> >> ...
>
> ( Presumably:
> : memcopy ( src dest count -- )>  over + swap ?do  dup c@ i c!  1+  loop drop
>
> ( ; )
>
> Andrew, you're one of the top "real" Forth coders on the group, and
> yes, this is probably the best one can do WRT Forth style.  Because
> of the stack gymnastics I would've added some stack comments too.
> As somebody pretty familiar with both C and Forth, it took me quite a bit
> longer to convince myself of the Forth code.

: memcopy ( src dest count -- )
over + swap ?do  dup c@ i c!  1+  loop drop ;

Wow! I wish I were a "real" Forth programmer!

Just for the sake of simplicity, lets assume that we know ahead of
time that the destination is below the source. We still have the
problem that DO loops are generally inefficient. Here is a version
that uses a BEGIN loop (notice how similar this is to EXCHANGE in the
novice package):

: memcopy ( src dest count -- )
begin dup while
rover c@ rover c!
rot 1+ rot 1+ rot 1- repeat
3drop ;

Note that ROVER is defined like this:

macro: rover ( a b c -- a b c a )
2 pick ;

If being a "real" Forth programmer involves writing mind-blowing code,
here is a version that uses coroutines:

: get-data ( src dst cnt -- )
begin 3dup dive dup while rot 1+ rot 1+ rot 1- repeat
3drop ;

: put-data ( src dst cnt -- )
get-data
begin
dup while drop swap c@ swap c! dive repeat 3drop ;

There is actually less "stack juggling" in this version, as we don't
need to use ROVER to access the pointers. That is the upside of mind-
blowing complexity. :-)

Note that DIVE is defined like this:

: dive ( -- ) \ r: ret-adr ip -- ip ret-adr
2r> >r >r ;

\ the return stack is from the perspective of the word that is calling
DIVE

Stephen Pelc

unread,
May 18, 2012, 5:41:57 AM5/18/12
to
On 17 May 2012 21:17:36 GMT, van...@vsta.org wrote:

>Also, can anybody feed that into their compiler and get better code than gcc
>produced? Omitting the procedure call noise, at -O2 the code is:
>
>(count in EBX, src in EDI, dest in ESI)
>
> xorl %edx, %edx
> testl %ebx, %ebx
> je .L3
>.L6:
> movsbl (%edi,%edx),%ecx
> movb %cl, (%esi,%edx)
> addl $1, %edx
> addl %ecx, %eax
> cmpl %ebx, %edx
> jne .L6
>.L3:

I tried the following on VFX:

: movesum \ src dest len -- sum
0 -rot bounds ?do \ -- src sum
over c@ dup i c! + swap 1+ swap
loop
nip
;

The inner loop is
\ .L6
( 004C7E80 8B5500 ) MOV EDX, [EBP]
( 004C7E83 0FB612 ) MOVZX EDX, Byte Ptr 0 [EDX]
( 004C7E86 8B0C24 ) MOV ECX, [ESP]
( 004C7E89 8811 ) MOV 0 [ECX], DL
( 004C7E8B 03DA ) ADD EBX, EDX
( 004C7E8D 8B5500 ) MOV EDX, [EBP]
( 004C7E90 42 ) INC EDX
( 004C7E91 83042401 ) ADD [ESP], 01
( 004C7E95 8344240401 ) ADD [ESP+04], 01
( 004C7E9A 895500 ) MOV [EBP], EDX
( 004C7E9D 71E1 ) JNO 004C7E80
\ .L3

That's 11 instructions versus 6. Not so good. What would we need
to do to improve this? Remember that the design decisions and
financing of gcc and VFX are very different. gcc is supported by
major corporations. VFX is designed to be a fast one-pass compiler
for Forth.

What's really killing us here is the memory traffic. The memory
traffic arrives because
a) we generate a canonical stack at loop boundaries,
b) Forth is bad at handling four items

There are two solutions
a) adjust the canonical stack model at inner block
boundaries. This is doable at the expense of complexity
and the x86 code generator is already 6000 lines of source.
b) Use register-based locals. I believe Marcel does this
in some versions of iForth.

I'm already getting complaints that the VFX compiler is not fast
enough. Let's change the comparisons. VFX compiles 1M lines
of Forth source code in about 40 seconds on an i7. How long
does gcc take at -O2 ? Heavens to Murgatroyd, if you stay with
C, you'll never get any work done! And you have surrendered
your Open Source soul to Intel and AMD!

Teasing aside, there are reasons for the differences. If I
spent as much time and effort on VFX as has been spent on gcc,
I'm sure I could get similar results. A more productive
focus is to ask what Forth is good for and to understand the
design decisions in the compilers for Forth and C.

So, where do I get benefit from Forth? From the use of an
interactive, extensible language. I spent some of Wednesday
listening to a presentation about the debug tools needed for
gdb. I was appalled by the technology required when you use
the wrong approach to debugging.

But thanks for retriggering the code generation competition.
I now have work to do ...

Stephen

--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads

Andrew Haley

unread,
May 18, 2012, 5:50:08 AM5/18/12
to
Hugh Aguilar <hughag...@yahoo.com> wrote:
> On May 17, 11:52?am, van...@vsta.org wrote:
>> Andrew Haley <andre...@littlepinkcloud.invalid> wrote:
>> >> void
>> >> memcopy(char *src, char *dest, int count)
>> >> {
>> >> ? ?while (count--) {
>> >> ? ? ? ?*dest++ = *src++;
>> >> ? ?}
>> >> }
>> >> ...
>>
>> ( Presumably:
>> : memcopy ( src dest count -- )> ?over + swap ?do ?dup c@ i c! ?1+ ?loop drop
>>
>> ( ; )
>>
>> Andrew, you're one of the top "real" Forth coders on the group, and
>> yes, this is probably the best one can do WRT Forth style. ?Because
>> of the stack gymnastics I would've added some stack comments too.
>> As somebody pretty familiar with both C and Forth, it took me quite a bit
>> longer to convince myself of the Forth code.
>
> : memcopy ( src dest count -- )
> over + swap ?do dup c@ i c! 1+ loop drop ;

Let's try this with VFX. The inner loop is:

1: MOVZX EDX, Byte Ptr 0 [EBX]
MOV ECX, [ESP]
MOV 0 [ECX], DL
INC EBX
ADD [ESP], 01
ADD [ESP+04], 01
JNO 1

It's not perfect because the loop parameters are kept in memory,
presumably because x86/32 is desperately short of registers, but it's
not bad.

> Wow! I wish I were a "real" Forth programmer!

Don't we all.

> Just for the sake of simplicity, lets assume that we know ahead of
> time that the destination is below the source. We still have the
> problem that DO loops are generally inefficient. Here is a version
> that uses a BEGIN loop (notice how similar this is to EXCHANGE in the
> novice package):
>
> : memcopy ( src dest count -- )
> begin dup while
> rover c@ rover c!
> rot 1+ rot 1+ rot 1- repeat
> 3drop ;
>
> Note that ROVER is defined like this:
>
> macro: rover ( a b c -- a b c a )
> 2 pick ;

The inner loop is:

2: TEST EBX, EBX
JZ/E 2
MOV EDX, [EBP+04]
MOVZX EDX, Byte Ptr 0 [EDX]
MOV ECX, [EBP]
MOV 0 [ECX], DL
MOV EDX, [EBP+04]
INC EDX
MOV ECX, [EBP]
INC ECX
DEC EBX
MOV [EBP], ECX
MOV [EBP+04], EDX
JMP 1
1:

So, you've succeeded in making the code much harder to understand and
you've made it slower. What was it you were trying to achieve?

Andrew.

Andrew Haley

unread,
May 18, 2012, 5:55:35 AM5/18/12
to
Stephen Pelc <steph...@mpeforth.com> wrote:

> What's really killing us here is the memory traffic. The memory
> traffic arrives because
> a) we generate a canonical stack at loop boundaries,
> b) Forth is bad at handling four items
>
> There are two solutions
> a) adjust the canonical stack model at inner block
> boundaries. This is doable at the expense of complexity
> and the x86 code generator is already 6000 lines of source.
> b) Use register-based locals. I believe Marcel does this
> in some versions of iForth.
>
> I'm already getting complaints that the VFX compiler is not fast
> enough. Let's change the comparisons. VFX compiles 1M lines
> of Forth source code in about 40 seconds on an i7. How long
> does gcc take at -O2 ? Heavens to Murgatroyd, if you stay with
> C, you'll never get any work done! And you have surrendered
> your Open Source soul to Intel and AMD!

LOL! I would have thought the more interesting question was whether
to stick with the register-starved x86/32 model. 64-bit is where
you'll get the big win with locals and/or stack in registers.

But really, why is all this micro-optimization such a huge deal
anyway? I think it's rather silly. Are your customers clamouring for
better code generation?

Andrew.

Arnold Doray

unread,
May 18, 2012, 6:32:02 AM5/18/12
to
On Fri, 18 May 2012 11:46:26 +1000, marko wrote:

> There are two fundemental reasons why forth cannot replace these
> languages, development and delivery infrastructures.

Really?

There are lots of new languages like Clojure, Scala, etc. that are making
inroads into old territory. Ruby was obscure (except in Japan) until
Rails came along.

Your reasoning could also be applied to Forth in the 1980's, when it had
was hugely popular. If your resoning is correct, it should have remained
so. What happened?

Languages succeed (or fail) depending on a variety of factors. IMHO for
Forth, it is the lack of immediately available facilities/libraries and
other scaffolding that modern application developers take for granted.
Forth is in a death-spiral from this point of view because its main
adherents have an embedded focus, where libraries, etc are viewed with
some skepticism -- for good reason. But Forth is probably dying even in
its main niche. I was talking to a young (late 20s?) embedded hardware
engineer who hadn't even heard of Forth. He thought I meant Fortran. He
uses C.

It's sad, because Forth is a beautiful, practical languges which has the
potential to be relevant even outside it embedded niche.

Cheers,
Arnold









Mark Wills

unread,
May 18, 2012, 6:24:39 AM5/18/12
to
> Stephen Pelc, stephen...@mpeforth.com
> MicroProcessor Engineering Ltd - More Real, Less Time
> 133 Hill Lane, Southampton SO15 5AF, England
> tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
> web:http://www.mpeforth.com- free VFX Forth downloads- Hide quoted text -
>
> - Show quoted text -

Introduce the concept of registers into the Forth language.

Seriously. Where stack juggling becomes an issue, registers are the
antidote. It would often pay off to spend some time getting data from
the stack into registers, performing the work with the registers, and
populating the stack again. Problem solved.

For example, what if the memcpy routine could be written in Forth like
this:

: memcpy ( src dst cnt --)
->R0 \ count to R0
->R1 \ dst to R1
->R2 \ src to r2
BEGIN
(R2+)->(R0+) \ copy source to destination with post increment
R0-- \ decrement count
R0-> \ push count to stack
UNTIL
;

It's not machine code. But it looks like it. It's Forth. The point is,
the stack isn't used until the end where the count is placed on the
stack as a parameter to UNTIL.

I think it's neat. This wouldn't be a good idea on native
(registerless) Forth CPUs however. I admit that. Just build DMA in and
you don't need a memcpy ;-)

However, this discussion raises an interesting point. Most Forth
programmers would have the ability to drop into assembler and simply
write something in machine code if they needed to - if they thought
the stack was a bottleneck in a particular routine, for example. Most
C programmers wouldn't know how to do that. I make that statement,
because I just asked an office of 9 software engineers (who code C
(not C++) day in day out) if they could write memcpy in assembler for
PC104 stacks that we use. They all said they wouldn't know how to do
it, but then they all pointed out that they wouldn't have to - there
are library calls in QNX to do it all for you!

"Oooooooooohhhhhhhh!" I said. "That's okay then, forget I asked" :-)

*THAT* is the difference between C and Forth. The difference is
between the chair and the keyboard, in the caliber of the programmer.

That's not to say all C programmers fit into that category, of course.

Andrew Haley

unread,
May 18, 2012, 7:10:47 AM5/18/12
to
Mark Wills <markrob...@yahoo.co.uk> wrote:
>
> Introduce the concept of registers into the Forth language.

What on Earth for? Just use locals. Put locals in registers.

> Seriously. Where stack juggling becomes an issue, registers are the
> antidote. It would often pay off to spend some time getting data from
> the stack into registers, performing the work with the registers, and
> populating the stack again. Problem solved.
>
> For example, what if the memcpy routine could be written in Forth like
> this:
>
> : memcpy ( src dst cnt --)
> ->R0 \ count to R0
> ->R1 \ dst to R1
> ->R2 \ src to r2
> BEGIN
> (R2+)->(R0+) \ copy source to destination with post increment
> R0-- \ decrement count
> R0-> \ push count to stack
> UNTIL
> ;
>
> It's not machine code.

Yes it is! Why wouldn't

: memcopy { s d n}
begin
s c@ d c!
1 +to s 1 +to d
-1 +to n
n 0= until ;

generate the same code? No reason I can see.

Andrew.

Rod Pemberton

unread,
May 18, 2012, 7:20:31 AM5/18/12
to
<van...@vsta.org> wrote in message news:a1l87g...@mid.individual.net...
> Peter Knaggs <p...@bcs.org.uk> wrote:
> > : movesum ( src dest count -- sum )
> > chars over + 0 swap rot ?do
> > swap count dup i c! rot +
> > [ 1 chars ] literal +loop nip
> > ;
>
> I suspect only the most fervent Forth'er would argue that the Forth
> version is easier to read or to write. The source would bulk up a
> bit--but probably be easier to follow--if local variables were used.
> As it is, the stack gymnastics are about par for the course.
>
> Also, can anybody feed that into their compiler and get better code
> than gcc produced?


By feeding different C code to GCC, you can get GCC to produce smaller code
for the body. GCC is superb with optimizations involving constants, but it
is horrid on x86 with variables of a byte in size. It's so-so on
control-flow. The more complicated the flow control, the worse it gets. A
while(1) with an if-break usually optimizes better than a while() with some
condition. Sometimes, it optimizes much better. A for() with conditions is
usually the worst. You can unroll the for() completely and get much better
optimization. Also, sometimes declaring a local scope variable in GCC
- which gets a parameter copied to it - will sometimes allow you to
produce much better code too. GCC generally doesn't emit byte sized
instructions, i.e., emitting eax instead of al, etc. With proper coding,
you can get it to do so. This - byte sized instructions, i.e., 8-bit
registers, e.g., for char - eliminates lots of logical and's of
32-bit/16-bit registers with 0xFF.


Let's repost your original C code:

> void
> memcopy(char *src, char *dest, int count)
> {
> while (count--) {
> *dest++ = *src++;
> }
> }

...

> Omitting the procedure call noise, at -O2 the code is:
>
> (count in EBX, src in EDI, dest in ESI)
>
> xorl %edx, %edx
> testl %ebx, %ebx
> je .L3
> .L6:
> movsbl (%edi,%edx),%ecx
> movb %cl, (%esi,%edx)
> addl $1, %edx
> addl %ecx, %eax
> cmpl %ebx, %edx
> jne .L6
> .L3:
>

Well, you've made a mistake there. Apparently, no one else here noticed.
%edi, %esi, and %ebx are not initialized. So, the routine posted is
incomplete. The 3 additional instructions to initialize %ebx, %edi and %esi
are not "procedure call noise", but parameter initialization. "procedure
call noise" is the prolog(ue) and epilog(ue) with %ebp and %esp. However,
I'll continue the same way for my post below...

So, that's 9 instructions, or 12 including parameter initialization.

For reference, since I don't know version of GCC you used, GCC 3.4.1 -O2
produces for your C code above, without "procedure call noise", the
following:

jmp L7
L9:
movb (%ebx), %al
incl %ebx
movb %al, (%ecx)
incl %ecx
L7:
decl %edx
cmpl $-1, %edx
jne L9

At 8 (or 11 with parms), that's one less instruction. There seems to be an
extra check for an initial zero for 'count' generated by the version of GCC
you're using. It also appears the GCC code generator was switched from
'incl' to 'addl' even for non 64-bit code. I'm not sure why your version of
GCC (4.x.x series?) chose to use a signed move byte to long instruction.
It's "slow." (That's not move string in GAS syntax.)


Now, let's take this C code:

void memcpy(char *src, char *dst, int count)
{
int cx=0;

while(1)
{
*(dst+cx)=*(src+cx);
cx++;
if(cx==count)
break;
}
}


Yeah, you'd *never* code that, "right"? (wrong)


For GCC 3.4.1 -O2 it generates, without "procedure call noise":

L11:
movb (%esi,%edx), %al
movb %al, (%ebx,%edx)
incl %edx
cmpl %ecx, %edx
jne L11

That's 5 (or 8 with parms) resulting in 3 fewer instructions for the main
body. I'm not sure about the timings. Unfortunately, the "procedure call
noise" adds two more instructions in this case. I.e., the net is one
less. You shouldn't ignore "procedure call noise".

Unfortunately, in this case, the gain wasn't much. But, I've seen other
cases where the gain was substantial. I may just be a matter of rewriting
it again, a different way.

So, if I had a Forth compiler, I'd try for something like that sequence
above, i.e., 8 instead of 12.

With -O2 this C sequence generates the same assembly sequence. Without it,
IIRC, generally the subscript operator [] adds an additional instruction per
use.

void memcpy(char *src, char *dst, int count)
{
int cx=0;

while(1)
{
dst[cx]=src[cx];
cx++;
if(cx==count)
break;
}
}

HTH,


Rod Pemberton









marko

unread,
May 18, 2012, 7:27:26 AM5/18/12
to
Arnold Doray wrote:

> On Fri, 18 May 2012 11:46:26 +1000, marko wrote:
>
>> There are two fundemental reasons why forth cannot replace these
>> languages, development and delivery infrastructures.
>
> Really?

This is poor grammer on my part - whilst development and delivery
infrastuctures are crucial, I was pointing forward to the fact that
many will accept poor quality, hence stifling innovation and that the
new product must hit a sufficiently large need first time in an already
crowded and confused market.


>
> There are lots of new languages like Clojure, Scala, etc. that are
making
> inroads into old territory. Ruby was obscure (except in Japan) until
> Rails came along.
>
> Your reasoning could also be applied to Forth in the 1980's, when it
had
> was hugely popular. If your resoning is correct, it should have
remained
> so. What happened?

That I don't know, I first used it in 1987 and I still use it now for
some things.

>
> Languages succeed (or fail) depending on a variety of factors. IMHO
for
> Forth, it is the lack of immediately available facilities/libraries
and
> other scaffolding that modern application developers take for
granted.
> Forth is in a death-spiral from this point of view because its main
> adherents have an embedded focus, where libraries, etc are viewed
with
> some skepticism -- for good reason. But Forth is probably dying even
in
> its main niche. I was talking to a young (late 20s?) embedded
hardware
> engineer who hadn't even heard of Forth. He thought I meant Fortran.
He
> uses C.

I think Elizabeth was spot on regarding extensions / libraries /
facilities / frameworks, whatever you like to call them. Where Forth
has suitable extensions available, the choice would be easier. I'd
never thought of using the standard as a baseline here, tending to work
on code everything to understand the problem phillosophy. Without
readily available domain specific extensions you have to make the
choice between changing to a new language or extending the existing
one. Unfortunately it is far too easy to defer the choice to someone
else, if you are even given a choice.

>
> It's sad, because Forth is a beautiful, practical languges which has
the
> potential to be relevant even outside it embedded niche.


I totally agree. However applying Forth Application Oriented thinking
to any language should get you a better product especially in large
systems.

Cheers

Marko


>
> Cheers,
> Arnold

Hugh Aguilar

unread,
May 18, 2012, 7:40:31 AM5/18/12
to
On May 18, 2:50 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:
> So, you've succeeded in making the code much harder to understand and
> you've made it slower.  What was it you were trying to achieve?

I don't think that the BEGIN version is "much harder to understand"
--- personally, I've thought that DO loops were confusing since 1984
--- I won't support DO loops at all in Straight Forth.

Anyway, here it is in SwiftForth:

: memcopy ( src dest count -- )
over + swap ?do dup c@ i c! 1+ loop drop ; ok
see memcopy
480B1F 0 [EBP] EBX ADD 035D00
480B22 0 [EBP] EAX MOV 8B4500
480B25 EBX 0 [EBP] MOV 895D00
480B28 EAX EBX MOV 8BD8
480B2A 0 [EBP] EBX CMP 3B5D00
480B2D 480B3A JNZ 750B
480B2F 4 [EBP] EBX MOV 8B5D04
480B32 8 # EBP ADD 83C508
480B35 480B70 JMP E936000000
480B3A 40235F ( (DO) ) CALL E82018F8FF
480B3F 4 # EBP SUB 83ED04
480B42 EBX 0 [EBP] MOV 895D00
480B45 EAX EAX XOR 31C0
480B47 0 [EBX] AL MOV 8A03
480B49 EAX EBX MOV 8BD8
480B4B 4 # EBP SUB 83ED04
480B4E EBX 0 [EBP] MOV 895D00
480B51 0 [ESP] EBX MOV 8B1C24
480B54 4 [ESP] EBX ADD 035C2404
480B58 0 [EBP] EAX MOV 8B4500
480B5B AL 0 [EBX] MOV 8803
480B5D 4 [EBP] EBX MOV 8B5D04
480B60 8 # EBP ADD 83C508
480B63 EBX INC 43
480B64 0 [ESP] INC FF0424
480B67 480B3F JNO 0F81D2FFFFFF
480B6D 8 # ESP ADD 83C408
480B70 0 [EBP] EBX MOV 8B5D00
480B73 4 # EBP ADD 83C504
480B76 RET C3 ok
see (do)
40235F EDX POP 5A
402360 0 [EBP] EAX MOV 8B4500
402363 -80000000 # EAX ADD 0500000080
402368 EAX PUSH 50
402369 EAX EBX SUB 29C3
40236B EBX PUSH 53
40236C 4 [EBP] EBX MOV 8B5D04
40236F 8 # EBP ADD 83C508
402372 EDX JMP FFE2 ok

And here is the other version:

: memcopy ( src dest count -- )
begin dup while
rover c@ rover c!
rot 1+ rot 1+ rot 1- repeat
3drop ; ok
see memcopy
480B8F EBX EBX OR 09DB
480B91 480BEC JZ 0F8455000000
480B97 4 # EBP SUB 83ED04
480B9A EBX 0 [EBP] MOV 895D00
480B9D 8 [EBP] EBX MOV 8B5D08
480BA0 EAX EAX XOR 31C0
480BA2 0 [EBX] AL MOV 8A03
480BA4 EAX EBX MOV 8BD8
480BA6 4 # EBP SUB 83ED04
480BA9 EBX 0 [EBP] MOV 895D00
480BAC 8 [EBP] EBX MOV 8B5D08
480BAF 0 [EBP] EAX MOV 8B4500
480BB2 AL 0 [EBX] MOV 8803
480BB4 4 [EBP] EBX MOV 8B5D04
480BB7 8 # EBP ADD 83C508
480BBA EBX ECX MOV 8BCB
480BBC 4 [EBP] EBX MOV 8B5D04
480BBF 0 [EBP] EAX MOV 8B4500
480BC2 EAX 4 [EBP] MOV 894504
480BC5 ECX 0 [EBP] MOV 894D00
480BC8 EBX INC 43
480BC9 EBX ECX MOV 8BCB
480BCB 4 [EBP] EBX MOV 8B5D04
480BCE 0 [EBP] EAX MOV 8B4500
480BD1 EAX 4 [EBP] MOV 894504
480BD4 ECX 0 [EBP] MOV 894D00
480BD7 EBX INC 43
480BD8 EBX ECX MOV 8BCB
480BDA 4 [EBP] EBX MOV 8B5D04
480BDD 0 [EBP] EAX MOV 8B4500
480BE0 EAX 4 [EBP] MOV 894504
480BE3 ECX 0 [EBP] MOV 894D00
480BE6 EBX DEC 4B
480BE7 480B8F JMP E9A3FFFFFF
480BEC 8 [EBP] EBX MOV 8B5D08
480BEF C # EBP ADD 83C50C
480BF2 RET C3 ok

Rod Pemberton

unread,
May 18, 2012, 8:10:15 AM5/18/12
to
"Mark Wills" <markrob...@yahoo.co.uk> wrote in message
news:f0902853-ea0e-4891...@d17g2000vbv.googlegroups.com...
...

> Introduce the concept of registers into the Forth language.
>
> Seriously. Where stack juggling becomes an issue, registers are the
> antidote. It would often pay off to spend some time getting data from
> the stack into registers, performing the work with the registers, and
> populating the stack again. Problem solved.

How do you keep track of which register is in use? Is it entirely up to the
programmer to remember, just like with items on the data stack? Do you
require they be "empty" upon exiting a high-level word? C compilers use a
register allocator to keep track.

> However, this discussion raises an interesting point. Most Forth
> programmers would have the ability to drop into assembler and simply
> write something in machine code if they needed to - if they thought
> the stack was a bottleneck in a particular routine, for example. Most
> C programmers wouldn't know how to do that.

I'm not sure why you'd say that about C programmers. Even the oldest,
simplest C compilers have inline assembly.

> I make that statement, because I just asked an office of 9 software
> engineers (who code C (not C++) day in day out) if they could write
> memcpy in assembler for PC104 stacks that we use. They all said they
> wouldn't know how to do it, but then they all pointed out that they
> wouldn't have to - there are library calls in QNX to do it all for you!

From your description, I'd take it they were saying they didn't know enough
about "PC104" to implement stacks in assembly, not that they didn't know to
implement a stack in assembly.

> *THAT* is the difference between C and Forth. The difference is
> between the chair and the keyboard, in the caliber of the programmer.

They probably didn't understand why you'd want memcpy to be written in
assembler instead of C. First, C has a stack built in. Second, in general,
it's a few lines of C which map almost directly to assembly and which
generally optimize well.


Rod Pemberton



humptydumpty

unread,
May 18, 2012, 8:15:10 AM5/18/12
to
Hi!

Yet another version:
8<---
: c@!++ ( src dest -- src+1 dest+1 )
over c@ over c! 1+ swap 1+ swap ;

: memcopy ( src dest count -- )
BEGIN dup
WHILE -rot c@!++ rot 1-
REPEAT 2drop drop ;
--->8

Have a nice day,
humptydumpty

Albert van der Horst

unread,
May 18, 2012, 8:40:29 AM5/18/12
to
In article <jp410n$crl$1...@speranza.aioe.org>,
But also Knuth makes the point that a language that can't do that is not
to be taken seriously as a general purpose language.

<SNIP>

>
>HTH,
>
>
>Rod Pemberton

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Mark Wills

unread,
May 18, 2012, 8:57:14 AM5/18/12
to
On May 18, 1:10 pm, "Rod Pemberton" <do_not_h...@notemailntt.cmm>
wrote:

>
> How do you keep track of which register is in use?  Is it entirely up to the
> programmer to remember, just like with items on the data stack?  Do you
> require they be "empty" upon exiting a high-level word?  C compilers use a
> register allocator to keep track.
>


What difference does that make? "Keeping track" of a register is no
harder than "keeping track" of a local variable!

A PC104 is an embedded computer. The boards are stacked, one on top of
the other. I wasn't referring to Forth stacks in my earlier post!

https://en.wikipedia.org/wiki/PC/104

A quick coffee machine chat this AM reveals that in-line assembly (or,
in fact, any assembly) is not allowed. It contravenes the company
coding standards, written in conjunction with Lloyds. I wasn't aware
of that.

Anton Ertl

unread,
May 18, 2012, 8:58:40 AM5/18/12
to
steph...@mpeforth.com (Stephen Pelc) writes:
>What's really killing us here is the memory traffic. The memory
>traffic arrives because
>a) we generate a canonical stack at loop boundaries,
>b) Forth is bad at handling four items
>
>There are two solutions
>a) adjust the canonical stack model at inner block
>boundaries. This is doable at the expense of complexity
>and the x86 code generator is already 6000 lines of source.

Yes. Also note, that in applications (not micro-benchmarks), most
basic block boundaries are due to calls. You already do inlining
which should move that a bit towards loops and conditionals. But some
kind of interprocedural register allocation could be quite effective
(or not, depending on how aggressive the inliner is).

>b) Use register-based locals. I believe Marcel does this
>in some versions of iForth.

Yes.

>But thanks for retriggering the code generation competition.
>I now have work to do ...

Why does such a micro-benchmark trigger this for you? Granted, if you
work on application benchmarks like
<http://www.complang.tuwien.ac.at/forth/appbench.zip>, you will need
more effort to see the same speedups, but I think that these
improvements are more likely to also be profitable for other
applications than improvements for a micro-benchmark (even when you
consider improvement per effort as metric, as is sensible).

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2011: http://www.euroforth.org/ef11/

Stephen Pelc

unread,
May 18, 2012, 9:50:58 AM5/18/12
to
On Fri, 18 May 2012 04:55:35 -0500, Andrew Haley
<andr...@littlepinkcloud.invalid> wrote:

>LOL! I would have thought the more interesting question was whether
>to stick with the register-starved x86/32 model. 64-bit is where
>you'll get the big win with locals and/or stack in registers.

Sure.

>But really, why is all this micro-optimization such a huge deal
>anyway? I think it's rather silly. Are your customers clamouring for
>better code generation?

I didn't start this one!

No, our customers are not clamouring for better code generation.
For us, it's mostly good enough. However, performance is an
enabling technology to permit us to write portable libraries.
Especially in the embedded space, portable libraries for things
like FAT file systems, USB stacks and a TCP/IP stack are a
big win.

That having been said, I am personally always interested in seeing
what needs to be done to write better/faster code. The code generator
is one part of the chain.

Andrew Haley

unread,
May 18, 2012, 10:43:02 AM5/18/12
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Also note, that in applications (not micro-benchmarks), most
> basic block boundaries are due to calls.

In Conventional compiler terminology, a call does not terminate a
basic block.

>>But thanks for retriggering the code generation competition.
>>I now have work to do ...
>
> Why does such a micro-benchmark trigger this for you? Granted, if you
> work on application benchmarks like
> <http://www.complang.tuwien.ac.at/forth/appbench.zip>, you will need
> more effort to see the same speedups, but I think that these
> improvements are more likely to also be profitable for other
> applications than improvements for a micro-benchmark (even when you
> consider improvement per effort as metric, as is sensible).

There's a lot to be said for micro-benchmarks: you can see think about
a single thing, clearly. This one is just a simple combination of a
loop and stak ops, and improving it will benefit a lot of code.

Andrew.

Paul Rubin

unread,
May 18, 2012, 10:59:19 AM5/18/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>> This makes the, very common, assumption that a character is one
>> address unit wide.
> Yes. Elsewhere lies madness.

Other languages are now finding this untenable. One of the issues
making Python bite the bullet and do a bunch of incompatible changes
from Python 2 to Python 3, was the huge amount of bugs and conversion
hassles because Python 2 strings used byte-wide chars. So Python 3 uses
unicode by default. Haskell and Java have used unicode for quite a bit
longer. C libraries have things like wchar_t and so forth. 1-byte
chars may be ok as a sort of lowest common denominator but programs
dealing with non-Latin alphabets are hre to stay.

Andrew Haley

unread,
May 18, 2012, 11:22:54 AM5/18/12
to
Everybody noticed. It's the inner loop, which is what matters.

> %edi, %esi, and %ebx are not initialized. So, the routine posted is
> incomplete.

Well, yes.

> For reference, since I don't know version of GCC you used, GCC 3.4.1

3.4.1 ? Ya gotta be kidding! That was seven years ago.

> -O2
> produces for your C code above, without "procedure call noise", the
> following:
>
> jmp L7
> L9:
> movb (%ebx), %al
> incl %ebx
> movb %al, (%ecx)
> incl %ecx
> L7:
> decl %edx
> cmpl $-1, %edx
> jne L9

I get this with 4.6.3:

testl %ecx, %ecx
je .L1
xorl %eax, %eax
.L3:
movzbl (%ebx,%eax), %edx
movb %dl, (%esi,%eax)
addl $1, %eax
cmpl %ecx, %eax
jne .L3
.L1:

I ask you, how would you like it if someone used an ancient version of
your software that you'd done a lot of work on and complained about
its performance? :-)

Andrew.

Stephen Pelc

unread,
May 18, 2012, 11:25:29 AM5/18/12
to
On Fri, 18 May 2012 12:58:40 GMT, an...@mips.complang.tuwien.ac.at
(Anton Ertl) wrote:

>Yes. Also note, that in applications (not micro-benchmarks), most
>basic block boundaries are due to calls. You already do inlining
>which should move that a bit towards loops and conditionals. But some
>kind of interprocedural register allocation could be quite effective
>(or not, depending on how aggressive the inliner is).

Better intra-procedural register allocation would help loops
considerably, which is what Andy's example shows.

>>b) Use register-based locals. I believe Marcel does this
>>in some versions of iForth.
>
>Yes.

If we get better handling of the third and fourth items on
the Forth data stack (even if we have to invent some notation),
then the need for locals is reduced. Some systems already have
words such as THIRD and FOURTH, albeit as macros for x PICK.

>>But thanks for retriggering the code generation competition.
>>I now have work to do ...
>
>Why does such a micro-benchmark trigger this for you?

Sorry, I should have said *other* work.

Andrew Haley

unread,
May 18, 2012, 11:32:03 AM5/18/12
to
Paul Rubin <no.e...@nospam.invalid> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>> This makes the, very common, assumption that a character is one
>>> address unit wide.
>> Yes. Elsewhere lies madness.
>
> Other languages are now finding this untenable. One of the issues
> making Python bite the bullet and do a bunch of incompatible changes
> from Python 2 to Python 3, was the huge amount of bugs and conversion
> hassles because Python 2 strings used byte-wide chars.

Well, hold on. In ANS Forth, C@ and C! access a character, whatever
size that character happens to be. This isn't a wide character, and
is effectively a byte. The word CHARS has nothing to do with wide
characters, which are handled with the Xchar wordset.
http://www.forth200x.org/xchar.html talks about pchars, which are
effectively bytes, and xchars, which are wide characters built from
pchars.

Andrew.

John Passaniti

unread,
May 18, 2012, 1:01:06 PM5/18/12
to
On Friday, May 18, 2012 6:24:39 AM UTC-4, Mark Wills wrote:
> However, this discussion raises an interesting point.
> Most Forth programmers would have the ability to drop
> into assembler and simply write something in machine
> code if they needed to - if they thought the stack was
> a bottleneck in a particular routine, for example. Most
> C programmers wouldn't know how to do that.

Oh please. There are Forth programmers who don't know the underlying machine architecture (and who don't care) and there are C programmers who break into assembly language at the drop of a hat. Practically every C compiler I've ever used has had the ability to do inline assembly. Do you honestly believe this capability is unused?

> I make that statement, because I just asked an office
> of 9 software engineers (who code C (not C++) day in
> day out) if they could write memcpy in assembler for
> PC104 stacks that we use.

If you asked me, I would have said yes, I could certainly write such a routine. But I would ask you why you would make such an optimization? Did you perform some measurement and determine that a memcpy would offer a meaningful increase in speed? If speed is really important here, did you consider if the platform supported memory-to-memory DMA? Or if the platform doesn't support such DMA, did you determine if the memory you're copying actually needs to be copied-- is there some "zero-copy" version of the same algorithm that eliminates the need?

Or are you really asking because you started with the presumption that being able to code trivial routines in assembly somehow makes you a L33T programmer? Gosh, could it be that the reason they haven't acquired this skill is because they aren't worrying about the same microoptimizations that you are and are instead more on larger issues?

> They all said they wouldn't know how to do it,
> but then they all pointed out that they wouldn't
> have to - there are library calls in QNX to do
> it all for you!

Correct. If the infrastructure you are using already supports an efficient memcpy (and other routines) as part of the system libraries, then your ability to code or not code that routine in assembly is pointless. Why are you wasting time reinventing wheels? Is your wheel more round?

> *THAT* is the difference between C and Forth.
> The difference is between the chair and the
> keyboard, in the caliber of the programmer.

False. The difference is more in the type of work that they do. Programmers who write code for embedded systems or who do system-level programming tend to have a deeper understanding of the underlying architecture. That's independent of language, because in order to do that kind of work, you typically need that information.

It works the other way too. We have expert Forth programmers in this newsgroup who only work in embedded systems. Ask them to write code for a different problem domain, and they'll probably flop around with poor approaches. Take for example anytime the subject of web applications comes up and the peanut gallery here chimes in how they would do it using CGI. Hey, I liked 1994 too, but I moved on.

Elizabeth D. Rather

unread,
May 18, 2012, 2:02:59 PM5/18/12
to
On 5/18/12 2:15 AM, humptydumpty wrote:
> Hugh Aguilar wrote:
>
...
>> > Anyway, here it is in SwiftForth:

Please note that he has a very old version of SwiftForth.

Elizabeth D. Rather

unread,
May 18, 2012, 2:14:14 PM5/18/12
to
On 5/18/12 2:57 AM, Mark Wills wrote:
> On May 18, 1:10 pm, "Rod Pemberton"<do_not_h...@notemailntt.cmm>
> wrote:
>
>>
>> How do you keep track of which register is in use? Is it entirely up to the
>> programmer to remember, just like with items on the data stack? Do you
>> require they be "empty" upon exiting a high-level word? C compilers use a
>> register allocator to keep track.
>>
>
>
> What difference does that make? "Keeping track" of a register is no
> harder than "keeping track" of a local variable!

If you're talking about using real registers you have not only the
problem of machine dependence (which, of course, you do with assembler),
but also the fact that many if not most Forths use registers internally
in specific ways (e.g. as stack pointers) and have rules about stack
usage for user code.

If you're talking about locals pretending to be registers, just use locals.

Rod Pemberton

unread,
May 18, 2012, 10:09:11 PM5/18/12
to
"Andrew Haley" <andr...@littlepinkcloud.invalid> wrote in message
news:oLGdnbOmra7T9CvS...@supernews.com...
> Rod Pemberton <do_no...@notemailntt.cmm> wrote:
> > <van...@vsta.org> wrote in message
news:a1l87g...@mid.individual.net...
...

> > Let's repost your original C code:
> >
> >> void
> >> memcopy(char *src, char *dest, int count)
> >> {
> >> while (count--) {
> >> *dest++ = *src++;
> >> }
> >> }
> >
> > ...
> >
> >> Omitting the procedure call noise, at -O2 the code is:
> >>
> >> (count in EBX, src in EDI, dest in ESI)
> >>
> >> xorl %edx, %edx
> >> testl %ebx, %ebx
> >> je .L3
> >> .L6:
> >> movsbl (%edi,%edx),%ecx
> >> movb %cl, (%esi,%edx)
> >> addl $1, %edx
> >> addl %ecx, %eax
> >> cmpl %ebx, %edx
> >> jne .L6
> >> .L3:
> >>
> >
>
> 3.4.1 ? Ya gotta be kidding! That was seven years ago.

I use GCC via DJGPP. I haven't upgraded in a while. I also have 4.1.0.
Sometimes I have Linux around, sometimes I don't. Right now, I don't.
GCC is not known for efficient code. I doubt that has changed. E.g., why
the movzbl to %edx when only %dl is used? Why the 'addl' instead of
'incl' in 32-bit code? They need to study a compiler known for better code
generation, e.g., Watcom/OpenWatcom.


Rod Pemberton


Hugh Aguilar

unread,
May 19, 2012, 1:58:39 AM5/19/12
to
On May 15, 11:27 pm, quiet_lad <gavcom...@gmail.com> wrote:
> and java too
>
> stuff I see at work takes dozens fo gigs ram and still can only fo 18 responses a second, whiel backups take 5 hours

I "beleive" that a Forth program could supplant Gavino if "it wanted
to" (note that programs are non-sentient, so they can't actually "want
to" do anything, although Brodie did say about light-bulbs that
incandescents is their karma, so perhaps nonsense is a Forth program's
karma).

Let this be our new programming challenge --- write a program that
generates weird Gavino-like questions, complete with the bizarre
grammar and misspellings.

The test of success is if the questions can get posted on
comp.lang.forth and garner 60+ responses.

Andrew Haley

unread,
May 19, 2012, 5:20:37 AM5/19/12
to
Known by whom? People who use seven-year-old compilers?

> I doubt that has changed. E.g., why the movzbl to %edx when only
> %dl is used? Why the 'addl' instead of 'incl' in 32-bit code?

Instruction choice depends on the processor in use. If you compile
this for a 486 you get

je .L1
xorl %eax, %eax
.L3:
movb (%ebx,%eax), %dl
movb %dl, (%esi,%eax)
incl %eax
cmpl %ecx, %eax
jne .L3
.L1:

It's not just a matter of instruction length: some instructions pair
in the pipelines better than others. GCC has a model of the processor
that is used to drive the choice of instructions.

> They need to study a compiler known for better code generation,
> e.g., Watcom/OpenWatcom.

I note that you evaded my question. How would you like it? ("They"
includes me, BTW.) Of course, GCC isn't perfect, and work goes on
improving performance. There are examples of suboptimal code, but
this is not one of them.

And finally, if you really want good performance for his loop, you
unroll it. GCC will of course do that, but it's too long to include
here.

Andrew.

Anton Ertl

unread,
May 19, 2012, 6:54:19 AM5/19/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>> Also note, that in applications (not micro-benchmarks), most
>> basic block boundaries are due to calls.
>
>In Conventional compiler terminology, a call does not terminate a
>basic block.

There is no such convention. In some contexts, they do, and in some
contexts, they don't. In the VFX register allocation context, AFAIK
they do (they certainly do in RAFTS and in Gforth).

>> Why does such a micro-benchmark trigger this for you? Granted, if you
>> work on application benchmarks like
>> <http://www.complang.tuwien.ac.at/forth/appbench.zip>, you will need
>> more effort to see the same speedups, but I think that these
>> improvements are more likely to also be profitable for other
>> applications than improvements for a micro-benchmark (even when you
>> consider improvement per effort as metric, as is sensible).
>
>There's a lot to be said for micro-benchmarks: you can see think about
>a single thing, clearly.

Yes, but it does not tell you if that matters for a
lot of code.

>This one is just a simple combination of a
>loop and stak ops, and improving it will benefit a lot of code.

How do you know that it will benefit a lot of code? In my work, I see
very short basic blocks in Forth applications, and the most frequent
reason for basic block boundaries is calls.

In particular, see Figures 8-10 in
<http://www.complang.tuwien.ac.at/papers/ertl&pirker96.ps.gz>, Figure
9 in
<http://www.complang.tuwien.ac.at/papers/ertl%26gregg04ivme.ps.gz>,
and compare the dynamic counts of ;S (aka EXIT), COL: (aka ENTER),
?BRANCH, (LOOP) and (+LOOP) in
<http://www.complang.tuwien.ac.at/forth/peep/sorted>.

Inlining in VFX may lead to longer blocks so one would have to make
such evaluations especially for VFX, but as long as we don't have such
an evaluation, we are completely in the dark whether working on loop
optimizations benefits a lot of code, or just a few small benchmarks.

The code by Wil Baden in the MPE benchmark certainly does not look
like idiomatic Forth to me.

Anton Ertl

unread,
May 19, 2012, 7:31:23 AM5/19/12
to
steph...@mpeforth.com (Stephen Pelc) writes:
>Better intra-procedural register allocation would help loops
>considerably, which is what Andy's example shows.

The question is: Would it help Forth applications considerably?
Without your inliner, no. With your inliner, maybe. You have to
measure.

>If we get better handling of the third and fourth items on
>the Forth data stack (even if we have to invent some notation),
>then the need for locals is reduced. Some systems already have
>words such as THIRD and FOURTH, albeit as macros for x PICK.

Sure, as far as the compiler is concerned.

But for programmers, if they have so much data flying around and don't
find a way to factor it for fewer stack items, having THIRD and FOURTH
is probably worse than locals, and it's certainly less popular. So if
you want to have good register allocation for such things, it might be
more beneficial to let the register allocator cover locals.

Or maybe these things are not so frequent and other improvements would
have more effect on application performance.

Albert van der Horst

unread,
May 19, 2012, 9:19:10 AM5/19/12
to
In article <MYGdnZT7e6l4-CrS...@supernews.com>,
And of course it is open source. You don't like it, you improve it.
Just propose a patch!

>
>And finally, if you really want good performance for his loop, you
>unroll it. GCC will of course do that, but it's too long to include
>here.
>
>Andrew.

Andrew Haley

unread,
May 19, 2012, 12:43:05 PM5/19/12
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>>> Also note, that in applications (not micro-benchmarks), most
>>> basic block boundaries are due to calls.
>>
>>In Conventional compiler terminology, a call does not terminate a
>>basic block.
>
> There is no such convention.

IME there is, but there's no point arguing about the meanings of
words.

>>There's a lot to be said for micro-benchmarks: you can see think about
>>a single thing, clearly.
>
> Yes, but it does not tell you if that matters for a lot of code.

No, you have to use other knowledge, such as:

>>This one is just a simple combination of a loop and stack ops, and
>>improving it will benefit a lot of code.

> How do you know that it will benefit a lot of code?

Of course, there are ways of generating efficient code for this
pattern that will not benefit a lot of code. For example, one could
just recognize the pattern and treat it as a special case. However, I
suspect, based on my knowledge and experience, that a more general
solution which does an efficient register allocation would benefit
other code. I can't prove it without doing it.

> In my work, I see very short basic blocks in Forth applications,

I'm not surprised by that, if you terminate a basic block at a call.
This is Forth, after all.

Andrew.

Paul Rubin

unread,
May 19, 2012, 2:28:36 PM5/19/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
> FYI, I think a C library call version might look like
>
> {
> sigjmp_buf retry;
> sigsetjmp (&retry);
>
> TxStart (self, retry, false);
> TxStore (self, &(node->next), TxLoad (self, &head));
> TxStore (self, &head, node);
> TxCommit (self);
> }

Yeah, that's kind of ugly but lots of interpreters are written that way.
Maybe it could be a bit nicer with C++ operator overloading.

Also might be possible to use a wrapper function to remove some
boilerplate. With GCC nested functions:

{
void action (self) {
TxStore (self, &(node->next), TxLoad (self, &head));
TxStore (self, &head, node);
}
atomically (action);
}

where atomically is a library function that sets up the transaction and
retry and so forth. This is sort of what Haskell does, though syntax
sugar in the language papers over the nested functions.

Paul Rubin

unread,
May 20, 2012, 3:58:49 AM5/20/12
to
steph...@mpeforth.com (Stephen Pelc) writes:
> Remember that the design decisions and financing of gcc and VFX are
> very different. gcc is supported by major corporations. VFX is
> designed to be a fast one-pass compiler for Forth. ... VFX compiles 1M
> lines of Forth source code in about 40 seconds on an i7. How long does
> gcc take at -O2 ?

According to http://tinycc.org GCC compiles around 100 KLOC/sec (after
cpp expansion) on a 2.4 GHz Pentium 4, and TinyCC is about 9x faster,
about 859K LOC/sec. OTOH, the header expansion bloats that test code by
about 25x, so in another sense you're looking at around 30 sec for a
million lines, same ballpark as VFX. As TinyCC and GCC are batch
compilers you can presumably say "make -j8" on a quad-core i7 (8
threads) and get maybe 5x speedup. I'd guess you have a way to do
something comparable with VFX. TinyCC generates code that runs maybe 2x
slower than GCC optimized code: VFX might do a bit better than that, but
perhaps TinyCC is more comparable to VFX than GCC is.

TinyCC has around 80 KLOC of source code (in C) though that includes an
assembler, linker, cpp, etc. I think you mentioned someplace that VFX
was around 6 KLOC, which is impressive. I'm guessing VFX is written in
horizontal style, so each line has as much content as several typical C
lines, but still, that's pretty small for a serious compiler.

I thought

http://www.complang.tuwien.ac.at/anton/euroforth/ef00/pelc00a.pdf

was pretty interesting, though for reasons understood, it's not very
detailed. I wonder if you've got any reading suggestions for general
info (not Forth-specific) about how to write this class of code
generator (i.e. something fast and simple, that still makes some
reasonable global optimization efforts). I read the Dragon book long
ago, but it's pretty old by now.

Jan Coombs

unread,
May 20, 2012, 8:14:30 AM5/20/12
to
On 17/05/12 18:59, BruceMcF wrote:
> On May 17, 4:08 am, "Rod Pemberton"<do_not_h...@notemailntt.cmm>
> wrote:
>> IMO, without change of some sort, Forth isn't going to become "more
>> successful."
>
> The most likely change, though, would be to find some niche with
> substantial future growth prospects for which Forth's advantages are
> strong and where there it can either render some established source
> code base more usable, or move into a niche for which there is not yet
> an established course code base.
>
> What that niche would be? No idea. Its not a job that I'd suggest
> taking on based on hope for revenue or profit shares.

The Actel/Microsemi Igloo dev kit has FPGA with 8 RAM blocks of
256x18, so this is a tight niche. Lattice/SiliconBlue have similar
very low power parts.

If a stack engine memory requirements are shoe-horned into a 256x16
RAM then an array of 8 processors could fit on a small chip.

Jan Coombs
--
Simulate j1/b16 stack processor, export code to FPGA tools, email
for details:
jan4myhdlatmurrayhyphenmicroftdotcodotuk
http://excamera.com/sphinx/fpga-j1.html
http://bernd-paysan.de/b16.html
myhdl.org

Stephen Pelc

unread,
May 20, 2012, 11:09:18 AM5/20/12
to
On Sun, 20 May 2012 00:58:49 -0700, Paul Rubin
<no.e...@nospam.invalid> wrote:

Given that Forth has no preprocessor, the only sensible comparisons
will be very approximate and probably consist of real-world
applications.

>TinyCC has around 80 KLOC of source code (in C) though that includes an
>assembler, linker, cpp, etc. I think you mentioned someplace that VFX
>was around 6 KLOC, which is impressive.

To that you have to add the assembler, which is about 4k lines. The
disassembler is not part of the code generation, but you could not
develop a code generator without a disassembler, so add another 3k
lines.

>I'm guessing VFX is written in
>horizontal style, so each line has as much content as several typical C
>lines, but still, that's pretty small for a serious compiler.

Not really, but a lot of defining words.

>I thought
>
> http://www.complang.tuwien.ac.at/anton/euroforth/ef00/pelc00a.pdf
>
>was pretty interesting, though for reasons understood, it's not very
>detailed. I wonder if you've got any reading suggestions for general
>info (not Forth-specific) about how to write this class of code
>generator (i.e. something fast and simple, that still makes some
>reasonable global optimization efforts). I read the Dragon book long
>ago, but it's pretty old by now.

The project was started about 15 years ago. We read all the compiler
books of the time, plus the published Forth papers and code. These
days, there's nothing about compiling for Forth that cannot be found
in the compiler literature.

Bernd Paysan

unread,
May 20, 2012, 11:24:54 AM5/20/12
to
Andrew Haley wrote:
> Well, hold on. In ANS Forth, C@ and C! access a character, whatever
> size that character happens to be. This isn't a wide character, and
> is effectively a byte. The word CHARS has nothing to do with wide
> characters, which are handled with the Xchar wordset.
> http://www.forth200x.org/xchar.html talks about pchars, which are
> effectively bytes, and xchars, which are wide characters built from
> pchars.

It should also be noted that in many cases, C! and C@ in Forth code
really mean bytes (i.e. any data that fits into 0..255), not characters.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/

Bernd Paysan

unread,
May 20, 2012, 11:41:41 AM5/20/12
to
Stephen Pelc wrote:
> If we get better handling of the third and fourth items on
> the Forth data stack (even if we have to invent some notation),
> then the need for locals is reduced. Some systems already have
> words such as THIRD and FOURTH, albeit as macros for x PICK.

But they are used rarely (and should so).

Locals are used for words where you can't figure out how to reduce the
stack pressure so that it can be written nicely. Locals in a word are a
warning label, and my dominant usage of locals is when calling C
functions. The warning label means "bad factoring, cluttered stack",
and well, when calling C, I know that it is badly factored and the stack
is cluttered (C's stacks are allocated in megabytes, Forth stacks
usually do with kilobytes, if at all).

Andrew Haley

unread,
May 20, 2012, 1:49:00 PM5/20/12
to
Bernd Paysan <bernd....@gmx.de> wrote:
> Stephen Pelc wrote:
>> If we get better handling of the third and fourth items on
>> the Forth data stack (even if we have to invent some notation),
>> then the need for locals is reduced. Some systems already have
>> words such as THIRD and FOURTH, albeit as macros for x PICK.
>
> But they are used rarely (and should so).
>
> Locals are used for words where you can't figure out how to reduce the
> stack pressure so that it can be written nicely. Locals in a word are a
> warning label, and my dominant usage of locals is when calling C
> functions. The warning label means "bad factoring, cluttered stack",

Well, not necessarily. If locals are a super-efficient way of using
registers in colon definitions, then they're an easy way to write
fiddly low-level words that use multiple operands, maybe as good as
dropping into asm. That's a nice thing, isn't it?

Andrew.

Paul Rubin

unread,
May 20, 2012, 2:43:15 PM5/20/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
> Well, not necessarily. If locals are a super-efficient way of using
> registers in colon definitions, then they're an easy way to write
> fiddly low-level words that use multiple operands, maybe as good as
> dropping into asm. That's a nice thing, isn't it?

With extensive use of locals, Forth becomes just yet another computer
language. Having to organize one's algorithms to get the stack effects
to match up (avoiding a lot of juggling, locals, and PICK) to me seems
sort of like having to write computer documentation as poems that rhyme
and scan, instead of as ordinary English text. That seems to be part of
the Zen that makes Forth interesting, even if it slows coding down.
I've also seen a Forth style that simply uses globals (re-entrancy? Who
needs it) instead of locals, but I don't know how the cogniscenti react
to it.

[Bernd:]
> and well, when calling C, I know that it is badly factored
> and the stack is cluttered (C's stacks are allocated in megabytes,
> Forth stacks usually do with kilobytes, if at all).

One thing happening is C programs putting large structures or arrays on
the stack where Forthers would use ALLOT/FORGET or the like. The memory
usage from that is the same either way, but in Forth you have to
manually restore the old HERE, you can't allocate new permanent stuff
while the temp thing is there, etc. So I'm not persuaded the C approach
is worse. Stack-allocating large objects is perfectly natural
sometimes.

The other thing is Forth's convention of using a separate return stack,
and having called words consume their args from the data stack, while C
traditionally uses one stack, and has the caller clean up the args after
the called function returns. That means in Forth, if the called word
then calls other words, it's probably already consumed some args, and
this keeps going so that when you get further down the call chain, there
is quite a bit less stuff on the data stack. Maybe C compilers could
also generate code like that, saving some memory. Of course they
already pass a few args in registers on some architectures.

Paul Rubin

unread,
May 20, 2012, 6:43:46 PM5/20/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>>> This makes the, very common, assumption that a character is one
>>>> address unit wide.
>>> Yes. Elsewhere lies madness. ...
> Well, hold on. In ANS Forth, C@ and C! access a character, whatever
> size that character happens to be.

Do those contradict each other? The first quote says that a char is one
address unit (i.e. 1 byte). The second says it's whatever width. I'm
saying that the current trend is for "character" to mean unicode,
i.e. multiple bytes.

BruceMcF

unread,
May 20, 2012, 7:03:38 PM5/20/12
to
On May 20, 6:43 pm, Paul Rubin <no.em...@nospam.invalid> wrote:
> Do those contradict each other?  The first quote says that a char is
> one address unit (i.e. 1 byte).  The second says it's whatever width.
> I'm saying that the current trend is for "character" to mean unicode,
> i.e. multiple bytes.

But in that context, the C "char" would be a byte, not a unicode
character, so if [1chars=1] {NB} is true, then the sequence seems
valid.

{NB.
1 CHARS 1 = CONSTANT [1chars=1] IMMEDIATE
}



...

Paul Rubin

unread,
May 20, 2012, 7:34:35 PM5/20/12
to
BruceMcF <agi...@netscape.net> writes:
>> I'm saying that the current trend is for "character" to mean unicode,
> But in that context, the C "char" would be a byte, not a unicode
> character,

Yes, C has used char=byte since the 1970's and as such, it is far behind
the current trend.

Bernd Paysan

unread,
May 20, 2012, 7:35:37 PM5/20/12
to
Andrew Haley wrote:
> Well, not necessarily. If locals are a super-efficient way of using
> registers in colon definitions, then they're an easy way to write
> fiddly low-level words that use multiple operands, maybe as good as
> dropping into asm. That's a nice thing, isn't it?

How many of those fiddly low-level words do you write? I've just
finished writing the code for our (Forth Gesellschaft) LinuxTag eye-
catcher (a new version of our Triceps robot), and for reliability
reasons, it will run on the b16 FPGA board. So no locals, no assembler
to drop down to, just 16 stack elements deep, and as usual, the program
size should not exceed 2k by much. The new triceps has much more
demanding trigonometry than the old one.

I actually profit from placing intermediate results into global
variables, because they are easy to inspect by the debugger (b16 is a
Forth processor, but its Forth is just an assembler, i.e. edit-upload-
run style programming. Uploading is quick, so no real problem).

Elizabeth D. Rather

unread,
May 20, 2012, 8:01:52 PM5/20/12
to
On 5/20/12 8:43 AM, Paul Rubin wrote:
> Andrew Haley<andr...@littlepinkcloud.invalid> writes:
>> Well, not necessarily. If locals are a super-efficient way of using
>> registers in colon definitions, then they're an easy way to write
>> fiddly low-level words that use multiple operands, maybe as good as
>> dropping into asm. That's a nice thing, isn't it?
>
> With extensive use of locals, Forth becomes just yet another computer
> language. Having to organize one's algorithms to get the stack effects
> to match up (avoiding a lot of juggling, locals, and PICK) to me seems
> sort of like having to write computer documentation as poems that rhyme
> and scan, instead of as ordinary English text. That seems to be part of
> the Zen that makes Forth interesting, even if it slows coding down.

Except that, in virtually every comparison I've seen (both in the
context of professional programming projects and competitions held in
the past) projects are complete in Forth much faster than in C. For over
30 years FORTH, Inc. has been bidding on projects against teams using C.
Our bids usually come in 1/4 to 1/6 that of the C team bids. And we
usually deliver on time.

> I've also seen a Forth style that simply uses globals (re-entrancy? Who
> needs it) instead of locals, but I don't know how the cogniscenti react
> to it.

In the first place, "re-entrancy" is only an issue in the presence of
multiple tasks. For people using single-threaded Forths, it isn't an
issue at all.

For most of my career, though, I've used multi-tasked Forths (everything
produced by FORTH, Inc. since 1973). Our style is to use variables for
values that need to have a "lifetime" beyond a single definition or be
shared by multiple tasks as a component of the overall application
design. Variables that might have re-entrancy issues or which tasks need
private copies are defined as "user variables" (every task has a private
copy).

> [Bernd:]
>> and well, when calling C, I know that it is badly factored
>> and the stack is cluttered (C's stacks are allocated in megabytes,
>> Forth stacks usually do with kilobytes, if at all).
>
> One thing happening is C programs putting large structures or arrays on
> the stack where Forthers would use ALLOT/FORGET or the like. The memory
> usage from that is the same either way, but in Forth you have to
> manually restore the old HERE, you can't allocate new permanent stuff
> while the temp thing is there, etc. So I'm not persuaded the C approach
> is worse. Stack-allocating large objects is perfectly natural
> sometimes.

ALLOT yes, FORGET almost never. Given that Forth is extremely
parsimonious with memory, it's rarely necessary to worry about
temporarily allocating space. Temporary arrays can go in the unallocated
space at PAD, and ALLOCATE/FREE is useful sometimes. Programmers coming
from other languages tend to worry a lot more about releasing space than
Forth programmers.

> The other thing is Forth's convention of using a separate return stack,
> and having called words consume their args from the data stack, while C
> traditionally uses one stack, and has the caller clean up the args after
> the called function returns. That means in Forth, if the called word
> then calls other words, it's probably already consumed some args, and
> this keeps going so that when you get further down the call chain, there
> is quite a bit less stuff on the data stack. Maybe C compilers could
> also generate code like that, saving some memory. Of course they
> already pass a few args in registers on some architectures.

Except when we're having to call C (or other language) routines, Forth
programs don't use very much stack space. We have done studies on a few
large applications and found that they rarely get more than 8-10
elements deep.

BruceMcF

unread,
May 20, 2012, 8:02:50 PM5/20/12
to
On May 20, 7:34 pm, Paul Rubin <no.em...@nospam.invalid> wrote:
That is quibbling over labels. Calling a byte "char" doesn't mean that
you store your character code points as bytes, it means that when the
low level support for UTF8 uses the four letter sequence "char" to
label the bytes in the format.

Paul Rubin

unread,
May 20, 2012, 10:10:28 PM5/20/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
> In the first place, "re-entrancy" is only an issue in the presence of
> multiple tasks. For people using single-threaded Forths, it isn't an
> issue at all.

If you're doing anything at interrupt level, that counts as
multitasking, and re-entrancy matters. And these days, it seems like
almost every program I deal with is multi-threaded (maybe that's just
me). Single-threading seems like a 20th-century thing.

> Variables that might have re-entrancy issues or which tasks need
> private copies are defined as "user variables" (every task has a
> private copy).

In this case you're burning memory unnecessarily, if you're using a
variable for some temporary result, and you have a copy in every task
when it's if variable will be never active in more than one or two tasks
simultaneously. The usual approach is to put the variable on the stack.

> ALLOT yes, FORGET almost never. Given that Forth is extremely
> parsimonious with memory, it's rarely necessary to worry about
> temporarily allocating space. Temporary arrays can go in the
> unallocated space at PAD, and ALLOCATE/FREE is useful
> sometimes. Programmers coming from other languages tend to worry a lot
> more about releasing space than Forth programmers.

I hope that doesn't mean you're programming in a way that simply leaks
space. Also, ALLOCATE is even clumsier than ALLOT compared to
straightforward stack allocation.

>> this keeps going so that when you get further down the call chain, there
>> is quite a bit less stuff on the data stack.

> Except when we're having to call C (or other language) routines, Forth
> programs don't use very much stack space. We have done studies on a
> few large applications and found that they rarely get more than 8-10
> elements deep.

Yes, partly a matter of calling conventions, partly a matter of coding
style, and probably partly a matter of what the applications do (Forth
applications are simply less likely to be the kinds of applications that
munch on large volumes of data). One reason C code is more likely to
keep stuff on the stack is that it considers the stack to be randomly
addressible, while Forth traditionally avoids PICK.

Right now I'm messing with some C++ code that crunches XML documents
that can be megabytes in size (they are usually smaller), extracting
different fields and computing stuff. So there have to be a few dozen
variables active (across multiple call frames), keeping track of what's
in the different input buffers, copying stuff out of fields for
processing, and so on. A Forth program would probably use globals for
that stuff. The C++ code puts it on the stack since it considers the
stack to be randomly addressible.

Elizabeth D. Rather

unread,
May 20, 2012, 11:05:49 PM5/20/12
to
On 5/20/12 4:10 PM, Paul Rubin wrote:
> "Elizabeth D. Rather"<era...@forth.com> writes:
>> In the first place, "re-entrancy" is only an issue in the presence of
>> multiple tasks. For people using single-threaded Forths, it isn't an
>> issue at all.
>
> If you're doing anything at interrupt level, that counts as
> multitasking, and re-entrancy matters. And these days, it seems like
> almost every program I deal with is multi-threaded (maybe that's just
> me). Single-threading seems like a 20th-century thing.

Well, as I said, I've always worked on multitasked Forths. But we do not
handle interrupts in task code. It's a little hard to explain here, but
there's a whole consistent design concept involving the relationship
between interrupts and task-level code.

>> Variables that might have re-entrancy issues or which tasks need
>> private copies are defined as "user variables" (every task has a
>> private copy).
>
> In this case you're burning memory unnecessarily, if you're using a
> variable for some temporary result, and you have a copy in every task
> when it's if variable will be never active in more than one or two tasks
> simultaneously. The usual approach is to put the variable on the stack.

We rarely use variables for a truly "temporary" result, that's what the
data stack is for. User variables are allocated and managed conservatively.

>> ALLOT yes, FORGET almost never. Given that Forth is extremely
>> parsimonious with memory, it's rarely necessary to worry about
>> temporarily allocating space. Temporary arrays can go in the
>> unallocated space at PAD, and ALLOCATE/FREE is useful
>> sometimes. Programmers coming from other languages tend to worry a lot
>> more about releasing space than Forth programmers.
>
> I hope that doesn't mean you're programming in a way that simply leaks
> space. Also, ALLOCATE is even clumsier than ALLOT compared to
> straightforward stack allocation.

No, space is allotted according to the overall design of the
application, but the allocations are usually permanent. I'm not even
sure what a "leak" means in the Forth context.

>>> this keeps going so that when you get further down the call chain, there
>>> is quite a bit less stuff on the data stack.
>
>> Except when we're having to call C (or other language) routines, Forth
>> programs don't use very much stack space. We have done studies on a
>> few large applications and found that they rarely get more than 8-10
>> elements deep.
>
> Yes, partly a matter of calling conventions, partly a matter of coding
> style, and probably partly a matter of what the applications do (Forth
> applications are simply less likely to be the kinds of applications that
> munch on large volumes of data). One reason C code is more likely to
> keep stuff on the stack is that it considers the stack to be randomly
> addressible, while Forth traditionally avoids PICK.
>
> Right now I'm messing with some C++ code that crunches XML documents
> that can be megabytes in size (they are usually smaller), extracting
> different fields and computing stuff. So there have to be a few dozen
> variables active (across multiple call frames), keeping track of what's
> in the different input buffers, copying stuff out of fields for
> processing, and so on. A Forth program would probably use globals for
> that stuff. The C++ code puts it on the stack since it considers the
> stack to be randomly addressible.

Yes, it's a very different programming style.

BruceMcF

unread,
May 20, 2012, 11:22:37 PM5/20/12
to
On May 20, 10:10 pm, Paul Rubin <no.em...@nospam.invalid> wrote:
> One reason C code is more likely to
> keep stuff on the stack is that it considers the stack to be randomly
> addressible, while Forth traditionally avoids PICK.

Though if you want a randomly accessible stack, you can always build
one.

> A Forth program would probably use globals for
> that stuff.  The C++ code puts it on the stack since it considers the
> stack to be randomly addressible.

Or globals or dedicated stack pads holding the addresses of
structures. If those are created and consumed on the fly, they'd often
be allocated and returned to the heap, either individually or in a
structure pool.

Paul Rubin

unread,
May 20, 2012, 11:38:47 PM5/20/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
> We rarely use variables for a truly "temporary" result, that's what
> the data stack is for. User variables are allocated and managed
> conservatively.

Here's a simple arithmetic problem (multiplying complex numbers)
that I remember having trouble with:

: z* ( a b c d -- ac-bd bc+ad )
.... ;

I found it pretty complicated to do that without some form of temp
variables, even worse if all the data (args and return values) are
floating point numbers rather than ints. Any advice?

> I'm not even sure what a "leak" means in the Forth context.

It just means allocating storage for something repeatedly, without
bothering to free it, so the program's space usage keeps increasing. It
usually means the program has a bug, but it's tolerable in some
situations if the total amount of leakage is bounded to some acceptable
amount.

BruceMcF <agi...@netscape.net> writes:
> Though if you want a randomly accessible stack, you can always build
> one.

I thought the Forth machine model doesn't allow addressing the stack,
except with PICK, whose implementation is allowed to be horrendous.
Some Forth cpus (Chuck's) actually implement non-addressible stacks.
I'm not sure how to build an addressible stack even in a software Forth
that doesn't supply one, without hacking up the underlying interpreter.

Standard Forth has PICK but no obvious (maybe I'm missing something)
O(1) way to write to an arbitrary location in the stack.

Hugh Aguilar

unread,
May 21, 2012, 1:44:38 AM5/21/12
to
On May 20, 10:49 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:
Locals are only "a super-efficient way of using registers in colon
definitions" if those colon definitions are gigantic. In well-factored
Forth though, they tend to be quite small (3 to 4 lines typically, and
rarely more than 7 lines).

I've seen C programs in which the functions were gigantic --- you had
to scroll through them --- they were like mini-programs. In this case,
it makes sense to put the locals into registers because they are going
to stay there for a long time. In a short Forth colon word, it doesn't
necessarily make sense --- you have to save/restore all of those
registers with every function call and exit --- if you are only
accessing the local once or twice, it would be more efficient to just
use a local stack and dispense with all of that save/restore overhead.

Hugh Aguilar

unread,
May 21, 2012, 1:53:06 AM5/21/12
to
On May 20, 10:44 pm, Hugh Aguilar <hughaguila...@yahoo.com> wrote:
> it would be more efficient to just
> use a local stack and dispense with all of that save/restore overhead.

For example, the PIC24 accesses a register or a memory address in 1
clock cycle. Unless you are using the register as a pointer to
indirectly access memory (which you can't do with a memory variable),
then you might as well just access your data in memory.

Elizabeth D. Rather

unread,
May 21, 2012, 3:37:20 AM5/21/12
to
On 5/20/12 5:38 PM, Paul Rubin wrote:
> "Elizabeth D. Rather"<era...@forth.com> writes:
>> We rarely use variables for a truly "temporary" result, that's what
>> the data stack is for. User variables are allocated and managed
>> conservatively.
>
> Here's a simple arithmetic problem (multiplying complex numbers)
> that I remember having trouble with:
>
> : z* ( a b c d -- ac-bd bc+ad )
> .... ;

I don't understand your stack comment (I'm no mathematician) , but I
remember from years past working Chuck, who used complex numbers and
defining operators like C* C- and C*/ (multiply complex by a ratio) as
primitives. No temp variables; the primitives could use whatever
registers were available. Of course, this was in the days before
optimizing compilers, but it worked well.

> I found it pretty complicated to do that without some form of temp
> variables, even worse if all the data (args and return values) are
> floating point numbers rather than ints. Any advice?
>
>> I'm not even sure what a "leak" means in the Forth context.
>
> It just means allocating storage for something repeatedly, without
> bothering to free it, so the program's space usage keeps increasing. It
> usually means the program has a bug, but it's tolerable in some
> situations if the total amount of leakage is bounded to some acceptable
> amount.

Ok. My style is to allocate whatever storage you need for this program
at the outset and use it, not repeatedly allocate and release (which I
can certainly see could cause problems). Alternatively, use temporary
space at PAD (which doesn't require any allocation or releasing).

A. K.

unread,
May 21, 2012, 3:55:46 AM5/21/12
to
On 21.05.2012 05:38, Paul Rubin wrote:
> "Elizabeth D. Rather"<era...@forth.com> writes:
>> We rarely use variables for a truly "temporary" result, that's what
>> the data stack is for. User variables are allocated and managed
>> conservatively.
>
> Here's a simple arithmetic problem (multiplying complex numbers)
> that I remember having trouble with:
>
> : z* ( a b c d -- ac-bd bc+ad )
> .... ;
>
> I found it pretty complicated to do that without some form of temp
> variables, even worse if all the data (args and return values) are
> floating point numbers rather than ints. Any advice?

Sometimes I use "my poor man's locals" with three fast&simple but
non-standard words
RP@ and RP! (get/set rstack depth)
and RPICK (like PICK but from the rstack)

Then it's just:

: Z*
2>r 2>r 2>r 2>r rp@ >r \ note rstack elements
... \ do your arithmetics by rpicking
r@ rp! ;

Paul Rubin

unread,
May 21, 2012, 4:22:28 AM5/21/12
to
"A. K." <a...@nospam.org> writes:
> Sometimes I use "my poor man's locals" with three fast&simple but
> non-standard words
> RP@ and RP! (get/set rstack depth)
> and RPICK (like PICK but from the rstack)

I see, then the R stack is used as an array.

> Then it's just:
> : Z*
> 2>r 2>r 2>r 2>r rp@ >r \ note rstack elements
> ... \ do your arithmetics by rpicking
> r@ rp! ;

It looks neat, but what are you using rp@ and rp! for here?

Paul Rubin

unread,
May 21, 2012, 4:27:49 AM5/21/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>> : z* ( a b c d -- ac-bd bc+ad )
>> .... ;
>
> I don't understand your stack comment (I'm no mathematician)

ac-bd just means a*c minus b*d. So the word takes 4 parameters a,b,c,d
representing the two complex numbers a+bi and c+di. It multiplies them
leaving the single complex number (ac-bd) + i*(bc+ad), as two
coefficients on the stack. It's trivial with locals:

: z* { a b c d -- x y }
a c * b d * - b c * a d * + ;

doing it without locals seems quite inconvenient. I think Chuck might
have used globals.

m.a.m....@tue.nl

unread,
May 21, 2012, 4:52:00 AM5/21/12
to
On Monday, May 21, 2012 10:27:49 AM UTC+2, Paul Rubin wrote:
> ac-bd just means a*c minus b*d. So the word takes 4 parameters a,b,c,d
> representing the two complex numbers a+bi and c+di. It multiplies them
> leaving the single complex number (ac-bd) + i*(bc+ad), as two
> coefficients on the stack. It's trivial with locals:
>
> : z* { a b c d -- x y }
> a c * b d * - b c * a d * + ;
>
> doing it without locals seems quite inconvenient. I think Chuck might
> have used globals.

Does this qualify as using locals?

: z* ( a b c d -- ac-bd bc+ad )
params| a b c d | a c * b d * - b c * a d * + ;

' z* idis

$012478C0 : [trashed]
$012478CA pop rbx
$012478CB pop rdi
$012478CC pop rax
$012478CD pop rdx
$012478CE mov r9, rdx
$012478D1 imul r9, rdi
$012478D5 mov r10, rax
$012478D8 imul r10, rbx
$012478DC sub r9, r10
$012478DF mov r10, rax
$012478E2 imul r10, rdi
$012478E6 mov r11, rdx
$012478E9 imul r11, rbx
$012478ED push r9
$012478EF lea rbx, [r10 r11*1] qword
$012478F3 push rbx
$012478F4 ;

These are indeed locals, unless I'd use SSE2.

: z* ( f: a b c d -- ac-bd bc+ad )
flocals| a b c d | a c f* b d f* f- b c f* a d f* f+ ;
see z*
Flags: ANSI
$01247940 : z*
$0124794A fpop,
$01247954 sub rsi, #16 b#
$01247958 fstp [rsi] tbyte
$0124795A fpop,
$01247964 sub rsi, #16 b#
$01247968 fstp [rsi] tbyte
$0124796A fpop,
$01247974 sub rsi, #16 b#
$01247978 fstp [rsi] tbyte
$0124797A fpop,
$01247984 sub rsi, #16 b#
$01247988 fstp [rsi] tbyte
$0124798A fld [rsi #48 +] tbyte
$0124798D fld [rsi #16 +] tbyte
$01247990 fmulp ST(1), ST
$01247992 fld [rsi #32 +] tbyte
$01247995 fld [rsi] tbyte
$01247997 fmulp ST(1), ST
$01247999 fsubp ST(1), ST
$0124799B fld [rsi #32 +] tbyte
$0124799E fld [rsi #16 +] tbyte
$012479A1 fmulp ST(1), ST
$012479A3 fld [rsi #48 +] tbyte
$012479A6 fld [rsi] tbyte
$012479A8 fmulp ST(1), ST
$012479AA faddp ST(1), ST
$012479AC lea r13, [r13 #-32 +] qword
$012479B0 fxch ST(2)
$012479B2 fstp [r13 #16 +] tbyte
$012479B6 fstp [r13 0 +] tbyte
$012479BA add rsi, #64 b#
$012479BE ;

-marcel



Ecki

unread,
May 21, 2012, 5:06:18 AM5/21/12
to
Please correct me, but isn't the final + missed in the integer version:

> : z* ( a b c d -- ac-bd bc+ad )
> params| a b c d | a c * b d * - b c * a d * + ;
>
> ' z* idis
>
> $012478C0 : [trashed]
> $012478CA pop rbx
> $012478CB pop rdi
> $012478CC pop rax
> $012478CD pop rdx
> $012478CE mov r9, rdx
> $012478D1 imul r9, rdi
> $012478D5 mov r10, rax
> $012478D8 imul r10, rbx
> $012478DC sub r9, r10
> $012478DF mov r10, rax
> $012478E2 imul r10, rdi
> $012478E6 mov r11, rdx
> $012478E9 imul r11, rbx
> $012478ED push r9
> $012478EF lea rbx, [r10 r11*1] qword
> $012478F3 push rbx
> $012478F4 ;
>
> These are indeed locals, unless I'd use SSE2.

while existing in the floating point version:

Andrew Haley

unread,
May 21, 2012, 5:29:34 AM5/21/12
to
Paul Rubin <no.e...@nospam.invalid> wrote:
> It's trivial with locals:
>
> : z* { a b c d -- x y }
> a c * b d * - b c * a d * + ;
>
> doing it without locals seems quite inconvenient. I think Chuck might
> have used globals.

No. As Elizabeth said, Chuck defined a primitive that used whatever
registers were available. This has always been the Forth way to do
it.

Andrew.

Andrew Haley

unread,
May 21, 2012, 5:32:42 AM5/21/12
to
Hugh Aguilar <hughag...@yahoo.com> wrote:
> On May 20, 10:49?am, Andrew Haley <andre...@littlepinkcloud.invalid>
> wrote:
>>
>> If locals are a super-efficient way of using registers in colon
>> definitions, then they're an easy way to write fiddly low-level
>> words that use multiple operands, maybe as good as dropping into
>> asm. That's a nice thing, isn't it?
>
> Locals are only "a super-efficient way of using registers in colon
> definitions" if those colon definitions are gigantic.

Not at all. See the complex multiplication examople upthread.

Andrew.

Andrew Haley

unread,
May 21, 2012, 5:40:31 AM5/21/12
to
Paul Rubin <no.e...@nospam.invalid> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>>>>> This makes the, very common, assumption that a character is one
>>>>> address unit wide.
>>>> Yes. Elsewhere lies madness. ...
>> Well, hold on. In ANS Forth, C@ and C! access a character, whatever
>> size that character happens to be.
>
> Do those contradict each other? The first quote says that a char is one
> address unit (i.e. 1 byte).

A byte, not necessarily an address unit. C@ and C! address the
smallest accessible unit of storage, which must be large enough to
hold a (primitive) character. The smallest accessible unit of storage
is not necessarily one address unit: consider nybble-addressed
processors.

> The second says it's whatever width. I'm saying that the current
> trend is for "character" to mean unicode, i.e. multiple bytes.

Yes, and these are what Forth 200x calls xchars. xchars are built
from pchars. C@ and C! address pchars, i.e. bytes. C@ and C! do not
address multibyte characters.

Andrew.

Andrew Haley

unread,
May 21, 2012, 5:46:26 AM5/21/12
to
Java uses bytes (which are what Forth calls pchars) and chars (which
are what Forth calls xchars). It's no different; you're just arguing
about what things are called.

Andrew.

Albert van der Horst

unread,
May 21, 2012, 6:59:35 AM5/21/12
to
In article <7xfwauz...@ruckus.brouhaha.com>,
Not negating the need to have byte access in almost all lowlevel
code in micro controllers. Few people care to use something
different from C@ to access bytes.

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Albert van der Horst

unread,
May 21, 2012, 6:57:08 AM5/21/12
to
In article <7x8vgmf...@ruckus.brouhaha.com>,
Paul Rubin <no.e...@nospam.invalid> wrote:
>"Elizabeth D. Rather" <era...@forth.com> writes:
>> In the first place, "re-entrancy" is only an issue in the presence of
>> multiple tasks. For people using single-threaded Forths, it isn't an
>> issue at all.
>
>If you're doing anything at interrupt level, that counts as
>multitasking, and re-entrancy matters. And these days, it seems like
>almost every program I deal with is multi-threaded (maybe that's just
>me). Single-threading seems like a 20th-century thing.

Within a thread you're single threading. So you're wrong.
Re-entrancy matters for library functions. not for thread specific
functions. Normal library functions (D.R) CMOVE or TYPE can
be called from other Forth instances.

The bottom line is that we just keep track of what to share and
what not ourselves.

>
>> Variables that might have re-entrancy issues or which tasks need
>> private copies are defined as "user variables" (every task has a
>> private copy).
>
>In this case you're burning memory unnecessarily, if you're using a
>variable for some temporary result, and you have a copy in every task
>when it's if variable will be never active in more than one or two tasks
>simultaneously. The usual approach is to put the variable on the stack.

But we do that all the time! A variable not on the stack is rare.
That would be a good benchmark: to compare that written in Forth.

A. K.

unread,
May 21, 2012, 8:19:48 AM5/21/12
to
Sorry, I didn't have my coffee this morning... ;)
... and without thinking mixed 2 different implementations to nonsense.

It's rather

: Z*
2>r 2>r 2>r 2>r \ re-imag complex pairs
... \ do your arithmetics by rpicking
8 radjust ;

(radjust: cells rp@ + rp! --- depending on how rp@/rp! are implemented)

Anton Ertl

unread,
May 21, 2012, 10:22:26 AM5/21/12
to
Paul Rubin <no.e...@nospam.invalid> writes:
>I'm
>saying that the current trend is for "character" to mean unicode,
>i.e. multiple bytes.

There are different encodings for Unicode, but the trend is to use
UTF-8. Now UTF-8 is a variable-width encoding, with each Unicode
character taking 1-4 bytes.

How does that relate to Forth? On byte-addressed machines C@, C!,
CHAR+ etc. deal with bytes (i.e., chars are bytes), and we have extra
words (the xchar wordset) for dealing with characters that may take
more than one byte. However, most of the time one deals with strings,
where the difference does not matter. E.g., TYPE outputs an UTF-8
string just as easily as an ASCII string.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2011: http://www.euroforth.org/ef11/
It is loading more messages.
0 new messages