02 September 2017

Reflections on 8th - my road to having fun again

Coding along in 8th I am truly amazed by the epiphanies that came about:

  1. my mindset is shifting a lot - thinking "like a stack" *is* different
  2. what I used to value as one of the most miraculous Lisp features (macros) is available In 8th for free when using immediate words. That said, I need to put a lot of work in that area.
  3. when I started with 8th, there were no local variables yet and I thought: all globals!!! Yuck!     But when coding along I finally *get* it. One should aim to use NO VARIABLES AT ALL. Just use the stack. And now even the idea of using local variables seems a bit offending ;-) 
  4. in the past, I gave up 2 times on 8th, because I didn't get it. But now I have real fun coding 8th. Giving up on 8th is really not possible anymore! What earlier appeared to be easier to code in (like Python), now seems to be awkward and bloated.
  5. since I like stories about programming, I found several about Charles Moore. Maybe it is not possible for everyone to create there own Forth, but surely we should aim for compact, non-bloated code. Why buy VLSI software for $$$.$$$ if one can write it in 500 lines of Forth?  Of course there is a great difference between geniuses and mediocre developers, so, maybe that is the biggest secret behind Charles' success stories 
  6. I think I now also understand better why Ron - the creator of 8th - (who is proficient in other, more generally accepted languages) chose to use Forth as the base for 8th.

So, kudos to Ron and 8th (and the whole Forth community).

(Not) convinced?
Get the free version of 8th from 8th-dev.com and join the discussion in the forum 8th-dev.com/forum

Note: it is amazing tha Ron, the creator of 8th, is always around in the forum and that he answers all questions and fixes bugs most of the time within hours!

12 August 2017

Rosetta Code and 8th

Ignorance and shame ...

A few days ago I proposed (in the 8th forum) to start creating examples of solutions to Rosetta Code problems using 8th as the programming language.

My intention was (and still is) to support 8th and make it much more visible to programmers and thus help the development of 8th.

That said, I made the false assumption that there wouldn't be any 8th solutions out there :-(

So, totally ignorant, I created an unoptimized version for the 100 doors problem and published that in the 8th forum.

To my great embarrassment the creator of 8th, Ron, appeared to have created and published a very nice 8th solution for this problem already. Man, did I feel like an ass ... I really couldn't sleep the night after because being so ashamed :-(

After that I found out there are already a lot of 8th solutions out there.

Lessons learnt ...

Having learnt from my ignorance I now will be careful and pick Rosetta Code problems for which there isn't an 8th solution yet ;-)

That said, I learnt a second lesson: not only to use Google first, but also have a look at the samples provided with 8th. I really hadn't looked at them before.

Amongst them is the now (for me) famous 8th solution by Ron to the "100 doors" problem.

I have alreaddy skimmed the samples and saw how helpful these can be. I surely will make good use of the embedded knowledge in them in the future.

Would you like to help writing solutions?

I do not know if many people read this. But if you do and you happen to be a programmer, please consider solving one of the Rosetta Code problems using 8th and discuss it in the 8th forum in the "Sample Code" section!



09 August 2017

Comeback ... and a bit of history

I have studied and used quite a few programming languages in the past 38 years.

Yes, I am *that* old ;)

In fact, when I started, there were no PC's, tablets and smartphones and even no homecomputers like the BBC and the Commodore 64.

I started, working with a mainframe (to be precise a Siemens 4004 which was compatible with IBM S/360 mainframes).

During the time that I learned to program in Cobol, I did all sorts of work, like operating the mainframe, exchanging tapes and disks (yes, in those days one could exchange complete disk packs depending on which job had to be run).

We had card readers and punchers. Also card sorters, which was a heck of a lot of work to handle, because sometimes we had to sort a very big card deck on multiple positions. That could take hours. And if we by accident dropped a bunch of cards on the floor we had to start all over ...

We had also mark sensing devices. There were cards with no punched holes in it yet, but people could "mark" a specific area on the card using a pencil. The device then would interpret the marked parts and punched holes accordingly, such that the cards could be read by the computer later on.

The last device was one which printed characters on top of the card. For those devices you had to use patch panels with cables to determine which punch positions should be printed where. A bit similar to the old fashioned telecphone switch stations where a few ladies did the wire patching ;-)

There were a few "punch guru's" among us, who almost always could detect errors in a card deck used for program input, simply by looking straight through the whole deck. They new there should be holes through and through on known positions and thus could spot a lot of "bad cards".

When I started programming, we wrote a (Cobol) program literally on paper. The complete program (on paper) would then be punched into cards by special ladies, called data typists. When we received the card deck the fun began...

In order to compile a program you had to feed the card reader with:
1. a punched card deck of the compiler itself (* later on the compiler would already be on disk)
2. the card deck with the source code

