Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!rutgers!mailrus!uwmcsd1!ig!agate!ucbvax!dewey.soe.berkeley.edu!oster From: oster@dewey.soe.berkeley.edu (David Phillip Oster) Newsgroups: comp.lang.forth Subject: Re: Forth and Functional Languages Message-ID: <26098@ucbvax.BERKELEY.EDU> Date: 15 Sep 88 06:28:08 GMT References: <8809092121.AA09902@jade.berkeley.edu> <1625@crete.cs.glasgow.ac.uk> Sender: usenet@ucbvax.BERKELEY.EDU Reply-To: oster@dewey.soe.berkeley.edu.UUCP (David Phillip Oster) Organization: School of Education, UC-Berkeley Lines: 85 We've been talking about "very high level languages", and "functional programming languages" and "languages with linguistic support for modularity". I prefer to lump them all together as "languages inspiring superior programming." Many forth programmers have never seen a "language inspiring superior programming" better than Pascal, C, or Fortran. I'm going to be using the phrase "language inspiring superior programming" a lot in this article, so I'm just going to abbreviate it LISP from here on out. In LISP, every data object (the equivalent of a Forth address) is tagged with a type. Operations such as "+" check the tag type of their operands and do the appropriate thing without any human intervention. In Pascal, You get error messages if you apply an operator to inappropriate types. In Forth you just get garbage results. In LISP the language will do the operation if it can. If it can't you'll get an error. (An error is a special kind of object, with special flow control properties, similar to resetting the return stack, except in LISP you can specify that certain clean-up operations, such as closing open files, will happen automatically if anybody, even the operating system, generates an error during the program.) In LISP you can add new data types and have them automatically take advantage of all the existing capabilities. For example, suppose you define a new kind of number, say complex number, and you want to use the convenient notation of (a + b) * c where "a" might be a floating point number, "b" an integer, and "c" a complex. In Pascal you can't use "+" to add complex numbers. You can write your own function to add complex numbers, but you loose access to the outer interpreter of Pascal's knowledge that most human beings mean "a b + c *" when they write "(a + b) * c". In Forth, you can, but you have to use a special version of "+" that lives in a different vocabulary from the integer "+" and you must explictly tell Forth to switch vocabularies. Since forth does not automatically keep track of the types of operands and automatically insert type coercion operators, you'd have to write something like: A @ FLOATVOC B @ INT->FLOAT + FLOAT->COMPLEX COMPLEXVOC C @ * much more cumbersome and error prone. (Note that I have to explicitly switch vocabularies to get floating "@", and again to get complex "@". If you don't have special hardware to do the tag analysis, doing the tag will slow the system down. Therefore many very high level languages have a compiler (the equivalent of the Forth outer interpreter) that, tries to determine the types of the operand. If it can it produces threaded code that directly performs the reuired operation, so it does the tag analysis in zero time. For example, if you multiply "65536 * 65536 * 65536" you'll get the wrong answer in Forth or Pascal, because that expression requires a 48 bit integer, and neither language supports the automatic overflow of integer arithmetic into variable sized big numbers, each as big as it needs to be. Better LISP systems do this. On the otherhand, if you are using the "i" of a "FOR" loop, and you write "i * i", the compiler can deduce, based on the upper bound of the for loop, that that expression will never overflow a 16-bit integer, and generate simple, fast code to evaluate it. Pascal is type strict: the compiler must be able to tell, strictly from by your inclusion of extra type declarations, the type assignment of every object in every expression. You can't extend the domain of the built in operators like "+" to handle new types. LISP is type safe: if the compiler doesn't know the types, they'll have to be checked at run time. You can extend the domain of the built in operators like "+" to handle new types. You can set up the system to detect and do something reasonable on overflow. Often type checks can be made at compile time, so the run time cost is zero. Forh is chaotic: if the programmer accidently applies an operator to inappropriate arguments, he is screwed. He has to find it himself, the compiler and the run-time system aren't going to tell him. --- David Phillip Oster --When you asked me to live in sin with you Arpa: oster@dewey.soe.berkeley.edu --I didn't know you meant sloth. Uucp: {uwvax,decvax,ihnp4}!ucbvax!oster%dewey.soe.berkeley.edu