-
Notifications
You must be signed in to change notification settings - Fork 1
Fundamental Differences
At face value, Fun is a clone of Joy with a few different built in functions. A simple program, for example:
1 2 + .
Will produce the exact same result: 3
.
The real differences between the two are in the underlying implementation.
What this means is Fun does not actually execute a program until the ‘dot’ is reached. The result is that the language actually runs backwards, executing functions as they are popped off the stack by other functions above them. Alternatively, given the behaviour, one could say it’s “top-down” evaluated or perhaps even “self-evaluating”.
There are a few reasons behind using this type of behaviour, but the main one is that it allows the program to be compiled and executed without any kind of interpreter while still maintaining the homoiconicity and purity of the language, particularly with regards to executable lists. If the entire language was to run eagerly without an interpreter, lists would need to be compiled into some kind of hybrid list/function object that knows how to run itself. This is not really desirable, nor would it be even slightly fun to implement.
There are a few caveats to this behaviour. The most obvious being that it means some functions may be run at the wrong time. For example, you would expect the following code to run just fine in joy:
bq.
"lib-fibonacci" import
13 fib .
However, in Fun this would throw an error, since the import will not be executed first and as such fib is a nonexistent function.
Another common case where this backwards behavior shows through is using I/O. In joy, the following code:
"Hello " print "world!" print .
will output exactly what you would expect (well, ignoring that print is not a joy builtin). In Fun, it will output "world!Hello ".
The simple solution to such problems is to end your separate expressions with a dot, ensuring they will be run in order. If using a dot isn’t possible, try using a combinator to get the correct execution order.
Another caveat is that the language recurses a bit. I have tried to make as much use of tailcalls as possible to reduce the impact of this, however the fact is if you have a large program, it’s going to make a very deep call stack. Hopefully no one will run into issues from this, but it is something the programmer should be aware of.
Continuations in joy are basically a stack copy. Continuations are made often to preserve the stack and therefore the program ‘state’ while a function is being ran. Its useful, but quite wasteful. In Fun the stack is not copied when a continuation is made. Instead the continuation will mark where it sits relative to its parent, and if any values from the prior continuation are required, it will copy them as needed. A very handy feature.
I have no idea why they were added to Joy, but Fun does not implement them, mainly because I have no idea why they would be useful.
Ok, this is a lie at the moment. Fun does not have objects at all, but I plan to add them soon, now that all the required joy builtins have been implemented.