39

The purpose of this question is not to assemble a laundry list of programming language features that you can't live without, or wish was in your main language of choice. The purpose of this question is to bring to light corners of languge design most language designers might not think about. So, instead of thinking about language feature X, think a little more philisophically.

One of my biases, and perhaps it might be controversial, is that the softer side of engineering--the whys and what fors--are many times more important than the more concrete side. For example, Ruby was designed with a stated goal of improving developer happiness. While your opinions may be mixed on whether it delivered or not, the fact that was a goal means that some of the choices in language design were influenced by that philosophy.

Please do not post:

  • Syntax flame wars. Let's face it, we have our preferences, and syntax is important as it pertains to language design. I just want to avoid epic battles of the nature of emacs vs. VI (which a great number of people these days know nothing about).
  • "Any language that doesn't have feature X doesn't deserve to exist" type comments. There is at least one reason for all programming languages to exist--good or bad.

Please do post:

  • Philisophical ideas that language designers seem to miss.
  • Technical concepts that seem to be poorly implemented more often than not. Please do provide an example of the pain it causes and if you have any ideas of how you would prefer it to function.
  • Things you wish were in the platform's common library but seldom are. One the same token, things that usually are in a common library that you wish were not.
  • Conceptual features such as built in test/assertion/contract/error handling support that you wish all programming languages would implement properly--and define properly.

My hope is that this will be a fun and stimulating topic.

Edit: Clarified what I mean by Syntax Flame Wars. I'm not trying to avoid all discussion of syntax, particularly because syntax is a fundamental part of program language design.

sdg
  • 1,872

26 Answers26

48

Unicode Support by default

This day and age, programs are being developed to be used internationally, or under the assumption that they might be used internationally. They must provide support for their character sets or render programs written in that language useless.

Malfist
  • 3,661
25

I have a couple:

  • Generics/templates. For example, Java generics are powerful, but not necessarily flexible. Also, because they use type erasure, I have seen problems implementing them abstractly, especially in interfaces. And the compiler shouldn't warn when a non-specific generic is used (Like Hashmap instead of Hashmap<String, int>). I think they could be improved significantly. Good templating is very useful, but often neglected.

  • Good Date support in the standard library. I mean being able to add and subtract dates, hours, and minutes, and not having to deal with the number of milliseconds since January 1, 1970.

Spoike
  • 14,771
Michael K
  • 15,659
24

Some of the best languages were designed by people who wanted to make a language for themselves.

So I think language designers should pay less attention to their users. You can't please everyone, neither should you attempt to.

24

Please make your language analyzable/auditable for computer security people.

Security folks need to be able to find vulnerabilities in a program before it ships. Ideally, we're called in early and can comment on the codebase as it develops, but often not.

When a new version of the language or core libraries comes out, things that were previously safe may no longer be:

  1. libraries may become more powerful : e.g. URL library now supports javascript:
  2. there may be new ways to convert strings or bytes into code : e.g. eval or deserialization libraries
  3. language reflection techniques may become more powerful : e.g. exposing local variables

Any of these changes can increase the amount of abusable authority a program has, but since the amount of authority the program uses (when dealing with non-malicious clients) hasn't changed, security folk are hard pressed to figure that out without an intensive re-audit.

So, please think about us when designing and versioning the language. Below are a few tips:

Define a few primitives that a program can be decomposed into.

HTML5 is particularly bad this way. They have obviously put a lot of thought into security and have some very smart people, but instead of specifying new program elements like <video> in terms of old ones, or creating a common abstraction that new <video> and old <img> both can be specified in terms of, <video> is yet another one-off program element with its own security consequences.

Make your language amenable to static analysis (even if not statically typed).

Security folk often use static analysis to find patterns, and to try and rule out parts of a program so that they can focus on the really tricky bits.

It should be obvious which identifiers are local variables and which are not.

