Language Design

Posted by Rusky on Feb. 21, 2011, 7:09 p.m.

So, before I begin, how can I update my submissions? Do I just resubmit them or is that not implemented (yet) in v3?

C is a relatively nice high-level assembly language. C++ is the kitchen sink sitting on top of that, so you can do lots of things with it but it can be painful. I'm sure this will be disputed, so I'll get to it in a minute. Java is a simplification of C++, but in some places it oversimplified like with "a.setFoo(a.getFoo() + 3)." Scala and C# move back toward C++, but they're both still on VMs and designed for high level applications.

That leaves us with few options for low-level and/or performance-sensitive projects like game engines, operating system kernels, embedded applications and almost anything else fun. Contemporary, well-supported, easily-accessible and well-enough designed languages include C, C++ and… well, anything else fails to meet our requirements.

It's obviously possible to write large projects in C (e.g. the Linux kernel) but it's not the best-designed of languages. All the little things like type conversions, declaration syntax, scope and namespaces and verbosity make C more painful than it could be. Then larger-scale issues like polymorphism (ad-hoc/inclusion and parametric), higher-level functions and type safety go out the window.

C++ almost had to be based on C to become popular, so it inherits a lot of its problems. In addition, it's just a big kitchen sink bolted on top, so it lacks the elegance of languages like Smalltalk that a lot of its ideas come from. Larger projects have to enforce restrictions on different allowed subsets of features (Google eliminates exceptions, RTTI and multiple inheritance in the interest of compatibility, less fragile code and consistency).

I would like to design a systems-level programming language that can be as efficient as C but can also be much more expressive and easy to use than C++. Rather than designing by committee to build a checklist of features, it would need to have a unifying idea, like Lisp, Smalltalk, Haskell or Go. The systems-level programming world needs something like that.

Rather than starting from C or C++, I'll start from scratch. The goal will be to use a small, easily-learned feature set that will allow a large range of simple, concise designs. Things like Lisp macros, Haskell type classes, Smalltalk/Objective-C message passing, etc. Haskell comes closer to this than Smalltalk, in that its type system is much stronger than C's (although it would need some tweaking to allow the required control over memory layout, etc.), but still allows all the uses of C++ virtual function calls, CLOS multimethods and OOP-style namespaces.

Anyone have any stories of things they'd have liked to be able to express in their favorite programming language but couldn't without resorting to verbosity, repetition or some ugly hack or other?

Comments

Rusky 13 years, 9 months ago

This makes me cry.

Cpsgames 13 years, 9 months ago

I know C# and Java. I personally like C# more, unless you want a web app. Screw Silverlight then and go to java or whatever.

Undeadragons 13 years, 9 months ago

I find Java has oversimplified things too much, I prefer C++ to it, but at the end of the day, as long as I can avoid ASM while programming PCs I'm happy. The only problem with C++ is that occasionally one has to resort to the odd hack, or resort to bad practices (like overloading primitive data types).

Designing a programming language isn't too hard, implementing a compiler and/or assembler on the other hand can be a real pain in the ass. Just one bit of advice, if you do design a language, beware of feature creep, have a very clear outline.

Castypher 13 years, 9 months ago

I know I'm a bit late on this, but here you go anyway.

Quote:
Also, cout is almost as bad.
I wasn't talking about efficiency or implementation. I was only talking about how painful it is to type longer commands a thousand times. Cout and System.out.println were just examples, and obviously you don't use those all the time, since we're no longer writing programs for users to open in the command prompt.

Rusky 13 years, 9 months ago

Designing any old programming language isn't hard, but what's the point of that? The point of designing a programming language is to make something better than the feature-blobs we have now (in other words, having a "clear outline" as you say). That's just as difficult as implementing a compiler.

I was talking about the syntax of iostreams as well. They're often at least as verbose as System.out.println once you start actually printing things instead of just typing their names. C++ does have a slight edge on Java in the syntax/verbosity area, but it's really not much better. Compare it to scripting languages or functional languages and you'll see what I mean.

Misconstruct 13 years, 9 months ago

You don't even have to worry about syntax with drag and drop, baby!

Undeadragons 13 years, 9 months ago

Well of course designing a solid programming language can be tricky, the trade-off is design time & implementation complexity vs. distance from machine code. That being said, given that you seem to have an idea of what such a feature set would be, it wouldn't be too hard, so long as you stick to it.

I do agree with you though, whilst there is a lot of power to be derived from lower lever languages, they often have problems due to how they were created, C++ is probably one of the better ones, but as C was somewhat haphazard in it's creation and C++ was meant to be a superset of it, C++ suffers from many of the same problems that plague C. Java is another good option, but in it's endeavour to have a more rigid architecture than C/C++, it has enforced the whole rigid class system to the point of absolute frustration. Functional and scripting languages are quite often much more limited in what they can do, but as a trade off are often much more expressive. There is a reason there are few languages that are powerful and also expressive.

But I tell you what, I for one would be game if this ends up being more than simply a thought, I have designed a simple programming language (for a uP I designed), but it would be interesting to take a shot at a real programming language.

Rusky 13 years, 9 months ago

A lot of the ideas I've been considering are ways to bring the expressiveness of functional languages to a lower level language. For example, Haskell uses type classes for polymorphism rather than class hierarchies with virtual functions. This gives several advantages over C++ and can be implemented just as or more efficiently. However, type classes in Haskell are not applied to traditional object-oriented open inheritance hierarchies. Combining both of these would solve real problems in real projects.

A type class in Haskell is similar to an interface. They are equivalent to the now-dead C++0x concepts and concept maps, but at runtime. A typical type class is Eq:

class Eq a where

(==) :: a -> a -> Bool

(/=) :: a -> a -> Bool

This means that any object of a type in the Eq class can be compared for equality with another object of that type. The cool part is that you don't make types members of classes as part of their definitions, but rather as separate instance declarations:

instance Eq MyType where

a == b = – compare equality

a /= b = !(a == b)

This means you can make any arbitrary type "implement" any arbitrary "interface" without modifying the type. You can combine different libraries yourself, and the instance declarations are only scoped where you put them, so you don't have to modify third party code and you don't have to do Ruby-style monkey patching that can interfere with unrelated systems.

Now, the types in Haskell are closed- in other words, you can't add new ones to the "hierarchies." If you have a parse tree or a type that uses collision testing, it's all declared in one place:

data Node = Name String | Number Double | Binary Op Node Node

Adding new types means messing with the original definition. In C++, you have

class Node { virtual void foo() = 0; }

class Name : public Node { string name; virtual void foo() { /* … */ } }

// add more from wherever you like, even dynamically link them

Now, imagine both of them together. Instead of making a bunch of Node children, you instance them for your type class for code generation, and then in your optimization library have them instance a different class without modifying their definitions. With real multiple dispatch as well, you can completely eliminate the need for the visitor pattern- a two-parameter Visitor type class on the visitor and the visitable types could be instanced, without modifying the AST library, for any kind of operation on the parse trees you like.

ludamad 13 years, 9 months ago

D is kinda cool.

Undeadragons 13 years, 9 months ago

That's quite interesting I must say.

What other features would you include?