One of the things I wanted to do from the beginning of the project is approach it from a highly pragmatic standpoint; not necessarily asking "what makes the most sense in terms of idealistic goals" but rather "what's going to convince real programmers in real projects to use this language." In fact, I've been a little more pragmatic than that, even: the central question (at least in this early phase) has been "what kind of language do I want to use that would make my life a billion times easier?"
There are two immediate answers to this in my mind: first, I want a functional language, because I find them superior for constructing powerful abstractions. More importantly, functional languages are very good at creating layers of abstraction, and I firmly believe that the best way to build software is by layering abstractions onion-style. Lisp is, of course, the canonical king of this style of development.
The second thing I want is low-level transparency. Specifically, I'm a game developer at the moment, and for game development to adopt new languages at any significant rate, those language have to be able to talk in low-level terms. We simply must be able to communicate in ways that hardware can understand, and that means that our tools must understand the existence of bits, and bytes, and processor cycles, and data busses. It is non-negotiable.
Even further than just game development, though, low-level access is mandatory for actual hardware drivers and OS implementations. There are two reasons why I feel this is especially important.
One reason is rather idealogical and speculative, but still worth pursuing. Consider the notion that nested abstractions are (generally) the most robust ways to build systems. It is easily apparent to anyone with experience with this model that if each layer of abstraction is written in the same language, life is generally much simpler. Mixing languages isn't impossible or even especially difficult much of the time, but it can introduce serious complications.
Take this a step further, then. We write ApplicationX as a set of nested abstractions, all in Foo Language. What better way to make use of built-in OS functionality or libraries, than if the OS itself is written in Foo Language? The power of this approach is readily apparent in the *nix world, where C (and languages that interface well to C) is de facto king.
Imagine never having to worry about GUI APIs or hardware compatibility again, because all of your drivers and libraries are already written in a standard langauge in a standardized way.
Best of all, because the language itself is very pliable and configurable (think of Lisp's "programmable programming language" ideal), the fact that everything is in a single "master language" actually helps domain-specific projects rather than hindering them.
(Contrast this to our current situation, where a highly domain-specific language like MATLAB just isn't easily integrable with, say, DirectX. Right now, we have "different tools for different jobs" and that's a good thing overall. If, however, everything in the system is designed to work well within a standardized meta-language framework, Lisp-machine style, this inverts itself, and it becomes beneficial for everyone to use that same set of languages.)
There's another reason why I want the Epoch language to believe in low-level notions, however: we're coming due for a hardware architecture revolution. The x86 arch is terrible and needs to die, and multicore architectures are misguided and ugly for a host of reasons.
I don't think we'll see this hardware revolution come from hardware designers. Intel won't design a new CPU that demands that Windows be rewritten from the ground up; it just isn't smart business.
So the revolution will work from the other direction. Good apps will be written in a good language, and eventually, if that language plays by the right rules, good libraries will be written and shared. Those libraries will facilitate the development of more apps.
Now here's the magic tipping point: if the language supports low-level notions, those libraries can actually become closer to hardware over time. Eventually, we reach a point where it is feasible to actually write the entire user experience portion of the OS in this Foo Language, on top of something like the Linux or Mach kernel.
From there, it's going to be abundantly clear that the next best step is to write the OS core itself in Foo Language, and that will be possible if Foo has sufficient low-level capabilities.
I see this being a very plausible progression for technology, but only if some Foo steps up to the plate and fills that role. Since Epoch already needs to have low-level features to fit my own personal demands, why shouldn't it also become this utopian framework on which entire systems are built? Interoperability issues would evaporate quickly, standardization would be a radically simplified concern, and we could finally step beyond petty technical concerns that have bogged down software development for decades, and actually start solving interesting problems.
It's all well and good to speculate about the future of a language, but it's obviously a tiny bit silly when that language doesn't even exist in any meaningful way yet.
Rest assured, I really am working on things [wink]
As I remarked quite a while ago, the current syntax is looking to be a sort of bastard child of Haskell and Lisp. In fact, it could almost be a Lisp dialect, with liberal use of macros to add syntactic sugar, except for the fact that it's also highly "typeful."
Again, the "be pragmatic" guiding principle has helped immensely here. In particular, I've been considering how exactly to go about creating early implementations of the language, which will be evolved iteratively into something suitable for general release.
My scheme at the moment looks something like this:
- Create a very simple execution environment which "parses" and "executes" a program. A program can consist of only one keyword, error which is a magic function. When the error function is evaluated by the runtime, the program stops and displays an error message.
- Define an interface by which certain concepts of execution can be deferred to the "execution environment." This environment is a sort of stack, at which the application sits at the highest level, based on the onion-model of abstractions. For example, arithmetic would be deferred to the environment rather than actually computed by the program itself.
- This notion of deferring operations is actually extremely powerful, provided that the interface is defined carefully. In particular, deferred monadic operations provide an easy interface for upcalls into non-Epoch execution space. This then allows us to create bindings to non-Epoch libraries and APIs, similar to marshalling to unmanaged code in .Net.
- Binding outside of Epoch immediately avoids a lot of wheel-reinventing. In particular, real, deployable Epoch programs can be written relatively quickly without needing to write a lot of support libraries or boilerplate code. This allows the language to be put into real usage early, which as I've said before I think is absolutely critical to making the language successful. "Dogfooding" will be vital.
- Again, if the deferred operation model is defined well, this also allows the actual execution model of Epoch to be evolved without affecting any running code. So we can start with a hacked up parser/interpreter running in C# (which is indeed my current plan), and move on to a proper JIT compiler/VM and even machine code eventually.
Obviously this is all still fairly abstract and vague, and there's a lot of idealistic shortcuts and license being taken in my thought process. But it's a start, and more importantly, it's keeping me interested in continuing to actually develop the project and produce something of measurable value.