Ola Bini, a core JRuby developer and author of the book Practical JRuby on Rails Projects, has been developing a new language for the JVM called Ioke. This strongly typed, extremely dynamic, prototype based object oriented language aims to give developers the same kind of power they get with Lisp and Ruby, combined with a nice, small, regular syntax.
Ola explains the basic nature of Ioke:
Ioke is a strongly typed, extremely dynamic, prototype based object oriented language. It’s homoiconic and got built in support for several kinds of macros. The languages that most closely influence Ioke is Io, Smalltalk, Self, Ruby and Lisp (Specifically Common Lisp).
The language is currently built on top of the JVM, but I’m currently considering compiling it down to JavaScript and run it on V8.
I have several goals with the language but the most specific one is to create a language that combines the things I like about Ruby and Lisp together. It turns out that Io already has many of the features I’m looking for, but in some cases doesn’t go far enough. I also wanted to have a language that is very well suited to express internal DSLs. I want to have a language that doesn’t get in my way, but also gives me loads of power to accomplish what I want. To that event I’ve designed a macro system that some people will probably find insane.
InfoQ had a small Q&A with Ola Bini about the design of Ioke:
InfoQ: It seems that one of the key features of Ioke is the fact that it uses prototype based inheritance. Do you feel that its benefits are so overwhelming compared to the dominant class based orientation?
OK, so yes, this is one of the features of Ioke, but I'm not sure if it's a key feature or not. It changes the design of some things substantially, yes. I feel more comfortable in it, than in a class based system, actually, and since Ioke is primarily a language I develop for my own sake, my comfort tends to be important.
In Ruby, you can use the singleton classes to achieve something that looks a bit like prototype based OO, and I find that you can model algorithms quite cleanly that way. And there is no obvious problem in power, since you can always do class-based OO by convention, if you want.
One of the main guiding principles for Ioke is that I do not want to take any decisions for granted. Should I use class based OO just because it's the dominant paradigm? Not necessarily. There are obviously good reasons for many things, but there are also lots of historical baggage that doesn't make that much sense for most applications. So I'm trying to revisit as much as possible during the development of Ioke.
InfoQ: Since the only mainstream language with prototype based inheritance is JavaScript, do you think that this paradigm has a potential to be widely understood and used?
I actually think that prototype based OO is more natural, and easier to understand than class based OO. I think class based OO have to be learned, and that most people will find prototype based OO more intuitive once they unlearn the class based OO mantra. Of course, JavaScript might not be the best comparison, since the prototype based nature of the language easily gets hidden beneath all the cruft and corner cases of the language model, which means that most developers doesn't actually know how to use these parts of the language in a good way.
InfoQ: It seems that Ioke has been designed from the ground up to be a JVM language. Do you think that this will be the dominant trends for new languages for a long time to come?
My current thinking is that it doesn't really make sense to create your own virtual machine from scratch. Most new languages are garbage collected, for example, and I don't understand why people who create languages want to write their own GC. It will just take months from their lives and they will generally have done a subpar job. Just look at all the trouble Ruby has with GC. This thinking obviously is relevant for many other things too - especially libraries. So yeah, Ioke is a JVM language (but most of the language is not dependent on it. you could reimplement it on top of another platform, quite easily. The core is very small). And yes, I believe that languages targeting the JVM, the CLR, Parrott and to a degree LLVM should be the norm. There are very few cases where it makes sense to write your VM from scratch.
InfoQ: The conditions system you are implementing for Ioke seems similar to the exception handling system in Java, but more flexible. Can you give us some examples that demonstrate better it value?
Well, you could say that exceptions provide a subset of the functionality of a condition system. There are two differences - the first one is from the point of protocol and abstraction. Everything that exceptions are used for doesn't have to be exceptional or an error. Or take warnings. In most dynamic languages there are ad-hoc logging based warning systems. But what if you want to do something else? In Ruby you could change the warn method to raise an exception. But this still means there is a divide between how warnings and exceptions are handled. Or take system interrupts, or thread interrupts. All of these are superficially different features, but can be viewed as the same thing, really.
Conditions allow you to unify these. They provide a uniform protocol for talking about these kinds of events.
The functionality conditions provide you is twofold. The first is restarts, which is actually almost totally separate.
A restart is something you can register in a block. It's basically pieces of code to execute when a restart is invoked. And then there are some methods to invoke a named restart, find all active restarts and so on. A restart can be seen as an exception mechanism, almost. It's dynamic in scope.
Conditions allow you to register handlers for something that can happen. When that condition happen, a handler can choose to handle it, or pass it along to the next handle. But this isn't unwinding the stack (not yet at least). If a handler wants to do something about a condition, (and a handler is also a piece of code), that piece of code will be executed in the lexical context of the handler, but in the dynamic scope of the place where the condition was first signaled. This means that a handler several method calls away from a condition signaling point can actually do stuff in that context.
This isn't that strange, you could do it in pure Ruby for example. But it loses a bit of it's power if it isn't available in the standard library.
In Common Lisp it's very powerful. When you use Common Lisp interactively, the default handling of a condition is to dump you into a debugger. This debugger runs in the context of the place where the error happened, and it can do the same thing as a handler can do - including provide new values for variables and so on. The debugger doesn't need to do anything special it all, it's really only a specific use case for the condition system.
I really can't overemphasize how powerful this is.
InfoQ: How do you think Ioke measure up in terms of maintenance and refactoring, being dynamic but also strongly typed?
Hard to say at this point. Since it's quite terse and provide powerful features for succinctness, it should be very maintainable. Automated refactoring is probably not that interesting at this point for the same reason.
Just like Lisp, Ioke provides syntactic abstractions. They take two forms, the first one is macros, which is basically like method calls with lazy arguments that can be evaluated in special ways. The other form is syntax, which works a lot like Common Lisp defmacro. These together provide the possibility of creating new control structures and define new abstractions. The language is powerful enough to allow you to create your own method types, for example. If you don't like keyword arguments, you can define a new method type that doesn't have them. The DefaultMethod currently in Ioke could be implemented purely in Ioke, using macros.
InfoQ: For the syntax of Ioke you have chosen to follow the examples of Lisp and Smalltalk, e.g. the usage of the space. Someone could suggest that this will alienate most developers that are used to read and write C-like code. Do you think that this is the case?
I've been a C, C++ and Java programmer for a long, long time, and I never got comfortable with it. It is really a cumbersome syntax, and as many people before me has noted it's actually a large stumbling block for powerful abstractions. Doing syntactic macros is very inconvenient when you have an AST that looks like these languages. The syntax is a large part of that, since it's so extremely ununiform.
So, yes, people might find it unnatural at first, but I really like how it reads, and I think that people will like that aspect of it. I find Ioke to be highly readable in a way that Java is not, for example. There isn't that many punctuation characters that get in the way. Compare Java, Ruby and Ioke:
Arrays.asList("foo", "bar", "quux") .map(new Function<String, Pair<String, Int>>(){ public Pair<String, Int> call(String str){ return new Pair<String, Int>(str, str.length()); }}).select ..... // this gets too long, ok? ["foo", "bar", "quux"].map {|str| [str, str.length]}.select {|n| n[1] > 3} ["foo", "bar", "quux"] map(str, [str, str length]) select(second > 3)The difference with Ruby is not that large in this case, but it can differ wildly too. I find that it's much easier to read method applications separated with whitespace. Using dots to terminate an expression also makes a really large difference.
So, as a Lisp person, it feels slightly heretical to say this, but syntax actually matters. My goal with Ioke is to get the same kind of power I get with Lisp and Ruby, but combine it with nice, small, regular syntax.
If you are interested in following the development of Ioke, you can check it out at Ola’s git repository, or visit the project pages.
You can also find more information on Programming Languages,the JVM and Ruby right here at InfoQ.