E.g., don't make the same mistake as old versions of JavaScript which made it impossible to tell whether x is a local variable reference in the below (according to a literal reading of an old version of the spec):

if (Math.random() > 0.5) {
  Object.prototype.x = 0;
}

function f() {
  var x = 1;
  (function () {
    alert(x);  // Might alert 0, might alert 1.
  })();
}

Allow for decomposable security

A lot of secure systems are designed around a secure kernel that preserves the security properties, so that security folk can focus their efforts on analyzing a small amount of code and freeing most programmers from having to deal with {annoying,pedantic,paranoid} security folk.

It should be possible to write such a kernel in your language. If one of the security properties of your language, is that only a certain subset of URLs will ever be fetched, can the kernel writers do something to channel all URL fetching through their code? Or can static build checks (like looking at imports) serve the same function.

Some languages like Newspeak use an object capabilities model. That's awesome and a great way to get decomposable security.

But if you can't do that, making the module graph a statically analyzable artifact can get you quite a bit of benefit. If I can prove that a module can't reach the file I/O module (except by calling code in a module in the TCB), then I can rule out whole classes of problems from that module.

Limit the authority of embedded scripting languages

A lot of useful systems are organized as a static core that kicks off a lot of code written in dynamic (even functional) languages.

And embedding scripting languages can make a system much more extensible.

But a scripting language shouldn't have the full authority of the VM.

If you choose to allow embedded scripting languages, make it easy for the invoker to limit what they can do. An object-capabilities model (see comment on Newspeak above) is very appropriate here ; so when evaluating code in a scripting language, the caller should pass in the code to execute and all the global variables for that code.

Treat eval as a language embedding itself as a scripting language

If your language can invoke its own compiler to turn a string into code, then allow it to be sandboxed the same as you would any embedded scripting language.

Use a simple concurrency model

We security folks don't like to have to worry about race conditions when trying to figure out if a security property is maintained.

Please consider alternatives to threading before settling on threads as an almost impossible-to-secure default option.

One simple one is event loop concurrency like that found in E, Verilog, and JavaScript.

Don't encourage quoting confusion

Some languages are glue languages, and they end up dealing with strings in a lot of different languages.

For example, JavaScript often composes strings of HTML, CSS, XML, JSON, and even JavaScript. It is very hard for programmers to remember to properly encode plain text strings when combining them to make strings in other languages, so JS programs, unsurprisingly, have all kinds of quoting confusion problems : XSS being the worst.

If you want to include string composition features try to reduce the programmer's security burden. DSLs, hygienic macros, and embedded templating languages can be a great way of doing this by moving the burden for properly escaping onto library or language developers and away from the end-developer.

Mike Samuel
  • 1,868
17

Only 5-10% of time is spent actually writing code. Language designers should pay attention to the difficulties of actually making software work, which means fixing errors and bugs.

That means there should be from the get go a good debugger. Not some tool with arcane syntax and key commands that is only slightly better than tons of print statements.

whatsisname
  • 27,703
12

I think they should pay attention to Python, who does more things right than any other language I have encountered (and that even if you dislike some of the features). That doesn't mean that they should emulate Python, but it's important to know what Python did right, even if you don't want to make a language like Python at all.

As for philosophical ideas that are relevant there, these are the most important ones from the Zen of Python:

  • Explicit is better than implicit.
  • Readability counts.
  • Special cases aren't special enough to break the rules.
  • Although practicality beats purity.
  • There should be one-- and preferably only one --obvious way to do it.
  • If the implementation is hard to explain, it's a bad idea.
  • Namespaces are one honking great idea -- let's do more of those!

I think a language that follows these rules must necessarily be quite OK, but I know only of one that does this, and that's Python. For all the similarities with for example Ruby in implementation, Ruby misses out on things like readability and invites you to do code golf, which is fun, but not useful in a professional setting.

