LIMA - a high-rise programming language
 


I thought about making my own programming language in mid 2005, because I was bothered by the weirdness and inefficiency of C programming. Since then I've seen the even greater weirdness and inefficiency of other languages, and come to the conclusion that a big change in programming languages needs to happen. Most languages seem to rely heavily on library functions which are not part of the core language. Since they aren't part of the core language, they don't always have consistent usage and aren't integrated in a way that helps you program concisely.

Lima (pronounced "Lie-muh") is designed to be easy to learn, write, and read while incorporating all the control and more one would expect after coming from C, C++, and Java. Here's a few attributes of the language:

  • Powerful type system
    • Strong typing gives the programmer fine control over the data flow in their programs.
    • Static typing allows automated error checking and method validation.
      • Assertions, and pre- and post- conditions augment the static types variables to be very specific as to what values a variable can take on, and when they can take on those values.
    • Dynamic typing - The var type provides a flexible dynamic type that can be used to hold a value of any type.
    • First-class types - the type 'type' can be used to define a variable that holds a type. These types can be passed into functions and manipulated like any other variables. This allows for the maximum flexibility in defining generic functions and objects - flexibility other languages like Java and C++ don't allow. 
  • Object-oriented
    • Everything is an object - even types and functions are first-class.
    • Multiple-inheritance is supported in an unambiguous way. In the case of inheritance name conflicts, if a variable or function name conflicts, the programmer must explicitly specify which class a variable or function name will come from.
    • A simple public/private variable scheme allows any class in a module (i.e. in a source file) to access the private variables of other classes in the same module (i.e. in the same source file).
    • Transparent getter, setter, and accessor methods (like python and ruby have) make getter/setter code both easy and unnecessary in most cases.
    • Generics syntax like object<type<int>> is supported - albeit in a different and more flexible way than other languages that use similar syntax.
    • Static and dynamic function dispatch are both supported through two different variables types: className and className+. Variables declared as "class" can only hold that class, while variables declared as "class+" can hold that class and any other class that inherits from that class. This provides a concrete dispatch mechanism that doesn't exist in any other language.
  • Imperative programming
    • The paradigm you're familiar with.
  • Declarative programming
    • Lima is designed with the thinking that machines should do optimization, not humans. Some core functions in lima don't use a specific algorithm, but will use an algorithm that the compiler determines best suits your specific program. If you so choose, you can specify an algorithm to use in these cases. But instead, consider writing an optimization plug-in that can optimize for your specific case. If you then release that plug-in, everyone can benefit from your optimization work, and you won't have to solve that optimization problem again.
  • Pass by reference - no catch
    • You can modify variables inside functions without restrictions or special syntax
    • The editor will tell you which functions are mutators, and which variables they mutate.
  • Meta-programming - custom languages
    • The "custom function" and "custom class" constructs allow you to easily create domain specific languages that can be used directly inside lima code. These allow you to quickly produce your own syntax and design practical and experimental languages for general or specific use.

Like Ruby's philosophy, Lima is designed for the human, not for the machine. Lima has high-level constructs in the core language that have implementations depending on use (but consistent meaning despite implimentation). The general list type can be used like an array, set, queue, stack, associative array, etc. Lima also has a graph type that allows the programmer to associate data in an arbitrarily complex way - but in a way also supported by the core language. Separating meaning from implementation is important for program readability and programmer productivity. It also encourages programmers to add to and improve compiler optimization algorithms, rather than hacking together original (or not so original) implementations on their own.

Unlike other languages, Lima relies on an active development environment to make reading, writing, and debugging Lima code easier than sleeping. Lima's terse non-redundant syntax means that some properties of variables and functions can be discerned from use rather than being explicitly declared (like function return types, whether or not an argument may be modified by a function, etc).

The ability to produce "custom functions" using the parse function makes Lima ideal for creating micro-languages and domain specific languages for use in normal programs. The parse function goes far beyond functions like strtok() and "regular" expressions that have limitations, poor readability, and a high learning curve. It allows arbitrary parsing of any type of list, not only strings.

Lima is a high-rise language,
which means that it has all low-level constructs but also has high level constructs that allows the programmer to choose the level they want to interact on at every step in the program.

Lima is a transparent language. Lima is built to collapse complexity rather than hide it. The final Lima editor should allow a programmer to examine various lower levels of code generated by the optimizer, even down to the assembly language level. Hiding complexity is fine enough for programmers that don't care about the inner workings of their computer, but de-collapsing such complexity can be extremely enlightening - which is why Lima incorporates this idea.

Lima is a multi-paradigm language. Lima is based heavily on "imperative", "functional", and "object-oriented" programming. In addition to this, the language also uses "constraint programming" paradigm in Lima's parse function. "Concurrent" and "distributed" programming will also be incorporated as well as easy graphics and application programming.

