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.

2
  • Saying that syntax is just an implementation detail is just plain wrong. Syntax design is a fundamentally important part of designing a language. And many of the points that you do want to see posted may actually involve syntax. Pity. Seemed like an interesting question. Jan 4, 2011 at 18:35
  • What I want to avoid is the flame war. If you can discuss syntax without starting a flame war, go for it. Jan 4, 2011 at 19:15

26 Answers 26

49

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.

17
  • 2
    +1 In fact, the language itself should allow you to use any character for your identifiers. We aren't all English. Jan 4, 2011 at 17:12
  • 13
    @Berin: Actually, even though I am French, I much prefer English programs. The problem is one of communication, if you write programs with Hungarian, Spanish or Portuguese identifiers, don't expect me to ever be able to jump in... in a context of internationalization it's extremely important that developers be able to communicate between themselves, and that implies using a common language for identifiers, comments and documentation. English is the lingua franca of developers. Jan 4, 2011 at 19:27
  • 11
    I'd add that unicode support should be natural when using the language. If possible, it shouldn't take any extra effort to "add it in", it should "just work" (where reasonable).
    – RHSeeger
    Jan 4, 2011 at 19:52
  • 4
    Relatedly, the language should make a fundamental distinction between text (sequence of characters) and binary (sequence of bytes) data. C# gets this right with string and byte[]. As does Python 3.x with str and bytes. C(++) char gets this horribly wrong.
    – dan04
    Jan 7, 2011 at 9:06
  • 1
    @RHSeeger - indeed!!! Even in Python you have to type u'My Unicode Štring'. I wish you could just forget what type of string you're dealing with and friggin write code.
    – orokusaki
    Feb 1, 2011 at 1:33
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.

2
  • 2
    "good date support" is a pretty steep requirement though! what does that even mean? I think dates and times is one of those things where you can't get it allaround good. either you make it simple and wrong, or you make it right and ungodly complicated. it's REALLY hard to hit a good middle ground.
    – sara
    Aug 10, 2016 at 14:28
  • @kai The point is that date support is usually pretty terrible. The old java.util.Date has nearly all possible gotchas and problems. I know only a part of the new java.time.* package, but it's clean, easy to use and AFAICT bug-free. More advanced users might find problems, but it's a huge improvement. +++ The problem seems to be, that it's a complicated problem and the first version is rushed and broken.
    – maaartinus
    Jul 21, 2018 at 21:46
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.

10
  • 4
    That may be true to a certain extent. However, if you never listen to your users you never know the pain you inflict on them when they attempt to use your brain child. Without hearing/feeling that pain you will never come up with the next great idea that solves that problem and others. No man is an island. Pain can be a great motivator for inovation. Jan 4, 2011 at 15:16
  • 5
    @Berin: I don't think the point is that you should never listen to your users, but don't listen to the users who want to use the language for something that it wasn't designed to do. If you designed a language to solve a specific set or problems, then you should cater to the users who also need to solve those problems. However, you do address the extreme and sometimes a language can find a niche in a new domain, so +1.
    – Jeremy
    Jan 4, 2011 at 15:28
  • 2
    @Jeremy, yes, that's exactly what I'm saying, but I think it's uncommon for a language to work well in a domain it wasn't designed for. Jan 4, 2011 at 15:57
  • @dan_waterworth: Successful languages usually work, often well, in domains they weren't designed for. Jan 4, 2011 at 19:08
  • 8
    Instead of "don't listen to users", the advice is better phrased as "don't listen to users you don't have". Jan 4, 2011 at 20:06
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.

1
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.

4
  • 3
    +1. Debugging is one of the places where some languages are better than others--and some IDEs make all the difference between a usable language and one that gets in your way. Jan 4, 2011 at 17:20
  • 2
    I'll add a bit to this and say, where possible, useful stack traces. If there's an error (or uncaught exception or whatever, depending on your language), I want to be able to view the entire call stack that got to it, along with the values of arguments used. Tcl does this exceptionally well.. but, to be fair, everything is a string in Tcl, so you can print the value of everything with relative ease.
    – RHSeeger
    Jan 4, 2011 at 19:54
  • 1
    Not just debugging, but making it hard to write bugs. I was so happy when Java introduced automatic bounds-checking on arrays...but here we are, 15 years later, still making those mistakes in other languages. Jan 5, 2011 at 14:55
  • 3
    Would it not be better to have a language which finds the Bugs at compile time? For example when I use Ada is spend significantly less time in the debugger then when I use C or C++.
    – Martin
    Jan 6, 2011 at 11:59
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. :-)

