General Ideas
Z-talk is a lisp. But don't tell anyone, people don't dig lisps these days. Mostly because very few know what it actually means. But I'll tell you right away: lisp is a language, that you can extend with any language construct you like by writing this extension in the same language and including it as a library. Basically, this gives any lisp the power of any (or better every) other language.
Heard something cool about new super-duper-funcy language? Write an extension to your lisp and start using it in your programs right away.
Heard about new proposal for C++, that will be included in the standard in a few years? No need to wait, implement it as a library in lisp.
Ok, that's lisp. But what about Z-talk? You just said any lisp can be extended with any feature, which probably means all lisps are one and the same.
Well, not exactly. Or better say, they should be, but in fact every one has limitations. Not inherently, btw. It's just creators of lisp choosed to limit their languages. Why? God knows! But it's just fact of life.
Is Z-talk limited too? To my knowledge, no. If you notice something, that you think cannot be implemented in Z-talk, tell me immediately. I'll do my best to fix the glitch.
Ok, more specific, what are the features of Z-talk that make it so cool?
I would say this. Z-talk is a library, it is its own library. And you are free to extend it. For example, when Z-talk reads your program, it uses library functions to parse it and you are free to extend (or even replace) this library. When Z-talk compiles expressions it just read, it does some transformations, which you again are free to overload. And so on.
You might say that there must be something underneeth it!
No, it's turtles all the way down!
Ok, there is something concrete enough that allows the base language to work: basic data types and basic evaluation procedure.
Data types
Integers (not 32- or 64-bit integers, just integers, as in math) Symbols (or names) Tuples (as in math) Arrays (like tuples but can be extended) Dicts (assiciative arrays) Nil (like “no value”) Procedures (something you can call) User defined types (anything you like)
Fundamental operators:
- lambda: (lambda (x) (x x))
- apply: (f x)
- continuation capture: (call/cc f)
- quotation: 'x
- annotation: (annotate type x)
Runtime hooks:
(annotate 'mac x) — makes x a macro
(0 f) — same as ((lambda (x) (x 0)) f)
From the user's point of view everything is a dict. Internally it's not the case, but z-talk's runtime make every base type look like a dict. For example, when expression like (f x) is evaluated, you can think what actually happens is the call to a function, that is stored in a type object of variable x, i.e. the same as ((dict-ref (type f) #call) f x). In fact, you can actualy evaluate the latter expression and get the same result, except performace will not necessary be the same if type of f is primitive. This works for objects of any type which means you can put any function into a dictionary with the key #call and it will be called whenever you evaluate an expression with an object annotated with this dictionary in a functional position. For example:
(def vect (dict #call (fn (t i) (t i))))
(def (mk-vect n) (annotate vect (mk-tuple n))
(def v (mk-vect 5))
(print (v 0))
When (v 0) is evaluated type of v is accessed as a dict, the value associated with the key #call is calles with arguments v and 0, which in turn returns the 0th element of the tuple (rep v).