Lima makes readable projects. Makefiles are evil. Open source projects generally have a source tree that is more or less unintelligible, because they rely on makefiles to tell the computer which files to compile how and when. Unfortunately, makefiles are not written for humans in most cases. Lima is designed to need no compiler flags (and no makefiles) to be easily compiled. A Lima program contains one main file, which must contain all the information it needs to compile. Linked libraries and included modules are all declared in the main .lima file. Every other file should be a .lh file that is used by the .lima file. Compiling the project is as simple as compiling the .lima file.



     The syntax of Lima is designed to be as consistent as possible, so that both new and experienced programmers can learn the language quickly. Being consistent also produces a concise language, so that old programmers never have to look up old concepts.

     The syntax is based off of C++ but also takes from Java, Python, D, Verilog, Boo, Ruby, Lisp, and Water. Like python and Boo, unnecessary semicolons don't appear everywhere. Like C++, Java, and D, blocks are delimited by brackets (though they are square brackets in Lima). And like most of those languages, whitespace (tabs, spaces, and newlines) is generally ignored (except as a delimiter between language tokens/keywords). Lima gets its white-space delimited lists from Lisp and Water (an xml-based programming language). Lima takes the concept of blocks and its syntax partially from Ruby and Boo, its getter and setter ideas from Ruby, a high impedance value from Verilog, object type assertion function from Java generics, auto documentation and iteration syntax from Java, and different modes of type casting from newer versions of C++.

Some claim that lisp makes no distinction between run-time and compile-time, but lisp's macros are evaluated at compile-time, while functions and the like are evaluated at run-time. Lima really does make no distinction between run-time and compile-time, but attempts to perform at compile-time as many of the statements that it can or make any number of simplifications and substitutions at compile-time to make the run-time more efficient. In cases where program size is at odds with execution efficiency, the programmer should be able to decide which takes precedence and by how much.

Lima treats the whole process from a blank source file to a completed and executed program as a single event that should be optimized.



    
Industry has shown us that customization is really an alias for lazy-design - where designers add options and preferences because they don't know what the defaults should be. Even if companies would (please) produce good quality customizable products, one would always be lacking if they didn't have the ability to program themselves. Some people see a future where everyone will have the knowledge and ability to program their own computers to do what they want them to do.

     Lima is designed to be a programming language that is both simple and powerful - a programming language that anyone can use effectively, for any task. This may be ambitious, but it has to be to compete with today's languages. Because of this, Lima shouldn't be bogged down with obscure libraries which could be needed to provide necessary functionality. Lima can't be a second C++ that uses antiquated syntax. Lima can't be a second Java, which uses long fully specified class names and a huge set of libraries. Lima can't be a second Basic either, because it should be able to perform any function that the computer allows.

     Here are the current goals:
1. Write the Parse Standard Function so that it works for programming Lima.
2. Write a program to parse some basic Lima
4. Rewrite the Parse Standard Function in Lima.
3. Modify the Parse Standard Function so that it works for any input.
4. add the rest of the basic features of Lima
5. add graphics, sound, and application creation specifications to Lima - based on OpenGL, GLSL, and SDL and maybe OpenAL
6. add networking and threading specifications to Lima
7. Get some people (whoever's still reading this) interested in Lima
8. Get some of *those* people ^ to help me work on all these things.
9. Start a wiki where people can discuss how to improve the language.

     Here are some of the lofty goals:
1. Provide a concise core vocabulary that allows efficient and simple programming for any application without need for extra libraries.
3. Be able to translate into and from a wide variety of languages including C, C++, mips, Java, PHP, Fortran, and html+javascript+css.
4. Be able to translate into machine code for any notable platform.
5. Be able to translate into machine code that runs without an OS (most likely this would be used to program an OS).
6. Implement a way to write interactive web pages using dynamic programs instead of static HTML.
7. Also formulate a way to translate lima into HTML and javascript so that Lima can create working classic web pages.
8. Implement a garbage collection system for the language as an *option*, allowing both explicit garbage collection calls and automatic collecting.

     Here are some of the more specific long-term goals:
1. Be portable, while everyone seems to be coming to x86, not everyone's coming to [insert your favorite OS here].
2. Use in-code comments to produce out-of-code documentation.
3. Provide a comprehensive and well thought-out compiler and development environment that provides the ability to run Lima as an interpreted language (allowing run-time user modification of code, helping in debugging).
4. Provide unobtrusive smart error checking and semi-automatic error correcting in the development environment.
5.
Have the compiler provide default error messages to the user so that those types of things don't have to be programmed explicitly every time. Errors that are manually handled would automatically disable the default error messages.
5.
Allow the user to specify how optimized they want the code to be. Less optimized code compiles faster, and allows the programmer to build and test faster when optimized code is not imperative. Also allow full program optimization to optimize the entire project rather than just by section or file.

Look at my resume for contact information.