The compiler would then:
1. print a listing with any errors
2. punch a card deck containing the object format (* later on it went straignt to disk)

Most of the time there were lots of errors. Maybe not real programming errors, but just typos of the punch ladies, for whom all the text was just gibberish ;-)

After repeating this proces and punching individual "patch" cards to update the source, one would obtain an object deck.

This had to be linked via the card reader:
1. feed card deck of the linker (* later on the linker resided on disk)
2. feed the object deck (from the compile step)

(* With later on I mean that this became available at a later stage)

As you can see a very cumbersome series of tasks.

One of the most problematic things was the small main memory of the mainframe. In fact, our mainframe had a core memory of 128KB (of which I have still preserved a physical piece somewhere). Core memory really was handwoven by women under a microscope, where they put 3 very thin copper threads through each small magnetic core, a real wonder of technique indeed!

In order to save memory during compilation and loading of a program we used the so called "label lists". In the current times we can use variable names of any length, because we have plenty of memory. Not so in the old days.

We had, on paper, a list of our (very short) variable names and next to them the corresponding description a.k.a. the would be variable name :-)

Debugging a program was really mind boggling. One had to use an up-to-date label list. But, hey, in those days there were also a lot of people that eschewed documentation. Hence we had a beautiful task of trying to grasp the meaning and structure of sometimes very big and complex programs, not being helped whatsoever with the variable names.

That said, in these days we also had "cowboy programmers" using "go to" all over the place. And even worse, in Cobol you could change the meaning of a "go to", so that you ended up in deep shit when debugging ...

Luckily enough I was teached structured programming and later one most of my collegues as well.

Another nice thing was that big programs did not fit in the 64KB user part of core memory (the rest was reserved for the OS). So we wrote our programs in overlays. That is:
1. write a base piece which always stays in memory during execution
2. the base piece loads an overlayed part when needed
So, in fact we used our own hand written swapping mechanism. Nice huh?

Also notice that there was no multi processing whatsoever. When a job ran, it used the whole user part of the memory all the time. One job at a time. Unthinkable these days, isn't it?

What has this all to do with 8th?


Well, one of the reasons to be fond of 8th is it's heritage - Forth.

When I was struggling with Cobol, a lot of scientists (many astronomers) were using Forth to control their million dollar equipment (telescopes).

When we develop using 8th we take a lot for granted:
1. we have an easy to use Operating System
2. we have plenty of good and free program editors
3. we have marvelous PC's with lots of internal and external memory
4. we have enough room for nice word names :-)

Those astronomers just used Forth. No OS, no (external) editor, very small internal memory.
How could that be???

Well, in fact the old school Forth was an OS in itself. It supported editing etc.
Still, it was not easy at all, because:
1. one had to wite their own device drivers
2. one had to take care of using the right chunks of memory (no overwrites)
3. one had only a very simple in built editor
etc. etc.

When I take a step back and compare my current smartphone with the mainframe I started with, well the magnitude of scale is really beyond what one could ever have expected.

Given the fact that we now do have plenty of memory. I still hate (very much) the many bloatwarez. So, in my search for the best programming languages, I always end up with the small ones, that accomplish many things right out of the box.

So, not Micro$oft or O$acle programming languages prevail in my vision.

I think 8th ranks with the few very best languages, not bloated, small footprint, very functional (many libraries), many target platforms (in part thanks to its Forth heritage).

If you did not try 8th earlier, please download a free copy here
The forum is *very* n00b friendly!

15 April 2016

Lesson 17 – Using files in 8th – Part 2


Reading a file in one sweep

Sometimes it is useful to read a file into memory in one go. For that we have the word f:slurp.
This word creates a buffer instead of a string! This means that is not the best way for reading a text file, if only because it can consume lots of memory. For a text file we’d better use f:eachline as in this example:



OS level file write operations invoked by 8th


f:chmod
Most often used to change the read-only mode of the file; on Unix-like OSes can do many more things.

f:copy
Tries to copy a file.

f:copydir
Tries to (recursively) copy a whole directory.

f:link
Tries to create a symbolic link to a file. This feature is mostly used in Unix like OS-es.

f:mkdir
Tries to create a new directory.

OS level file info requests

f:canwrite?
Detects if it is possible to write to a given file.

f:ctime
Gets creation time of a file.

Read the manual

When I go through the manual for the f namespace I see a lot of very useful words.
So really, you should study the manual, otherwise you’ll miss the juicy parts of 8th

A final example of file handling

We will:
1. Go into the root directory c:\ (Windows here)
2. Check if a directory with the name example already exists there
3. If not, create it
4. Go into that directory
5. Create a small text file there
6. Query some file info of that file

Program source code


"example"  var, dirName
"test.txt" var, fileName
false      var, dirExists
["line 1\n", "line 2\n", "line 3\n"] var, records