17
  • 4
    I consider two other things more important, especially on a language design level: "Special cases aren't special enough to break the rules." because a language with a thousand special cases or arcane rules is hard to use, in conjunction with "Although practicality beats purity." because otherwise you drift into the realm of turing tarpits.
    – user7043
    Jan 4, 2011 at 16:49
  • 15
    If explicit is better than implicit then why aren't you required to declare variables? When a simple typo can cause hard-to-debug errors, (as opposed to errors that are caught at compile time or runtime errors that are obvious and easy to debug,) that's a major strike against the language IMO. Jan 4, 2011 at 17:35
  • 4
    @Mason Wheeler: The only reason you have to declare variables in other languages is that you have to declare which type they are. Python is dynamic, so type declaration isn't needed, and therefore declaration isn't needed. I don't see how that has anything to do with implicit/explicit. The types in Python are explicit. So are the variables. After ten years, a typo has never cause a hard to debug error. In fact, they are trivial to debug. Jan 4, 2011 at 20:47
  • 8
    +1 for the list, -1 for the fanboy-ness. Paying attention to all languages that have gained significant success, and attempting to incorporate, or at least analyze the applicability of those elements seems like the more pragmatic approach. Jan 5, 2011 at 16:26
  • 3
    @Lennart: I would say that being able (but not required, see rule 4) to explicitly state function's types is a good thing. It is similar to design by contract. That is the point I want to make. Jan 9, 2011 at 1:55
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.
4
  • 2
    Put in other words, the language should have one overarching design principle, and the language should be consistent with that principle. Comments about language evolution are warranted (I've seen this botched a few times). Jan 4, 2011 at 20:06
  • 1
    Reminds me of my favourite C++ quote ... An octopus made by nailing extra legs onto a dog.
    – ocodo
    Jan 5, 2011 at 22:20
  • 5
    Prove that it can't be done in a library. +1 Dec 1, 2014 at 4:11
  • 2
    I like the library tidbit. It's cool how languages like haskell don't have built-in controlflow stuff like loops, exceptions or continuations. they're just really straightforward to define within the language, keeping the syntax really clean and promoting extensibility and composability over making a bunch of clever language features.
    – sara
    Aug 10, 2016 at 15:15
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.

4
  • Interesting. Good meta programming support can be difficult to get right, but very powerful when it is. I've heard from people who like Lisp that Lisp's implementation is among the best--but they say that about everything in Lisp. Any examples of what you think is meta programming done right? Jan 4, 2011 at 20:02
  • "Metaprogramming done right" has got to be where it is simple to do right (well, for reasonable simple activity) and where the end result feels like a natural part of the language. Jan 4, 2011 at 20:51
  • 1
    Not just modifiable, but decipherable modification. If you've remapped something in the language, I as a reader should be able to quickly figure it out. Annotations or other extrinsic markers could help with this. Jan 5, 2011 at 14:57
  • I think Mata-Lua or Template Haskell do an good job for providing this. (Not as nice as Scheme macro's, but that's what you pay for using more then parens in a language) Jan 7, 2011 at 4:52
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.

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.

11
  • 2
    Bounded integer types ala C, C++, D, Java, C#, etc. have their place for sure. Some types of programming don't care and simply only need the distinction of integer vs. floating point. Even then, perhaps we just need a number type and worry about the integral part of the number later? In short, business programming is less sensitive to the specific integer type than it is to the fact that a number is an integer. When you are implementing a protocol at a low level the rules change drastically. Feb 14, 2011 at 19:52
  • 2
    What I thought where types like in Ada where you can just say type Date_Of_Month is 1 .. 31; and leave decisions like 16 or 32 bit to the optimizer. But more importantly assigning 32 or 0 or -5 to a variable of the type gives you an RANGE_ERROR.
    – Martin
    Feb 15, 2011 at 15:48
  • Ranges work well for things like Date_Of_Month (or Month_Of_Year) where there's an obvious range to use, but many -- probably most -- cases are fuzzy. type Persons_Age is 0..120? What if someone breaks the longevity record? type Year is 0..9999? What if you're an Egyptologist?
    – dan04
    Feb 19, 2011 at 19:00
  • If you are an Egyptologist you oblivious need type Egyptian_Year is -9999 .. 300;. In my experience you can find useful bounds for integers most of the time. In this respect you should consider type Scrolls_Found is array Egyptian_Year of Natural; You can't / shouldn't have an unbounded type as array index. It's just an attack vector for hacker. BTW: Ada allows for range bounds to be calculated at run time.
    – Martin
    Feb 20, 2011 at 9:06
  • 1
    @kai nobody said that this particular feature of type systems must be used everywhere with no exceptions. I'm sure Ada also allows one to use "regular" numeric types. And bounded numeric types are certainly useful for some (rather common) problems. Apr 24, 2017 at 19:08
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)

