Whoa, linky. Who knew people actually read this blog? Zounds.
I should answer some of the questions being asked. (Why here and not on Reddit? Well, I don’t have a Reddit account, for one, and for two, I’d like to keep my answers about Smile in a place where they’re easier to find, rather than buried deep in a Reddit thread somewhere.)
So here we go.
- Smile is a Lisp derivative. With all that implies. Under the hood, all code is represented via symbols and cons cells. That’s not an accident; that was one of the original design goals. The magical abilities of the Lisp family to mutate your own code, to treat data as code and vice versa, were one of the original design requirements from when I first started on this trek so long ago. ‘
null‘ is the empty list and vice versa. (And yes, ‘
null,’ not ‘
nil.’ That’s a long explanation by itself.) There is an ‘
eval‘ that does what it says on the tin. Methods are functions are lambdas and are represented as lists and constructed from lists, in a very Schemish kind of way.
- Smile is a Smalltalk derivative. Cons cells are objects, with all that implies. There is a base Object from which everything descends. (Most stuff prefers ‘Actor’ as its true base, because Object is intentionally empty, whereas ‘Actor’ has a whole truckload of useful methods for doing reflectiony kinds of things like
list?and so on.) There is also a syntax translator that converts “clean” syntax into canonical form, following many of Smalltalk’s rules.
- Smile has some similarities to Ruby and to Python, but it is neither. Ruby and Python are great languages. Matz and Guido both rightly deserve praise for what they’ve built. But at the same time, I believe they didn’t go far enough. They’re great practical languages, but they don’t have the theoretical purity of something like a Lisp or a Smalltalk. In Smile I can take a method on an object, pull its body apart as a tree of cons cells and symbols, inject new “code” as data in the middle of it, turn it back into a lambda, and hook it to an object as a new method. (Example provided below.)
- Identifier parsing is unusual, by design. Certain punctuation characters terminate a preceding identifier, and certain others become a part of the preceding identifier. There are two categories of identifier, alphanumeric and punctuative, during lexing distinguished by the class of initial characters each will accept, and each allowing different sets of subsequent characters. (For the compiler geeks out there, these classes are uniquely describable using FSAs, but are more easily implemented with ad-hoc code.) The identifier rules are designed to allow you to write
sum/countin a natural way, without requiring the spaces that Lisp identifiers would require to disambiguate it.
- About hyphens. These identifier parsing rules mean that hyphen is necessarily overloaded; a number of you pointed out that hyphen is a bit odd in some of the examples.
print-lineis a single identifier, as is
print- x(notice the space) is three identifiers because hyphen cannot be an initial or trailing character on an alphanumeric identifier; but on a punctuative identifier, like
<--, it’s perfectly legitimate as a trailing character. Requiring whitespace to separate all identifiers is annoying, and I spent quite a lot of time refining the rules over the years until I got a set of rules that would allow it to be omitted in a lot of common scenarios. Also: Why hyphen for separating identifier words and not underscore? Simple: It’s one less keystroke. Hyphen is easier to type than underscore, and surprisingly, I’ve found it to be more comfortable to read too. There are a number of places in Smile where the language design was influenced by the number of keystrokes required to do something, which is (among a few other reasons) why Smile uses
if (...)— parentheses are slower to type than
- Smile is very immature at this point. The core of the language is there, and I have a working interpreter. The libraries are great in some places (lists, functions, integers, strings), and are still pretty severely weak-sauce in others (exceptions, files, networking, more complex data structures). The interpreter is currently written in C#, and I really want to someday rebuild the whole thing in C for performance and flexibility, but C# allowed me to get it off the ground and fix bugs and gotchas faster than C would have. There’s no debugger. A handful of the ancillary language features are still either partially implemented or unimplemented (first-class macros, assertions, Scheme-like catch-symbol-as-goto). Nearly every other major and minor language out there runs circles around the current implementation. But even with all that, what exists is a surprisingly solid foundation, and I’ve built the first couple of initial “release” packages of it for the first few adopters to begin using — literally, smile-release-0.2.tar.gz is the current “release” tarball.
- I don’t expect anybody else to like Smile. Seriously, if you’re a Lisp addict, go code Lisp — I sure as heck won’t stop you. Haskell? Ocaml? Go have fun and knock yourself out. If you want Ruby or Python, they’re fine and worthy languages. Smile exists because none of the many many languages I’ve coded in over the years fit what *I* expected to see in a language. I expected good theoretical foundations, a lack of kitchen-sink mentality (I’m not gluing in features just because they’re fashionable), and high expressivity with just a handful of basic constructs. I expected to not have to work around hardwired syntax for things like
- I don’t expect Smile to change the world. Smile is cool, and I have had more fun coding in Smile than I have had in any other language, and I’ve coded in a lot. But there’s a lot of language competition out there, and maybe Smile will never have anybody using it but me. And I’m okay with that. I’m going a direction I believe is right, and I don’t expect anybody else to follow me — I’m sure as hell not a leader. If you want to code in Smile, that’s awesome. And if you don’t, that’s fine too. You’re welcome to your opinion, and I respect it; but your opinion probably won’t change Smile because the language is what *I* believe it needs to be.
Since you guys asked for it, here’s a slightly more interesting example demonstrating some of what makes Smile unique:
#include "stdio" Integer.factorial = |n| if n > 1 then n * factorial (n - 1) else n Integer.sum-up-to = Fn of Integer.factorial.arguments, (Integer.factorial.body map-recursive |item| if item == `* then `+ else item) Stdout print-line Integer.factorial, ": ", factorial 5 Stdout print-line Integer.sum-up-to, ": ", sum-up-to 5
[$fn [n] [$if [n.> 1] [n.* [[n.- 1].factorial]] n]]: 120 [$fn [n] [$if [n.> 1] [n.* [[n.+ 1].factorial]] n]]: 15