: chkSubdir
  dirName @ f:exists?
  if 
    "The name already exists and ..." . cr
    dirName @ f:dir?
    if 
      true dirExists !
      "... it is indeed a directory!" . cr
    else
      "Error: a file with that name exists already!"
      . cr reset bye
    then
  else
    "The directory does not exist yet ..." . cr
  then
  ;

: makeDir
  dirExists @ not
  if
    "... so we create it now!" . cr
    dirName @ f:mkdir not
    if 
      "Error: cannot create directory!" . 
      cr reset bye 
    then
  then
  ;

: openFile
  fileName @ f:create dup   \ dup to retain file handle
  null? 
  if 
    "Error: error while creating file!" . 
    cr reset bye 
  then
  ;

: helpWrite
          \ Stack: file ix value   
  swap    \ Stack: file value ix
  drop    \ Stack: file value
  f:write \ Stack: file rc
  null? if "Error: writing to file!" . cr reset bye then
          \ Stack: file
  ;
  
: writeFile
  records @ ' helpWrite a:each 
  drop \ Get rid of array now
  ;

: openro
  fileName @ f:open-ro
  dup null? \ dup to retain file handle
  if
    "Error: error while reopening file!" . cr reset bye
  then
  ;
  
: queryFile
  getcwd "Current directory is: " . . cr
  fileName @ f:exists?
  if
    "The file does indeed exist now!" . cr
  else
    "Error: file not found!" . cr reset bye
  then
  openro
  f:size  "File size       : " . . " bytes" . cr
  f:ctime "File created at : " . . cr
  f:mtime "File modified at: " . . cr
  f:close
  ;
  
: app:main
  "c:\\" chdir     \ Set current directory to c:\
  chkSubdir        \ Does the subdirectory exist?
  makeDir          \ If not, create it!
  dirName @ chdir  \ Set current directory 
  openFile         \ Open a file for output
  writeFile        \ Write the records to the file
  f:close          \ Close the output file
  openro           \ Open written file for read
  queryFile        \ Now query some file specs
  bye
  ;
  

Below the output of two consecutive runs:



More info about 8th


8th Website:   http://8th-dev.com
8th Forum:   http://8th-dev.com/forum
My YouTube Channel:   https://goo.gl/DscYVD
The Big 8th Lessons Book:   http://goo.gl/qDa6fH

11 March 2016

Lesson 16 – Using files in 8th – Part 1

Input and output

In order to permanently store data, we need a system to provide that possibility. Every full blown Operating System has got it’s own filesystem(s). E.g. in modern Windows you can use the NTFS file system and in Linux the ext2, ext3 and even Reiserfs file systems.

The file system is a layer between the OS and the hardware. The OS provides specific interfaces (API’s) for programmers to use such a file system.

Most programming languages encapsulate these API’s in their own programming language parlance.

Today we will start to learn how 8th does this.

It is very important to note that 8th is a Multi Platform development tool and that the file handling we do as a developer is on an abstract high level in such a way that 8th behaves correct even when using totally different file systems on totally different OS-es!

What is a file?

A file is a collection of sequentially stored records.

Mostly files are written and read sequentially (record by record). However, it is possible to point to a specific part of a file and read / write “at random”.