5
  • Less of a language design issue, though. Sure, you always have to keep an eye on what enters the standard library, but language designers can't enforce naming conventions ;)
    – user7043
    Jan 4, 2011 at 16:46
  • 3
    You can for the standard library.
    – Malfist
    Jan 4, 2011 at 17:05
  • 3
    Don't even mention PHP. Worst commonly used language around. Not designed by a computer scientist just a guy who wanted templates, and steroids were added.
    – Benbob
    Jan 4, 2011 at 19:05
  • @delnan: some languages, like Mercury or Eiffel, impose naming conventions (all capital class names, variables starting with a capital, etc.) and they are enforced by the compiler. Fortran said that variables starting with i, j, k are integer (hence the traditional usage as loop variables in most languages...). And so on. Somehow annoying if you don't like the convention, but good for consistency of source codes, at least.
    – PhiLho
    Feb 24, 2011 at 12:43
  • @PhiLho: That's very limited though. It can't enforce - just one example - consistent, meaningful (to human readers) use of capitalization or underscores (it could try but would risk the sanity of the programmers in the process).
    – user7043
    Feb 24, 2011 at 16:27
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?

2
  • You mean something like ASIS (ISO/IEC 15291:1999 “Ada Semantics Interface Specification”)? ASIS does not cover all you want but quite a lot. I have often wished for something like ASIS for other programming languages. See sigada.org/wg/asiswg for details.
    – Martin
    Jan 6, 2011 at 10:25
  • Some of these things are relatively cheap to do, or come for free from your IDE: code organization, syntax highlighting, code folding, version control, templates/macros. Others require a lot more effort: runtime debugging, static debugging, Smart completion/predictive typing, refactoring, etc. While oft neglected, designing a consistent language is much more difficult when you also have to worry about IDE plugins. Feb 14, 2011 at 19:57
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.

2
  • Another example would be Erlang. A common theme among languages of this sort is a shared nothing approach, where state is essentially passed along with the message. The approach scales well. Jan 4, 2011 at 19:47
  • @Berin: You're right, even though I didn't cited Erlang in the message because I know little of it, it I recall correctly it implements the Actor model. Jan 4, 2011 at 19:50
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.

2
  • JavaDoc, CppDoc, RubyDoc, etc. have been a great asset in understanding the standard libraries, as well as the libraries you create. They aren't all created equal and some are easier to navigate than others. Jan 5, 2011 at 16:40
  • Agreed, The Java API site is an excellent asset. Its great having a standard format for creating API documentation also. The productivity gains from using an IDE with built in support for analyzing JavaDoc (netbeans) is amazing. Although I have a horrible memory so it probably benefits me more than others.
    – toc777
    Mar 31, 2011 at 17:08
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.

