Home

Awesome

~ readme ~

     .ooo
      'OOOo
  ~ p ooOOOo tion ~
      .OOO
       oO      %% a little
         Oo    fast language.
        'O
         `
        (o)
    ___/ /
   /`    \
  /v^  `  ,
 (...v/v^/
  \../::/
   \/::/

Build Status Coverity Status perl11.org/potion/

~ potion ~

Potion is an object- and mixin-oriented (traits) language.

Its exciting points are:

However, some warnings:

~ a whiff of potion ~

5 times: "Odelay!" print.

Or,

add = (x, y): x + y.
add(2, 4) string print

Or,

hello =
  "(x): ('hello ', x) print." eval
hello ('world')

~ building and installing ~

$ make

Look inside the file called INSTALL for options.

~ how it transpired ~

This isn't supposed to happen!

I started playing with Lua's internals and reading stuff by Ian Piumarta and Nicolas Cannasse. And I, well... I don't know how this happened!

Turns out making a language is a lovely old time, you should try it. If you keep it small, fit the VM and the parser and the stdlib all into 10k lines, then it's no sweat.

To be fair, I'd been tinkering with the parser for years, though.

~ the potion pledge ~

EVERYTHING IS AN OBJECT. However, OBJECTS AREN'T EVERYTHING.

(And, incidentally, everything is a function.)

~ items to understand ~

  1. A traditional object is a tuple of data and methods: (D, M).

    D is kept in the object itself. M is kept in classes.

  2. In Potion, objects are just D.

  3. Every object has an M.

  4. But M can be altered, swapped, added to, removed from, whatever.

  5. Objects do not have classes. The M is a mixin, a collection of methods.

Example: all strings have a "length" method. This method comes with Potion. It's in the String mixin.

  1. You can swap out mixins for the span of a single source file.

Example: you could give all strings a "backwards" method. But just for the code inside your test.pn script.

  1. You can re-mix for the span of a single closure.

To sum up:

EVERYTHING IS AN OBJECT. EVEN MIXINS ARE OBJECTS. AND, OF COURSE, CLOSURES ARE OBJECTS.

However, OBJECTS AREN'T EVERYTHING. THEY ARE USELESS WITHOUT MIXINS.

~ unique ideas (to be implemented) ~

Potion does have a few unique features underway.

The language itself is objects and closures.

Number add = (x): self + x.

But it also includes a data language.

app = [window (width=200, height=400)
  [button "OK", button "Cancel"]]

The code and data languages can be interleaved over and over again. In a way, I'm trying to find a middle ground between s-expressions and stuff like E4X. I like that s-expressions are a very light data syntax, but I like that E4X clearly looks like data.

When s-expressions appear in Lisp code, they look like code. I think it is nice to distinguish the two.

The closing "_ say" ends the block saved to "say" var.

Normally, blocks are closed with a period. In this case we'd need three periods, which looks strange.

say = ():
  10 times:
    20 times:
      "Odelay!" print
...

If you prefer, you can give it some space. Or you can use a variable name introduced by the block,

say = (phrase):
  10 times (i):
    20 times (j):
      phrase print
_ phrase


say = (phrase):
  10 times (i):
    20 times (j):
      phrase print
  _ i
.

Maybe it all looks strange. I don't know. I'm just trying things out, okay?

Period means "end". (In other langs it means "method call".) Comma breaks up statements. Space between messages gives a noun-verb feeling.

window open (width=400, height=500)

Assignments are side-effects only, but here extended. Atoms on the left-hand side (lhs) are trivial, but we prefer the power of LISP's destructuring-bind within macros, or prolog or elixirs matching. So = is actually a match operator which will recursively check if the expressions on both left and right side match, and binds all found lhs variables.

(1, x) = (1, 2) => (x=2)
(1, x) = (2, 3) => false
1 = 2           => false

_ is a special variable which matches everything, but is never bound, | seperates the head and tail from a list or lick.

So we can check trees like this:

(_, x, 2)   = (0, 1, 2)   and say x #=> 1
[_, [x, 1]] = [0, [1, 2]] and say x #=> 1
[_, x]      = [0, [1, 2]] and say x #=> [1, 2]
[_ | x]     = [0, 1, 2]   and say x #=> [1, 2]

fun = (a, b): [0, [a, b]].
[_ | [x, 1]] = fun(1, 2)  and say x #=> 1

~ feverish and fond thankyous ~

why is gravely indebted to Basile Starynkevitch, who fielded questions about his garbage collector. why favors French hackers to an extreme (Xavier Leroy, Nicolas Cannasse, Guy Decoux, Mathieu Bochard to name only a portion of those I admire) and is very glad to represent their influence in Potion's garbage collector.

Matz, for answering why's questions about conservative GC and for encouraging him so much. Potion's stack scanning code and some of the object model come from Ruby.

Steve Dekorte for the Io language, libgarbagecollector and libcoroutine -- I referred frequently to all of them in sorting out what he wanted.

Of course, Mauricio Fernandez for his inspiring programming journal housed at http://web.archive.org/web/20110814062722/http://eigenclass.org/R2/ and for works derived throughout the course of it -- extprot most of all. Many of my thoughts about language internals (object repr, GC, etc.) are informed by him.

Ian Piumarta for peg/leg. We use a re-entrant custom version of it, but the original library is sheer minimalist parsing amazement.

Final appreciations to Jonathan Wright and William Morgan who pitched in, back in the wee hours of Potion's history. Thanks.

~ license ~

See COPYING for legal information. It's an MIT license, which lets you do anything you want with this. I'm hoping that makes it very nice for folks who want to embed a little Potion in their app!