About Oforth

Oforth is a dynamic language

Oforth is coming as an interpreter. You can try things interactively while building your classes.

There is no compilation phase. Compilation is done when commands are entered.

A dynamic language does not mean a slow language. Even if a lot of features are handled at runtime (polymorphism, ...), Oforth can compare with many languages that have a compilation phase.

More details

Oforth is fast

Oforth has no bytecode. While reading code, immediate words generate native code on the flow.

Even if Oforth has no compilation phase, words are compiled.

Oforth garbage collector is incremental

Since release V0.9.22, GC is not a "stop the world" phase.

Tasks are allowed to run between GC steps.

GC steps duration is about 100 microseconds.

More details

Oforth is a concise language

The more lines you write, the more bugs you have...

With oforth, functions with more than three or four lines are rarely encountered. Using the data stack and the RPN allow to have very concise methods.

If you check lang package files, you will see that it is fully comprehensible quickly (about 30 files to handle all basic classes and have a functional system, and very short functions or methods.

More details

Oforth has functional programming features

Although oforth is an imperative language, some characteristics allow functional programming features :

  • Immutability is the default behaviour.
  • Everything is an object, even functions, methods, ...
  • These objects can be sent as parameters to high order functions.
  • Blocks are anonymous pieces of code and are also objects.
  • Even if functions can't be created by other functions, blocks can be the return value of functions or methods.

More details

Oforth parallel programming is easy

Handling concurrency can be tricky with threads.

With Oforth, threads are not visible. Oforth model is based on independant tasks that does not share their objects. The only way to send objects to a task is to use a channel. Only immutable objects can be sent into a channel.

Task creation and task context switches are far less expensive than threads creation and context switches.

Use of channels for objets transport between tasks is effecient : because objects are immutables, there is no copy and there is no need to handle synchronisation between tasks. Synchronisation is handled by the system at the channel level.

All oforth resources are compatible with this model : not only channels, but also sockets, console, ...

More details

Contact

Oforth is created and written by Franck Bensusan.

You can use the forum to post comments or remarks.

If you want to send a private message, you can use this mail.

Some examples (from tutorials).

You can find lots of examples here

Factorial

: fact(n) n 0 == ifTrue: [ 1 ] else: [ n fact(n 1 -) * ] ;



Fibonacci sequence

: fib(n) 0 1 n #[ tuck + ] times drop ;



Look and say (see detail)

: lookAndSay(n) [ 1 ] #[ dup println group map([#size, #first]) ] times(n) ;



Sum of square roots of all even integers between 1 and 10000

seq(10000) filter(#isEven) map(#sqrt) sum println 333383.040171148



A ping pong between 2 tasks running concurrently and using channels to communicate

: pong(n, ch1, ch2) | i | n loop: i [ ch2 send(ch1 receive) drop ] ;

: pingpong(n)
| ch1 ch2 i |

   Channel new ->ch1
   Channel new ->ch2
   #[ pong(n, ch1, ch2) ] &
   n loop: i [ ch1 send(i) drop ch2 receive println ] ;



An emitter that launches event listeners into parallel tasks running concurrently

: myemitter {
| e |
   Emitter new(null) ->e
   e onEventParallel($foo, #[ "foo" println ])
   e emit($foo)
   e onEventParallel($foo, #[ "bar" println ])
   e emit($foo)
   e close ;