8
  • Essentially an efficient way to do bounds checking? That would be pretty cool. Although, I would at least want that to be included for runtime checking as well as compile time checking. When you are pulling information from a database, or from the user interface, you always guarantee the value will be valid. If this were a language feature I would want to use it for these purposes as well. Jan 5, 2011 at 17:52
  • 3
    You ought to use Pascal. You can define a type that covers an arbitrary range of numbers, such as -5..25, which the compiler can verify at compile-time. (As long as you're only assigning constants, of course.) Jan 5, 2011 at 18:17
  • 1
    @Kugel: What else but a compiler feature is assert? And Unit test won't check the code in production. And not checking in production is like taking the live boats off after the maiden voyage. To save fuel and make the ship faster.
    – Martin
    Jan 10, 2011 at 11:44
  • 1
    I would use Ada, except that the platform I'm working on does not have an Ada compiler. It only has a C compiler, so this is all academic anyway. Jan 17, 2011 at 12:48
  • 1
    I already use lots of asserts, but it would be even better to have this and other things as language features. Jan 17, 2011 at 12:49
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.

14
  • 4
    I think the worst example is languages where you say public static void .
    – Joey Adams
    Jan 5, 2011 at 18:30
  • 1
    The Idea is not new and already implement in then form of SmallTalk which has no keywords at all. So you should have used SmallTalk as positive example for your claim. BTW: If you don't know what the IS is for then you have not understand Ada (did you ever program Ada?): IS separates the procedure declaration from the declaration of local variables and also distinguishes an specification from implementation. Of course you would only notice when comparing specification and implementation of a function to see that the IS makes perfect sense and is not a filler at all.
    – Martin
    Jan 6, 2011 at 10:02
  • 1
    Forgot to mention: The SmallTalk syntax also fits the back of a postcard. So it will also fulfils your desire for “small”. Of course most ideas here are already implemented in some language somewhere and most posters here use that languages as positive example instead of making a faulty negative example. I would vote you down if I hat enough reputation. Not because your idea is bad - but for using negative example.
    – Martin
    Jan 6, 2011 at 10:10
  • 7
    Filler words may actually serve a purpose if they help to disambiguate the syntax. For example, I much prefer if x then … to if (x) …. We’ve traded a pair of parentheses for a contextual keyword. This makes sense because the condition x may be a complex expression with its own parentheses. Eliminating the outermost pair can drastically increase readability. An alternative of course is to use a colon here, like in Python. In fact, I believe most such disambiguating fillers could be replaced by colons. Not sure which method I prefer. Jan 7, 2011 at 14:58
  • 3
    @Konrad: If it disambguates the syntax, it's not a filler. The is is a filler because Ada could have allowed procedure Hello begin ... end with no ambiguity.
    – dan04
    Feb 19, 2011 at 19:21
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.

4
  • 2
    How is Haskell's function composition in any way backward? It's a direct translation of (f ∘ g)(x) = f(g(x)).
    – Jon Purdy
    Jan 5, 2011 at 21:52
  • @Jon Purdy: It means you have to write the functions in reverse order of their application. In both forms, g is applied to the argument first, followed by f. If you want to sort a list, group it, and get the first item of those lists, you would write (map head . group . sort) list or map head $ group $ sort list or map head (group (sort list)). In all cases, you end up writing the operations backwards. By the way, importing Control.Arrow lets you say (sort >>> group >>> map head) list , but the >>> operator looks rather awkward and verbose to me.
    – Joey Adams
    Jan 6, 2011 at 0:11
  • 2
    I dunno, I still think the right-to-left one makes sense. (map head . group . sort) list reads as "the first item of each group in a sort of list", which is quite natural—and, to my ear, more functional than (sort >>> group >>> map head) list, which reads rather imperatively and backwardly as "sort then group then take the first item of each group...list".
    – Jon Purdy
    Feb 15, 2011 at 6:25
  • @JoeyAdams - the >>> operator looks rather awkward and verbose - A few more recent functional languages have started using |> as a left-to-right chaining operator, which is perhaps a little easier on the eyes...
    – Jules
    Jul 21, 2018 at 22:28
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...)

4
  • I'm with you 100% for a complete specification. Multi-paradigm and consistency will definitely be a balancing act. You can specify a set of behaviors for a dynamic paradigm as a subset of the behaviors for static checking--but I think these two approaches can lend themselves to very different programming styles. They really aught to be separate languages at that point. Perhaps a pair of consistent languages with 100% compatibility would be what you are looking for? Feb 14, 2011 at 19:41
  • Languages like Scala (and perhaps Haskell? I don't know it enough) have strong static type system and terseness, thanks to type inference and implicits.
    – PhiLho
    Feb 24, 2011 at 12:55
  • 2
    Architecture-dependent features are fine when a language lets a programmer specify what is or is not important. What makes C horrible is that there's no way to declare "numeric type which wraps modulo 65536"; even if a platform implements uint16_t, the standard requires that some implementations regard the difference between two uint16_t values as signed, and that others regard the difference as unsigned; it provides no way for the programmer to specify which behavior is desired.
    – supercat
    Oct 23, 2014 at 1:46
  • I disagree for multiparadigm; that leaves way too much wiggle room for coding style battles. Library A is written with a bunch of dynamic paradigms. Library B is written with a bunch of static paradigms. Well, now Library A needs to talk to Library B; where's the middle ground? If you have to write glue between two pieces of code in the same language, the language is inherently flawed IMO. Dec 1, 2014 at 5:21
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.

2
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)