Furthermore, there is an important difference between 2 types of file:

  • Text files - such files are written line by line. Each line ends with (a combination of) CR (Carriage Return) and/or LF (Line Feed) characters (sometimes called newline characters
    • Example:   documents
  • Binary files - these files can contain anything. CR and LF characters that happen to be part of such a file have no special meaning
    • Example:   executable files, pictures (JPG), music (MP3), etc.

Files are also used as the building blocks of a database. But that is out of scope for us today.

Test if a given file does exist

If you are not sure if a file does exist, you can check for that:






If false is returned, the file does not exist (as in this case), otherwise true

Create a new file

Before we can write to a file, we must create that file, like so:


If the operation fails, the item on the stack will be null, otherwise it will be the file handle of the file just created.

Write to the new file

As we can see in the previous picture, f:create leaves the file handle on the stack, which is convenient for writing, because f:write expects that file handle to be on the stack!

Writing a line goes like so:



As we see on the stack there are now 2 items:

  • at TOS is the number of bytes written (here: 6) or null if the operation failed
  • at position 2 there is still the file handle (which is convenient for other writes)

Do not forget to check for null!

For now we drop the value on TOS:



As we can see the file handle is now at TOS again.

Now we write a second line:



As we can see the operation succeeded again and the file handle is still present in position 2 on the stack.

We drop the result again:



and see that the file handle is still present.

Close the file just written

In order to make the file correctly visible and complete in the file system of the OS, we must close the file:







The close word grabs the file handle from TOS and closes the file.

Maybe you would expect a return code from the close word. However, that would be meaningless, because we cannot “recover” anything if it failed!

Checking the file which we wrote

Using a text editor we now open the file just created:












We see that there is just one line written, with the text of both write operations. What the heck??? I wanted to write 2 text records, not this!!!

Binary file by default

In 8th by default files are written as binary files.

In our examples we didn’t provide a newline (CR of LF) character, which is needed in text files!

How to write a text file?

Well, that is easy! You should append a newline to your text to be written. Instead of:

  • “line 1”    f:write

You should use:

  • “line 1\n”    f:write

More info about 8th

8th Website:   http://8th-dev.com
8th Forum:   http://8th-dev.com/forum
My YouTube Channel:   https://www.youtube.com/channel/UCcwRyVDxU-lMfWgz_10DudA
The Big 8th Lessons Book:   http://goo.gl/qDa6fH

07 February 2016

Lesson 15 – Using maps in 8th

Conclusion of the lessons on arrays

In the previous lessons we have seen the most advanced words for the array namespace.

Now it is time for you to discover for yourself the other words in that namespace. Learning a language is best done using it. So please play with these words!

What is a map in 8th?

A map is a collection of key / value pairs. The keys are unique within a map. Instead of referencing an item by index (like with arrays) you must reference an item by key.

Keys must be strings in 8th. Values can be of any type.

Creating a new map



So, a literal map is surrounded by braces.

Keys and values must be separated by a colon and key/value pairs must be delimited by a comma.

Note that the colon and the comma (here) are NOT 8th words, but just syntax.

Retrieving a value for a specific key






In order to retrieve the map itself, we need G:@.
In order to retrieve the value for a key we need m:@.

Storing a value in a map using m:!







Note that the order of key/value pairs is arbitrary! This kind of container is not suited for sequential in order access.

Removing a key with it’s value from a map using m:-


Iterating over a map using m:each


Note that this works almost exactly the same as for arrays.

Conclusion on maps

There are a few more very useful words for maps.

For now I will leave you with “homework”

  • Study the SED’s for the array and map namespace
  • Try out some words for yourself
  • Never ever give up!
  • Post any interesting piece of code in the forum

If you need help, please ask any question and report any problem you may have in the forum! Today I made a stupid mistake and finally asked in the forum. It’s really not a shame whatsoever.

More info about 8th

8th Website:   http://8th-dev.com
8th Forum:   http://8th-dev.com/forum
My YouTube Channel:   https://goo.gl/DscYVD
My BLOG:   http://goo.gl/n1NocJ
The Big 8th Lessons Book:  http://goo.gl/qDa6fH

02 February 2016

Lesson 14 – Using arrays in 8th – part 2

More on arrays

Now we are going to see a few more advanced words in the a (array) namespace.

Iterating over an array – the word a:each

Later we will see that 8th has special words for iterating / looping.

However, there are also words like a:each that make it very easy to use iteration under the hood, without having to bother with the details.

The SED of a:each is \ a w – a

  • a = input array
  • w = the helper word

The SED of show (in our example below) is \ index value --

  • index = index of current array item
  • value = value of current array item

So a:each is such a word, that takes another word as a parameter (as we saw in the previous lesson).

The show word will be handed the value of the item at TOS and it’s index in 2nd position on the stack.

Example





Note that we have to use swap in order to show the index before the value!

Note that 8th arrays can contain values of different types (unlike e.g. in C).

Output:



Note that a:each leaves the array on the stack after executing!

Reducing an array using a:reduce

Reducing is a process like this:

  1. use an array
  2. get a start value x (which will be used as an accumulator)
  3. for every item in the array:
    1. do something with the values of the current array element and x (and also consume them)
    2. push the result on the stack; that value will then be used as the x value in the next iteration

The SED of a:reduce is \ a w x – x

  • a = input array
  • w = the helper word
  • x = initial value, also used as an accumulator

The SED of sum (just an example word below) is \ value x -- newx

  • value = value of current array item
  • x = initial value, also used as the accumulator

Example


Output:



Filtering an array using a:filter

This word uses a helper word that returns either true or false.

Only if that helper word retruns true, the corresponding element will be put in an output array.

The SED of a:filter is \ a1 w – a2

  • a1 = input array
  • w = the helper word
  • a2 = output array

The SED of iseven (just an example word below) is \ value -- boolean
value = value of current array item
boolean = true or false

Example


Note that the not word regards the value 0 (zero) as false! So when value 0 is encountered, not will output true and otherwise false.

Output:


More info about 8th

8th Website:   http://8th-dev.com
8th Forum:   http://8th-dev.com/forum
My YouTube Channel:   https://goo.gl/DscYVD
My BLOG:   http://goo.gl/n1NocJ