The only technical feature I miss in Python is an "until" statement (like while, but not testing the expression the first time). Then there are a lot of things in both Python and other languages standard libraries that could be improved, but that's not strictly languages, so that's a different question. :-)

11

The most important thing is that your language needs to have a "style". For example, I would call C a pointer-based systems programming language. I'd call Erlang a highly concurrent functional programming language. Some other languages (like C++ and arguably Java) are what Allan Kay called "agglutinative" languages: Frankenstein languages consisted of a bunch of features tacked together.

Next most important is that changes to the language itself should be a last resort. Even the most benign-sounding can become complex when combined with the other features of the language. I would say that to put a new feature in a language, you need to:

  1. Prove that it is genuinely necessary.
  2. Prove that it can't be done in a library.
  3. Prove that it belongs in the language.
Jason Baker
  • 9,653
11

The ability to modify the language to suit your needs is a big one for me. For Lisp that's done with macros, for Tcl with uplevel. To a lesser extent, Ruby uses lambdas and the like. I just want the ability to add new control structures that suit the problem rather than molding my problems around the control structures available. As a simple example, the "do .. until" construct that exists in some languages but not other is a cleaner way to handle some cases than "while", being able to add new structures to meet other cases is extremely useful.

In the more general sense, this is metaprogramming... but I mostly use it for building new control structures.

RHSeeger
  • 221
10

Thanks for a great question. You're getting some pretty good answers.

Not to glaze over your eyes, but I look at a programmer as an information channel. Ideas/concepts/requirements go in one end, and code comes out the other.

If you take a set of requirements (no matter how they are stated) and the set of code on an enormous whiteboard, and draw lines mapping each requirement to the code that implements it, the complexity of that graph would depend on how well the code expresses the requirements. Ideally, it should be pretty direct and one-to-one, but that's hard to get in practice.

I measure the domain-specificity of a language as the extent to which it simplifies that graph. That is an extremely desirable property, and it can be approached in any number of ways, by anything from just defining the right classes/routines (nouns/verbs), to macros, to writing your own parser and interpreter/compiler.

Let me just give an example of what I mean. For the problem of creating flexible dialog user interfaces, this technique eliminates having to write event-handlers, data-moving, most of the stuff typically done in UIs. It also results in source code reduction of about an order of magnitude. The meta-language is really just a few routines and macros in C/C++/Lisp, and I've also done it in languages without macros.

If implementing a requirement can be done with 5 point edits to code, or with 10, doing it with 5 is not only less code, but fewer chances to miss a step and put in a bug. So the more domain-specific a language is, the smaller, more maintainable, and more bug-free is the code. I think we need to know how to drive toward that. It does not mean the code is more readable, unless the reader has invested in the learning curve to understand the technique.

Mike Dunlavey
  • 12,905
9

Bounded and distinct Integers types like in Pascal and Ada. Honestly: how often do you need the full range of any integer? I think there is a lot to be improved in primitive types to better represent the real world.

Martin
  • 101
  • 3
8

There are features that make programming languages easy to use once you learn them, and there are features that make them easy to learn to use. Since users of a language ideally have a long-term relationship with it, optimizing for ease of use is better than optimizing for ease of learning. Don't make things more difficult than necessary, but don't sacrifice expressiveness (being able to write a little code that does a lot) for readability to those who aren't familiar with the language. On the other hand, the language shouldn't read like line noise to people who've been working with it for years; that wouldn't be easy to use or to learn.

8

