Q L H A C K E R ' S J O U R N A L =========================================== Supporting All QL Programmers =========================================== #24 May 1996 The QL Hacker's Journal (QHJ) is published by Tim Swenson as a service to the QL Community. The QHJ is freely distributable. Past issues are available on disk, via e-mail, or via the Anon-FTP server, garbo.uwasa.fi. The QHJ is always on the look out for article submissions. QL Hacker's Journal c/o Tim Swenson 5615 Botkins Rd Huber Heights, OH 45424 USA (513) 233-2178 swensotc@mail.serve.com http://www.serve.com/swensont/ EDITORS' FORUMN As time goes by I'm finding myself doing less and less programming. My recent foray into distributing QL and Z88 freeware has kept me busy collecting QL freeware. Now I will have the pleasure of trying some of this software out, which always takes some time. I'm still working on getting QFAX going (after having it for almost a year). For some reason QFAX did not talk well to my modem. I've been meaning to sit down and figure out the problem, but it has become one of those get-around-to-it's. The only programming I have been doing in some work in Perl. Perl is great for some Sys Admin work in Unix and I've written a few CGI-BIN scripts in Perl. I'm hoping to do Perl work full time. A port of Perl to the QL may happen and I hope it does. Perl is a great language for quick programs. It's got the speed of development of SuperBasic but with the power of C, awk, and SED. In my browsing of the Web I've run across a web site dedicated to programming. Besides carring information about a number of different languages, they also have a section on "classic" papers. I downloaded the following papers: - What is "Object-Oriented-Programming"? by Bjarne Stroustrup - Recommended C Style and Coding Standards - How to Steal Code or Inventing The Wheel Only Once by Henry Spencer The papers are stored in Adobe Acrobat (.pdf) format and need an Adobe viewer to view or print out. I started reading Bjarne's paper on OOP but have yet to sit down and go through it all. It dicusses OOP by starting with procedural programming, then dicusses data hiding, data abstractions, and them moves on to OOP. It looks like this may actually be the article I've been looking for, that really discusses OOP in relation to procedural programming. I've always found other OOP articles that start of discussing OOP by defining the OOP terms but not relating them back to procedural programming. I need to see OOP in relation to something that I already know. If you want to visit the site, it's at: http://www.strangecreations.com/strange/ Using an older form of browsing, I was looking through my local library and ran across a book by P. J. Plauger. Mr. Plauger used to own Whitesmiths, a C compiler vendor, and has contributed to "Computer Language" and "C Users Journal" magazines. The book is called "Progamming on Purpose III" and is a collection of "Programming on Purpose" columns he wrote for "Computer Language." The topics all deal with software technology, while the other two books deal with software design and software people. The articles have some good things to say. They cover a wide variety of topics and are good idea generators. Some of the better articles covered technical writing, maintaining code, text editors, and user interface issues. I'm hoping that the library has the other two books as I am sure that they are worth the read. I'd like to end with one final note; when I started the QHJ I had hoped that most of the articles would come from you, the readers, but I was not so lucky. As it is taking me longer and longer to produce each issue, I would like to make a request to some of you might take pity of me in my plight and pen a few words for this one-man zine. SOME NOTES ON ARCHIVE by Bill Cable [ This came to me as a letter and not an article - ED] I am heavy into really relational databases now. The place I work uses Oracle. They have tables in their database with 50 million records or rows are they like to call them. I finally get to compare ARCHIVE (a quasi relational database) with the real thing. One this that is striking is how the syntax of ARCHIVE like insert, select, order and so forth are actually the same terms used in SQL compliant relational databases. As far as I can tell anything you can do in a relational database you can also do in ARCHIVE. In a relational database it can often be done directly while in ARCHIVE you will have to write procedures to do it and often a simple SQL statement can require a lot of procedures to duplicate. Still, taking ARCHIVE and its language you can do about anything you want. It may take too long to be practical but you can still do it. [ SQL is only a language used to query a relational database. ARCHIVE is a relational database and most resembles dBase (II/III/IV). When doing queries, both ARCHIVE and dBase suffer when compared to SQL - ED] In your last QHJ you discuss ARCHIVE a little bit. It is a very nice language to use and it is very tight (not many bugs). As you mention the _prg files are text files but the indentations seen in the ARCHIVE editor are not there. There is an easy way to get such a listing. In ARCHIVE you can list a program using the LLIST command. It normally lists to the printer with the indentations shown. If you want to send the listing to a file use the SPOOLON command which will redirect LLIST, LPRINT, and such to a file or to the screen. That way you can use LPRINT and control output from LPRINT to screen, printer, or file. So if you have some procedures loaded in ARCHIVE: llist will send indented listing to the printer. spoolon "ram1_proc_txt" llist spooloff will send indented listing to ram1_proc_txt. Be sure to always turn spoolon off or the file is still open and you can't access it if you haven't quit ARCHIVE yet. Spooloff always sets output back to the printer. You can spooloff even if you haven't done spoolon without an error. A spoolon screen will send output to the screen instead. Unfortunately there is no way for ARCHIVE to ready text files as when you might want to parse text and turn it into a database. If can, of course, read text files in the standard export format. You are right in that ARCHIVE can load indented _prg files. One of the more powerful features of ARCHIVE is that you can have an ARCHIVE procedure write a procedure to disk and then merge it and use it. That is one way Ihave my ARCHIVE programs do things you can't simply precode. PASSING PARAMATERS When I was learning Pascal, one of the hurdles I had to get over was the concept of paramater passing. Paramaters are used when passing data to procedures and functions. Paramaters some in two type; "call by value" and "call by reference." When you pass operation to a procedure, you are "calling" that procedure. When using procedures and functions, you need to know of you are calling by reference or value. Each has different effects on your program and not knowing the effects can cause what is called "side effects." Call by Value - This means that the value of the paramater is passed to the procedure. The procedure only gets a copy of the data and what ever it does to the data, it does not affect the original variable. C defaults to call by value. SuperBasic defaults to call by value only when you use numbers. Call by Reference - This means that the variable itself (or a reference to it) is passed to the procedure. If the procdure changes the value of the variable, it is changed through out the whole program. C uses pointers to get procedures to do call by reference. Superbasic defaults to call by reference when using variables. When programing in C, you know when you are calling by value or reference. It is an important part of the langauge and taught early when learning C. In SuperBasic it is not very apparent and not really discussed. In fact, I've been programming in SuperBasic for over 10 years now and I did not know if it used call by reference or value. So I decided to play with SuperBasic, read the manual, and figure this out. Below is a simple procedure that takes a variable as a paramater and increases it by one. We'll call the procedure inc for increment. 10 DEFine PROCedure inc ( x ) 20 LET x = x + 1 30 PRINT x 40 END DEFine When you call the procedure with a literal: 100 inc 20 or 100 inc (20) SuperBasic can only use call by value, since there is no variable to use in a call by reference. When you call it with a variable: 100 inc var SuperBasic uses call by reference. This means that when you call the prodecure, the value of VAR will increase by 1. In a way this procedure is working like a function called like this: 100 var = inc (var) Of course, when you use a function you must use a RETURN statement. If you do not know that SuperBasic uses call by reference in this instance, then the value of VAR will increase when you do not want it to. This is often called a "side effect" of a procedure. If you want to call the procedure with a call by value, you must tell SuperBasic this. You can do this by putting parentheses around your variable, like this: 100 inc (var) Now the procedure inc will get its own copy of VAR to play with and the real variable VAR will not change. The same works with functions. Since functions need parentheses around variables used in a call, a single set of parentheses is used for a call by Reference and a double set of parentheses is used for a call by Value. RECENT FREEWARE - CLIPS CLIPS is an expert system developed by NASA in 1986. It has been ported to the QL by Emiliano Barbaini of Italy. CLIPS is an interpretive language like BASIC or Lisp. Like Lisp or Prolog, CLIPS is designed for use in artificial intelligence. CLIPS has three ways to represent knowledge: Rules, Generic Functions, and Object Oriented Programming (OOP). CLIPS supports the 5 features of OOP: classes, message handlers, abstraction, inheritance, and polymorphism. Or so the manual says. When I read through the first part of the manual, it introduced CLIPS by talking about facts and rules. Facts are just "words" you tell CLIPS and rules are actions it takes based on the facts. Facts are what ever you define them to be. Here some examples: (assert (bob)) (assert (animal-is duck)) (assert (animal-is bob)) Each fact is stored as a literal in CLIPS and no check in done on it. Rules are really IF..THEN statements. Rules say that if a given fact exists, then perform some function. Here is an example (defrule animal (animal-is duck) => (assert (sound-is quack))) If the fact (animal-is duck) exists (has been asserted) then the fact (sound-is quack) will be asserted. You can have multiple facts in a rule, the same as using AND in an IF statement, by listing the facts before the =>. The same goes for having mulitple actions in the rule, by listing them before ending the rule with a closing ). CLIPS terminology is a bit different and takes some getting used to. CLIPS uses the term field to define a single element in a fact. In (assert (bob)), bob is a field. In (assert (bob dave)), both bob and dave are fields. CLIPS supports the following types of fields: float, integer, symbol, string, external address, fact address, instance address, and instance name. The manual that comes with CLIPS is really a tutorial. The reference manual as not passed to me. As someone new to CLIPS it is probably better to have a tutorial instead of the reference manual, it's makes it easier to learn the language. I have not gone too far into the manual, nor do I know how far I will go. I don't see CLIPS used for much everyday computing on the QL, but it does have the potential for letting a QLer explore the non-everyday areas of computer science. To get an idea of what one can do with CLIPS, the Proceeding from the first three CLIPS Users Conference are included at the back of the manual. Some of the area covered are: "Three CLIPS-based Expert Systems for Solving Engineering Problems", "Using CLIPS in a Distributed System - the Network Control Center (NCC) Expert System", "Space Shuttle Systems Monitoring: Real-Time Telemetry Processing Using CLIPS", "A CLIPS Expert System for Maximizing Alfalfa", "MOM - A Meteorological Data Checking Expert System in CLIPS", and "Using a CLIPS Expert System to Automatically Manage TCP/IP Networks". It looks like CLIPS can be used for a variety of applications. CLIPS is a 500K executable and requires an expanded QL. I have a Gold Card on my QL and it works fine. I have not tested it on a 640K QL. CLIPS is available via QHJ Freeware (same address as the QHJ). Send a disk and return postage and it is yours. The FTP site maya.dei.unipd.it seems to be down, so Emiliano did not put it there. If a request is made, it can be put on ftp.nvg.unit.no in the QL subdirectory. HOUSE OF CODING STYLE I was recently doing some CGI-BIN programming in Perl. Since I was new to CGI-BIN programming, I did what every other programmer does when he is new to something, he borrows somebody elses code to see how it is done. I borrowed come Perl CGI-BIN code from our local CGI-BIN expert at work. When writing my code I tried to stay close to the style that he was writing in. I did notice that he has a style that is very different than mine. He likes to put any long sections of code in a subroutine. Where as I do not like to break up these sections in to subroutines. My code looks kind of like this: -------------- -------------- -------------- IF ....... THEN ..... ------------ ------------ ------------ ------------ IF ...... THEN ...... ----------- ----------- ----------- ----------- ELSE ------------ ------------ ------------ ------------ END IF ------------- ------------- Where as his code looks like this: -------------- -------------- -------------- IF ....... THEN ..... Call Subroutine1 ELSE Call Subroutine2 END IF ------------- ------------- where the code in the IF-THEN-ELSE constructs were moved to two subroutines. Now none of these subroutines were going to be called from more than one place in the code. I prefer to write subroutines only when they save writing the same code in different part of the program. To me subroutines are designed to save the amount of code you are writing. My friends idea of subroutines is to make the main part of your code shorter and easier to read. This is fine if the sections of code that you are going to move into a subroutine are fairly long. I prefer to not use a subroutine unless I need to write the same code many places. For me the subroutines break the flow of the structure of the program. I view it sort of like parsing a tree. Just as with a left- or right-handed rule, you keep moving down a tree until you come to a leaf node and then you back up and take the next branch, coding flows out like a tree structure going down all of the IF-THEN statements until an end is reached and then brought back up the tree with and END IF statement. One never parses a tree by individual levels of depth at a time. I wanted to bring this up because it shows two distinct coding styles and why they are done that way, and maybe it will get you thinking about your personal coding style and how you feel about it versus others. RECENT FREEWARE - REXX The REXX language was derived from a batch language on the IBM System/370 called EXEC 2. It has since become a standard language for OS/2 with implementations on other platforms, including the Amiga. A version of REXX has been ported to the QL. REXX is a procedural language like BASIC, C, Pascal, etc. and its code has the same look as these languages. REXX seems to have the same constructs for writing a program, such as conditional statements, looping statements, input, output, etc., as the above languages, it just does it a little differently. A beginning REXX program is like this: pull a b=a*a c=1/a d=3+a e=2**(a-1) say 'Results are:' a b c d e Pull is equivalent to INPUT and say is equivalent to PRINT. The assignment statements are the same format as BASIC. REXX supports untyped data in the same way that Perl does. A variable can hold either string or a number. The following program demonstrates how this can work: a = 'A String' b = '123' c = '456' d = a ":" (b||c)*3 say d The results will be: "A String: 370368". The function || concatenates the two strings, which is a number so it can be multiplied by three. This is then added with a variable holding a string and a string constant to get the final result. REXX has a variety of loops and conditional loops. Here are a few: do 10 (repeat 10 times) say "hello" end do c= 1 to 20 ( FOR C = 1 TO 20 ) say c end do until var = 10 ....... end do while error = 0 ....... end As you can see REXX is a fairly verbose language and is fairly easy to read (unlike the terseness of C or FORTH). Most of the example programs are things that can be done in other languages, it's just a matter of figuring out how to do them in REXX. The version of REXX for the QL is a 500K executable, so it will require an expanded machine. I don't know what the lower limits are to run REXX. I have tested it on a QL with a Gold Card and it runs just fine. REXX is an interpretive language, like BASIC, but this implementation is not an interactive interpreter. If you execute REXX with no arguements, it will essentually do nothing. To run a REXX program, you have to exec REXX with the arguement of the program you want to run. Of course, this means you need to have TKII. To exec REXX with the example animal_rexx program included, you would do this: exec rexx_exe;"animal_rexx" This will execute REXX and load in the REXX program animal_rexx. The QL version of REXX comes with a simple tutorial for beginners and a longer fuller document that does into greater detail about REXX. Since REXX is popular for OS/2 and Amiga, there are a number of sources on the Internet. There really is not much else to say about REXX. If you are looking for another language to play around with, here is a good one. If you are looking to learn REXX to use on other platforms, this version of REXX should do the job. At the very least it give the QL programmer one more option.