6
  • Ruby sort of has "special forms" for looping, at least in the sense that iterable objects usually have a method like each that takes a block of code as an argument. (Ruby also has for and while loops, but no self-respecting Ruby programmer actually uses them.)
    – mipadi
    Jan 5, 2011 at 17:54
  • @mipadi: I am a big fan of Ruby blocks and the associated idioms.
    – snakehiss
    Jan 6, 2011 at 0:49
  • perhaps they think - You'll shoot your eye out. :) My guess it was the association of ye all powerful "Python" and "no good reason why". Nevertheless, metaprogramming is a valid language design issue that is often neglected. It's for that reason that I'll upvote this. Jan 6, 2011 at 15:30
  • @Berin: I actually use, and am a fan of Python which makes it more amusing.
    – snakehiss
    Jan 6, 2011 at 17:26
  • One type of loop would make flow of code obscure. For instance, how would a do..while loop look if there was one type of loop that had the evaluation at the top? It wouldn't look like a do..while loop at all. Dec 1, 2014 at 5:23
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.

3
  • 8
    But it can be a standard library feature just fine. Jan 4, 2011 at 20:53
  • @Donal: I never said otherwise (or at least didn't thought so), the question is open to both language and library features. My point is just that if you receive a language package and there is no network capability in there, you'll fill the pain sooner rather than later :) Jan 5, 2011 at 7:40
  • 3
    The standard library is really part of the language experience, and it should be treated with the same care and respect. I also agree with this requirement for a standard library. Jan 5, 2011 at 15:43
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.

1
  • Orthogonal means each feature does something different. Look at tools like grep or awk. They do one thing, well. You then hook them up in different orders to do anything you need. Jan 7, 2011 at 5:05
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.
7
  • 1
    Sorry, but I've gotta give you a -1 for being completely wrong on this. Terseness helps to write code faster, but it most definitely does not make code more readable, beyond a certain minimum. A certain level of verbosity makes code much easier to read, because those extra words and symbols mean something and impart meaningful information to the programmer, especially if it was originally written by someone else and you don't have the advantage of already having a mental model of it in your head. Jan 4, 2011 at 18:40
  • For me, clean code is readable code. I also said the smallest: having ":" instead of "=>" in PHP arrays, or having "." instead of "->", would certainly be an improvement (and I enjoy PHP already). Jan 4, 2011 at 18:47
  • 4
    @Mason: I, and many good technical writers (e.g. William Zinsser), disagree. Verbosity is the enemy of readability, not terseness. Jan 4, 2011 at 20:12
  • 2
    I go for a form of terseness which is defined in terms of symbols. I'm quite happy with multi-character symbols though, so long as they are things that the reader naturally treats as a single symbol (e.g., a word is a symbol). Jan 4, 2011 at 20:56
  • 1
    Your first point directly conflicts with your latter two. Dec 1, 2014 at 5:25
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#
1
  • 2
    This is a huge oversimplification. A much better example would be the difference between C and Objective-C.
    – Jon Purdy
    Feb 15, 2011 at 6:18
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.

9
  • 3
    Computers are already powerful enough to do this. It's just not practical, as you are going to need to get down into the code for some reason or another.
    – Jeremy
    Jan 4, 2011 at 14:48
  • 2
    It's still a language of sorts. There have been more than one attempt to make this a reality. UML tools will generate a certain amount of code, but when the model is sufficiently detailed to produce a working product it is no longer useable to understand to code. I believe that there was something on the Unix environment for graphical wiring of applications, but it required a lot of configuration to get it correct. Workflow engines use this metaphore to allow non-programmers to design the workflow. Jan 4, 2011 at 15:02
  • 1
    In short, while I seriously doubt the usefulness of this approach in general terms, there are specific applications where it is currently used and works well for that application. Re: your points... 1. Computers have the computational power, the technical side is not the problem. 2. The problem is providing a visual language that is expressive enough to do the work in the general sense without getting lost in the details. Outside of niche applications, text seems to be a much more compact representation of a program. I did upvote because it is applicable to the question posed. Jan 4, 2011 at 15:04
  • 1
    @Amir: Then please explain why computers need to be more powerful in order for "graphical programming" to drive software development?
    – Jeremy
    Jan 4, 2011 at 15:09
  • 7
    @Amir: You're confounding a technical limitation with a more fundamental one. The reason we don't have many graphical computer languages is that we don't know how to do them well (and don't know if they can be done well). I'm aware of LabView, and have heard enough bitching about doing complicated things in it, or changing simple things. Nor do we need more powerful computers to design such a language, so go ahead and try to sketch some sample programs in such a hypothetical language. Jan 4, 2011 at 15:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.