Naming Conventions (I'm looking at you PHP)

Malfist
  • 3,661
7

First-class integration with development environments.

Nowadays, coding is done in a rich environment. For HTML/CSS/JS, we have Firebug and other interactive tools. For Java, Eclipse and IDEA and other true IDEs. And so forth. There is an ecology of tools, starting with the editor but not ending there:

  • Organization of code within and across files
  • Smart highlighting
  • Smart completion/predictive typing
  • Static debugging (flagging syntax, semantic, and stylistic errors)
  • Creation and use of templates and macros
  • Version control (versioning, merging, branching, ...)
  • Distributed development with multiple authors (comments, inline doc, annotations, ...)
  • Run-time debugging (stack traces, stepping, watches, ...)
  • Interactive "live" debugging (like Firebug--editing behavior of a live system)
  • ...I don't even know what's next.

Languages should be built to provide support for these activities. Some progress has been made--annotations in Java to help other developers understand the intent of the code, for example.

But mostly it's hacked up stuff, like using $Id$ in a comment so that CVS-controlled source can contain a version number. Why can't I do something like this from the language itself?

Alex Feinman
  • 5,802
  • 2
  • 29
  • 48
6

Distributed Computation

The free lunch is over. Today one needs programs that run on multiple cores / multiple processors (and on special circumstances multiple computers).

Unfortunately writing multi-threaded code is hard conceptually, so there is really no need to add the language as a barrier.

C++0x use of future is certainly interesting, for all that it's brought as a library and does not free you from actual synchronization issues (you know, those that are just so easy to solve...)

I really like Go's approach to the problem: multithreading is built-in, and the approach taken (channels and goroutines) sets a much easier mindset than the traditional semaphore / mutex / lock approaches. It's still easy to access a non-synchronized structure concurrently though (Go has pointers) or to deadlock (cycle of wait on channels...)

I think that languages favoring immutability of data, like functional languages, may have the right of it (I do like experience there though).

Also, the Actor model may be our next target. It was meant for distributed computing too.

Matthieu M.
  • 15,214
6

Call me crazy but one of the most important language features to me is the availability of a good online reference, along with examples. I know that I can find good search results for any language, but I really like the MSDN and Java APIs site. They make programming much easier for a person who does not have much experience in the specific language.

apoorv020
  • 656
  • 5
  • 11
6

More ability to help the compiler check your code.

Being an embedded systems programmer, I always use C. But I always wish I had more/better ways to tell the compiler what I expect from my code so it can verify it.

E.G. I can have a function

f(int x)

but I would prefer

f(int range[-5..25] x)

E.G. I would like to be able to write assertions about functions using some kind of higher level functional language like Lisp or Haskell. These wouldn't be compiled into code, but could be used for static or dynamic analysis.

5

Small syntax with as few keywords as possible because verbose syntax is hard to learn and does not help readability.

The worst example is Ada:

procedure Hello is
begin
  Put_Line("Hello World!");
end Hello;

Filler words like is,as,.. don't make sense for programming languages.

Brainlag
  • 165
4

I would like to see more learning languages. Not only languages for absolute beginners with holier-than-thou restrictions like requiring a space between every token, but languages for people who already know programming and want to learn new concepts or get better at programming in general.

To me, Haskell is a great example of what I mean by a "learning language" (though it's also grown in popularity and general utility over the years). By abandoning the familiar C syntax and having backwards function composition operators (e.g. (+2) . (*3) is a function which multiplies by 3, then adds 2), Haskell taught me to write shorter functions. Its ruthless type checker helped me learn the language faster and improved my ability to think logically about code. Both of these benefits have spilled over to other languages, even assembly.

The goals of learning languages and those of general-purpose languages are often in conflict. A learning language should be challenging and rewarding to learn, and should enforce a particular style, even if that style is not the best for many applications. A general purpose language should be good for getting stuff done, and use of abstractions should be carefully measured and "make sense". For example, when fixing a website, learning about monads would be the last thing on a programmer's mind. On the other side of the coin, when someone is learning to program, they shouldn't have to wade through "public static void" nonsense if they haven't even learned about functions yet.

If you're a language designer, please make up your mind whether your language is a learning language or an applied language. This will determine to what extent you will want to employ purity in your design.

Joey Adams
  • 5,615
4

Since we are in 2011,

  • an absolutely complete specification. no archtitecture-dependend holes like in C
  • multithreading support; not just synchronisation features (locks), but language features that make multithreading as easy as writing a loop:

    all(o in myCollection) { o.someMethod() }

  • multi-paradigm; let me, the programmer, decide if I want the compile-time safety of a static language or the terseness of a dynamic language, on a case-by-case base; give me object oriented features, functional features, etc.

  • consistency (I know it's asking a bit much for both consistency and multi-paradigm...)

user281377
  • 28,434
3

Facilitate metaprogramming.

limit special forms

In Python there is no good reason why print it not a builtin function. It looks and acts like a function except for not wanting anything to do with parens.

Do we really need for, foreach, while and the like each as their own special form. How about one looping construct and some default macros to provide the syntactic sugar of the variant looping forms.

meta-programming for special forms

form['if'](test-fn, body-fn)

3

Lightweight Processes

I would like to have Lightweight Processes as in Erlang. It's mainly a problem for the runtime. This is missing in JVM and .NET CLR. LWP helps for creating massively concurrent software. Ideally there shouldn't be more expensive to create an process as it is to create an object in a language. I would like to create millions of processes in my applications.

It's implemented as a thread-pool with preemtive scheduling, so a single task doesn't block the other task, and the tasks can be scheduled on any cpu-core available.

Support for tail-recursion

I would like to have support for tail-recursion. This may also be a problem for the runtime environment. E.g. JVM doesn't have support for tail-recursion.

Easy distributed programming

I would like to have support for send (!) and receive primitives to parts of the application running on other machines on the same netword as in Erlang. This makes it easy to build scalable applications e.g. distributed datastores. Added to that serialization built-in in the language is also very helpful as in erlang. And not as in Java very I have to do it manually.

Jonas
  • 14,887
  • 10
  • 70
  • 103
2

Network capabilities

A language that ships without some network support is pretty lame in today's world.

Most real world applications need to communicate over some kind of network:

  • automatic update
  • database access
  • webservices

It's also a cornerstone of distributed/cloud computing support of course.

Matthieu M.
  • 15,214
1

I like a programming language that is easy to learn, and easy to combine to create new things.

For instance, while is attractive to have a lot of ways to write the something, I think it is better to have only one or two ways to write it. That way the program is easier to maintain.

A language whose concepts can apply across all the elements is very helpful ( I think this is called orthogonality ) So, the next time you face a new language feature, you can deduce how to use it.

I understand sometimes the language syntax has to get in the way to perform better in the compilation/interpretation phase, but sometimes I feel the language designer defer this work to the developer. For instance, multiline strings in Java or Javascript.

Finally, the language syntax is its user interface, and as such, it should be clear, concise, intuitive, easy to use, and should respect your habits.

OscarRyz
  • 1,665
  • 3
  • 15
  • 26
1
  • Readability: The less/smallest the symbols used in the grammar, the cleaner & the better.
  • Object Oriented types: Methods, not functions.
  • Understandability: Built-in fluent interfaces, comprehensive and short names for library classes/interfaces and the sorts.
dukeofgaming
  • 14,023
  • 6
  • 52
  • 77
1

Adding a feature to an existing programming language. So, new language B is old language A plus feature X.

Existing examples:

  1. C adding classes => C++
  2. Java adding some stuff => C#
Michael K
  • 15,659
umlcat
  • 2,206
0

When it comes to technology/platform/language/database etc. most of the times it comes down to performance. In future many todays software may be designed using a graphical language since we have more computational powerful.

I hope for the day when we have computational power and a language where you design your application and you don’t have to worry about language details.

Update: I send a link to such language LabView

Update: I should explain more what I mean by “computational powerful”. The performance of compiled software may not be as powerful as compiled software based on syntax language. I’m thinking of graphical programming as a higher level of programming and there may be more overhead. Today’s computers can and do easily run graphical programming languages.

Amir Rezaei
  • 11,068