Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

KISS ("keep it simple, stupid" or "keep it simple stupid", see e.g. here) is an important principle in software development, even though it apparently originated in engineering. Citing from the wikipedia article:

The principle is best exemplified by the story of Johnson handing a team of design engineers a handful of tools, with the challenge that the jet aircraft they were designing must be repairable by an average mechanic in the field under combat conditions with only these tools. Hence, the 'stupid' refers to the relationship between the way things break and the sophistication available to fix them.

If I wanted to apply this to the field of software development I would replace "jet aircraft" with "piece of software", "average mechanic" with "average developer" and "under combat conditions" with "under the expected software development / maintenance conditions" (deadlines, time constraints, meetings / interruptions, available tools, and so on).

So it is a commonly accepted idea that one should try to keep a piece of software simple (or simple stupid, in case you omit the comma) so that it easy to work on it later.

But can the KISS principle be applied also to programming language design? Do you know of any programming languages that have been designed specifically with this principle in mind, i.e. to "allow an average programmer under average working conditions to write and maintain as much code as possible with the least cognitive effort"?

If you cite any specific language it would be great if you could add a link to some document in which this intent is clearly expressed by the language designers. In any case, I would be interested to learn about the designers' (documented) intentions rather than your personal opinion about a particular programming language.

share|improve this question
4  
Have you explored the Basic family of languages (or at least, the original intent behind them)? –  MichaelT Dec 4 '12 at 22:33
4  
BASIC and Pascal...both designed as instructional languages. –  Mike Brown Dec 4 '12 at 22:38
7  
Scheme(r) was used as a teaching language for years (decades?) and was developed by simplifying LISP and Algol (and may be more). The book SICP takes very less time to teach the language itself. Also, DSLs come to the mind. –  vpit3833 Dec 4 '12 at 23:03
3  
@Giorgio have a look at Haskell. It has very and I mean very little in-built bits. Most operators are functions that are in the main library, but not necessary to the language itself, it has gone to great lengths to remove all unnecessary pieces –  Jimmy Hoffa Dec 4 '12 at 23:14
1  
@Andres F: It did not misquote it, both versions are used. –  Giorgio Dec 5 '12 at 13:34

11 Answers 11

A major key to maintaining "simplicity" is to recognize when complexity will be necessary, and have the parts of the system that can best deal with it, do so. Having a single kind of object reference which makes no distinction between immutable values, mutable values, and entities, makes Java "simple", doesn't eliminate the need to distinguish between values and entities; it merely deprives programmers of tools to help them do so.

More generally, if one is trying to have a programming language or framework feature support multiple usage cases, one should ensure that there won't be any situations where different behaviors would be appropriate in different usage cases, but the compiler would be unable to tell them apart. Adding more types to a language or framework may seem like a complication, but in many cases it may actually make things easier.

Consider, for example, the mess of rules surrounding signed and unsigned types in C. The complexity of these rules stems from the fact that some code uses unsigned integer types to represent numbers, while other code uses them to represent members of a wrapping algebraic ring (specifically, the set of integers congruent mod 2ⁿ). The type conversion rules behave in ways which are sometimes appropriate to one usage, and sometimes in ways appropriate to the other. Having separate wrapping and non-wrapping types would double the number of integer types, but could simplify the rules associated with them:

  • Any non-ring integer type of any size may be assigned to a ring of any size; a ring may be assigned only to a ring of equal or smaller size.

  • Operations other than relational operators involving a non-ring integer and a ring will implicitly convert the integer to the ring type.

  • Rings may be explicitly cast to numbers or to larger rings; the value of an unsigned ring is the smallest non-negative integer which, when added to the ring's zero, would yield the ring value. The value of a signed ring is the smallest-magnitude integer which, when added to the ring's zero, would yield the ring value, with the negative value being preferred in case of a tie.

  • Except as mentioned above, rings are limited to operations with rings of the same size or smaller.

  • Operations on non-ring integers of different types should upcast the numbers to a type that can accommodate all values of either operand, or should be rejected by the compiler if no suitable type exists

Defining ring types would seem to double the number of integer types, but would greatly simplify the writing of portable code. Using the same unsigned types for numbers and rings reduces the number of types, but leads to complicated rules which make it almost impossible to write efficient portable code.

share|improve this answer

Now, KISS approach to programming languages is a funny notion, at least if you consider programming languages to be an abstraction layer to a CPU's instruction set, etc. If you do not define "KISS" more closely. I am just saying here, that an oxcart is KISS applied to a car to its fullest.

Now another interpretation of KISS could be something like "smartly done without needless ornaments and not overly complicated". Especially one could argue, that there should not be too many specific cases for similar things, etc. Usually math is quite good at boiling down stuff to its essence, and - o wonder - mathematicians have spent some time thinking about programming and computers as well.

For programming, 2 quite famous abstract models exist:

  • One is the turing machine which defines a machine and a simple instructional model that is able to compute everything a computer could do.
  • The other one is the Lambda-Calculus by Church et. al. that is equivalent in power

Fun thing is: While the turing machine is quite simple in its layout, it is not a system that is easy to handle and I do not think it qualifies for "smart KISS". But Lambda Calculus has more to do with programming languages that we know -- and with Lisp and Scheme pioneering features of the lambda calculus it has made its way into a lot of languages.

Lisp and Scheme are REALLY simple, at least syntax wise. Syntax is a major problem with programming languages (which is probably why they are reinvented all the time). In the case of C++ it is almost unhandable for the human brain to predict how some source lines are interpreted by the compiler.)

Lisps are reducing the syntactical complexity altogether by introducing one common form for commands:

(command param1 param2 ...)

This can be a method call, such as

(max 1 2 3 4)

as well as a if branch, loop etc.

(if (< 1 2) 
    (write 4)
    (write 5))

(all code here is pseudo-Lisp/Dialect agnostic)

The form

(command param1 param2 ...)

can also be interpreted as a list

(item1 item2 item3)

And that is the basis for Lisps simplicity and beauty. Because nested lists (like in the if statement example) constitute trees and those can be easily understood both by the machine and by the human in front of the machine.

Another feature of Lisps are macros I won't go into the dirty detail here, but since there is no syntactic difference between normal function calls and "Syntax (e.g.g for loops, variable declaration, etc., everything the parser has to handle in other programming languages) you can create your own syntax. Macros are in essence Manipulations of the Tree that constitutes your program.

I think Lisp has a KISS to programming. That you can manipulate syntax by using macros has lead to a phenomenon that Lisp has evolved quite dynamically. Need a new Language feature like - lets say object orientation - just write a OOP system with macros!

While C was extended roundabout 2 times with OOP features (C++, Obj. C) Lisp was extended multiple times, in the end there was a winner.

That is another quirk about Lisp, it evolves (see Clojure and Clojurescript for interesting new Mutation of lisp).

For its KISS properties Lisps is favored as teaching languages by some. Like Fogus outlines in his blueprint of an educational language (http://blog.fogus.me/2013/01/21/enfield-a-programming-language-designed-for-pedagogy/ )

To start, I’m strong believer that when learning new, and at times complex topics it’s outright detrimental to overload students with frivolous syntax rules. Therefore, Enfield is designed with minimal syntax rules and what’s more minimal than a Lisp like syntax.
share|improve this answer
    
OP defines KISS for the context of this question pretty clearly, "allow an average programmer under average working conditions to write and maintain as much code as possible with the least cognitive effort". OP also mentions "interested to learn about the designers' (documented) intentions rather than your personal opinion about a particular programming language" –  gnat Mar 22 '13 at 7:59

When I think of minimialism, I think of Lisp and Go. With Lisp, all you have are functions and lists, which is about as simple as you can get (well, there's a little more, but whatever). However, I think the Go case is more interesting.

Go was designed to be simple (it's a decent read). The term they use is "feature orthogonality", which means that any feature should only be added if it provides something truly unique. This seems to stem with the authors' (Russ Cox and Rob Pike come to mind) involvement with Plan9, which was a reimagination of UNIX with simplicity in mind. (If you're interested in minimal design, Rob Pike's paper on a simple windowing system is a good read.)

Here's some simple examples of the syntax:

Only one looping construct

A loop can look like one of the following:

Infinite loop

for {
}

While loop

for <conditional> {
}

Traditional for loop

for i := 0; i < 10; i++ {
}

Foreach loop

// works for maps or arrays
for k, v := range arr {
}

Multi-purpose switch

switch {
    // cases must be evaluate to a boolean
}

switch <value> {
}

switch t := <value>; t {
    // can use t inside
}

Multiple return

return val1, val2, ...
  • Removes the need for throw (pass the error as last return value)
  • Removes the need for out parameters
  • Removes the need for tuples

Interfaces

type X interface {
    DoSomething()
    String() string
}
  • Solves similar problems as generics
  • Allows abstraction

Embedding

type A struct {
    Thing string
}

type B struct {
    A // embeds A in B, so B.Thing refers to A.Thing
}
  • Solves same problem as inheritance
  • Obviates need for classes

Channels

Can be used to implement semaphores

var c = make(chan bool, 1)
c<-true // semaphore lock
<-c // semaphore free

Used for message passing between threads

func produce(c chan<- bool) {
    for {
        c <- true
    }
}
func consume(c <-chan bool) {
    for {
        <-c
    }
}

var c = make(chan bool)
go produce(c)
go consume(c)

Can be used to handle asynchronous events

func async() chan bool {
    var c = make(chan bool)
    go doSomethingAsync(c)
    return c
}

// wait for long async process to finish
c := async()
select {
    case _ = <-c:
}

Conclusion

I'm not going to go into every part of the syntax, but hopefully you can see what minimalism can do. The language is intriguing not because it adds a ton of new features, but because it uses the best features from other languages without anything extra.

There's usually one "best" way of solving a problem. For example, on the mailing list, a lot of users complain about not having generics. After discussion, they realize that everything they want to do can be done with interfaces. Read up on effective go for examples on idiomatic syntax.

The benefit of KISS languages is it's possible to write idiomatic code, because code style is restricted by the language. For example, in Go, you cannot write something like this:

if <condition>
    statement;

You have to use curly-braces:

if <condition> {
    statement;
}

There are many other examples of this in the syntax, which makes reading other peoples code easier.

Benefits of KISS language over featureful languages:

  • easier to understand others' code
  • easier to grok the entire language (C++ is notorious for being hard to understand)
  • focus on algorithm, not the syntax
share|improve this answer
2  
In my humble opinion, the syntax of the traditional for loop is not that KISS. Of course it is familiar to every C-like programmer, but I remember the first time I learned this: I was very confused. BASIC is more KISS: for i=1 to 10, or python: for item in group –  mouviciel Mar 22 '13 at 8:16
1  
@mouviciel - I hardly ever use the traditional for loop. The problem with for i = 1 to 10 is whether i will ever be 10. This can be language dependant (bash includes 10, python doesn't). The traditional for loop is universal. –  tjameson Mar 22 '13 at 8:22
    
+1, especially for the summary about the benefits of minimalism. –  Giorgio Mar 22 '13 at 14:48

Hm... this is actually a tough question to answer 'positively', because when I think of simplicity in programming language design (and what's 'easier' to work with), I immediately think of:

  1. "Readability" of code - how well the language encapsulates objects, methods, etc.
  2. The consistency of the language APIs and interfaces.

There are a number of languages that do these things well - but what pops into my head is a language that doesn't do things well 'as a programming language': PHP.

[Disclaimer - I've written PHP and PHP is still my 'go to language' for simple web projects. This is a criticism of love...]

First, PHP does well for the environment that it typically runs in - web servers. It's easy to set up, easy to maintain, etc.

Where I struggle with PHP: when you want to do something "unusual" - something that you typically don't do on a regular basis (in the case I'm thinking of it was consuming a SOAP web service - not something I've done a lot with PHP), you're confronted with two options:

1) Various open source extensions to PHP. The PHP object model is loose enough where interface design is also not terribly consistent from library to library, developer to developer. When confronted with a set of code where someone used a library that you've never heard of, you spend a lot of time figuring out 'what the heck this does' because the language allows for loose API / library creation.

2) The "built-in" functions - of which there are a lot. I've gone through a few rabbit holes of either finding another library or implementing a bit of functionality to somehow later on stumble onto impossiblyfound_basefunction()

In my opinion, simplicity is consistency.

share|improve this answer

If a language is fixed in its design because of KISS, it cannot grow. A language that cannot grow will die.

In the following video Guy Steele cleverly explains that a programing language must be allowed to grow and why. If you apply KISS, then how can a langauge grow because once released, it's set of tools is fixed and never allowed to change.

Guy Steele's keynote at the 1998 ACM OOPSLA conference on "Growing a Language" discusses the importance of and issues associated with designing a programming language that can be grown by its users.

It is an hour long video but worth watching. If you don't know who Guy Steele is you really should when talking about language design.

I choose this video as the answer because I believe that applying KISS to language design in general is wrong, and hope that seeing a speech from a noted person of language design will help to expand your understanding of the future of language design.

Since you came here to learn about language design and I gave you a reason not to use KISS it is only fair that I point out something that I find of help in language design. Cognitive dimensions of notations

EDIT

When I wrote the above answer it is was based on the reasoning of: if an engine can be only maintained with a fixed set of tools then my reformulation of that meaning with respect to language design is that a language cannot change once released. The comments are indicating that that was not what was meant. So let me put forth this modified answer that will be more in-line with the revised understanding.

If one takes a look at Cognitive dimensions of notations then one learns that there are many competing dimensions associated with language design than just simplicity and if you focus too heavily on one, you will suffer in others. With the question of is focusing heavily on simplicity (KISS) good, and backed up by noted people of language design, I submitted the speech by Guy Steele to show that trying to keep a design solely simple will impact other dimensions. More importantly I am trying to convey that you need to look at many dimensions and weigh the pros and cons of them, not just simplicity.

share|improve this answer
2  
So, what happens if the video becomes unavailable? Or if it's not accessible in some countries? Your answer should be complete and self contained, please update it to at least give us a brief summary of the video, link only answers are not really helpful and might be removed at any time. –  Yannis Rizos Dec 6 '12 at 7:18
    
I like the video IMO its an appropriate answer. And it will be accessible in future, it's cited way to much to vanish fast or even at all. –  AndreasScheinert Dec 6 '12 at 9:15
3  
@AndreasScheinert The how to answer guide makes it clear that links must always be accompanied by summaries and/or relevant quotations. –  Thomas Owens Dec 6 '12 at 12:56
3  
I'm not sure I can agree with your assessment. Tcl, for example, is remarkably simple. It lasted for years with only 11 rules governing its usage. Yet, as simple as it is, it has grown considerably in the 20+ years of its existence. It now has 12 rules, which proves that not only has its library grown, but its fundamental nature has also been allowed to grow while still retaining all of its simplicity. –  Bryan Oakley Dec 6 '12 at 18:31
1  
@Guy Coder: On the other hand, the video you have posted a link to seems to say something different wrt what you say at the beginning of your answer, namely that a language should provide certain core features that allow its users (programmers) to extend the language (add new libraries). It does not say that the core language should grow indefinitely. –  Giorgio Dec 7 '12 at 14:50

Arguably, Tcl was developed along these lines. The entire language can be described in only 12 rules on a single man page. It is remarkably simple and consistent.

The creator of Tcl claimed the following as the original goals:

  • The language must be extensible: it must be very easy for each application to add its own features to the basic features of the language, and the application-specific features should appear natural, as if they had been designed into the language from the start.
  • The language must be very simple and generic, so that it can work easily with many different applications and so that it doesn't restrict the features that applications can provide.
  • Since most of the interesting functionality will come from the application, the primary purpose of the language is to integrate or "glue together" the extensions. Thus the language must have good facilities for integration.

From "History of Tcl" - http://www.tcl.tk/about/history.html

share|improve this answer

I think the Zen of Python will state why Python is a simple language a lot better than I can:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Edit in response to @Giorgio

As your question states,

"Do you know of any programming languages that have been designed specifically with this principle in mind, i.e. to 'allow an average programmer under average working conditions to write and maintain as much code as possible with the least cognitive effort'"

Python is, to me, what immediately comes to mind. Python's design is in direct response to Perl's methodology, the famous "There's More Than One Way To Do It". While that's great, allowing programmers to very easily write code, it doesn't help with maintenance. Having before managed a (very poorly written, I'll admit) program written in Perl, I appreciate Python forcing both good coding practices and concise language down your throat.

Python also does not force you to follow one particular methodology when writing programs. I can choose to follow strict Object-Oriented programming style, or I can write a simple script to execute sequentially. Not having to initialize a class, then call the main() method like you're forced to do in Java is very nice. (Also, printing to stdout in Python is wonderful, but that's a rather null point).

Finally, the "Batteries Included" methodology of including an expansive standard library with the language is wonderful. Instead of hunting through some external repository for packages, most of what I need is already included in the language. It's also nice having that external repo, but not having to dig through it in order to do a basic operation is really handy.

share|improve this answer
3  
Thanks for the useful citation. Is this the official intention of Python's designer(s)? Also, note that not all the readers might agree with your opinion about Python, so it is maybe a bit too strong to state that "Python is a simple language" as a well-known and accepted fact. Would it be possible to formulate it as "Python was designed with simplicity in mind"? –  Giorgio Dec 6 '12 at 16:13
    
@Giorgio - It is the experience of many developers around here that python actually is a simple language. Simple to learn, simple to write and simple to read. About the quote, as python is "batteries included", you can get it directly from the language with import this command. –  mouviciel Mar 22 '13 at 8:05
1  
TCL is also a good answer for this and IIRC was also a response to the complexity of PERL. –  jk. Mar 22 '13 at 8:22
    
@mouviciel After coming across some amazingly convoluted Python spaghetti code in multiple places, I no longer think Python succeeds in its goals here. Python is no better than most languages when it comes to simplicity - it can be very good at accidental obfuscation. –  Izkata Mar 14 at 4:04
    
Python is simple as long as people stay away from most of the __magic_functions__() and @decorators. –  weberc2 Sep 18 at 19:08

But can the KISS principle be applied also to programming language design? Do you know of any programming languages that have been designed specifically with this principle in mind, i.e. to "allow an average programmer under average working conditions to write and maintain as much code as possible with the least cognitive effort"?

It is a good thing you clarified what you mean by "simple", because in my mind a simple programming language is one with minimal syntax and few features (Scheme, Forth, ML), which does not directly translate to your definition. I think you are really looking for languages design with RAD (rapid application development) in mind, and there are quite a few of them. See this StackOverflow thread, for instance: http://stackoverflow.com/questions/66227/what-is-the-best-multi-platform-rad-language

share|improve this answer
    
"because in my mind a simple programming language is one with minimal syntax and few features (Scheme, Forth, ML)": Well, actually I copied the definition from wikipedia but I tend to identify the two things. E.g., Scheme can be learnt very quickly and after that I can concentrate on the problem to solve. Other languages (like C++, which I use at work) keep growing and you have to learn new stuff all the time. Also, code becomes less maintainable because different programmers tend to use different subsets of the language. So, I would consider SML and Scheme "simple". –  Giorgio Mar 22 '13 at 14:33

Here's a big quote from Bruce McKinney's Hardcore Visual Basic, which in turn puts words into the mouths of the designers of BASIC, Kemeny and Kurtz. Emphases mine.

Every computer language has its own feel, its own atmosphere, its own spirit. You can’t really define this spirit, but you know what it is when you see it. I think of Basic as the antithesis of a statement attributed to Albert Einstein:

Make things as simple as possible—but no simpler.

Had that quote been written by the original designers of Basic, John Kemeny and Thomas Kurtz, it would have been simplified further:

Make things simpler than possible.

That is the contradiction hardcore Visual Basic programmers live with. We want things to be simple, elegant, and intuitive—but they aren’t. We want our programs to model reality—but they don’t. We want our language to work the way we think, not the way computers or operating systems want us to think—but we’re not willing to pay the price.

share|improve this answer
    
On a related note, the fact that a language construct "can" be made to serve multiple purposes doesn't mean that such a design is preferable to having different constructs for those different purposes. For example, C uses unsigned types both to represent numerical quantities and to represent members of a wrapping algebraic ring. Adding a number of any size or signedness to a ring should yield a member of the same ring, while adding two numbers of any size and signedness should yield a result large enough to handle any value of either operand. Using unsigned types for both purposes... –  supercat Mar 13 at 4:37
    
...means that C's rules have to sometimes regard them as numbers and sometimes as ring members, in ways that make it almost impossible to write clean, portable code. –  supercat Mar 13 at 4:38

Ruby on Rails is all about reducing programmer workload. As their site states; "RoR is a framework that is optimized for programmer happiness and sustainable productivity. It lets you write beautiful code by favoring convention over configuration."

Obviously RoR is a web technology and isn't right for everyone, but if KISS is your only standard it would be worth your time to look into.

share|improve this answer
1  
I think he's talking more language design than framework design. –  Erik Reppen Dec 6 '12 at 2:01

Java Wikipedia - although not explicitly stated in Wikipedia, simplifaction is mentioned a number of times and was an original design goal, as the only serious OO capable (Term used loosely) language in those days was C++, which as we all know, is powerful but has more than a few traps for the unwary.

The JVM was intended as a way to simplify cross platform development, and "Write once Run anywhere" became a Java mantra for a few years - again, the intent was the framework was simple to deploy.

I believe C# falls into that category of simplification of the language.

share|improve this answer
    
Do you mean that C# was also initially designed as a simplification of C++? –  Giorgio Dec 4 '12 at 22:55
1  
C++ and OO? Alan Kay doesn't think so. C# Sinplyfication???? I don't know what you mean by simple. I think it would be best you state that before declaring things as such. LISP is simple as it has very few syntax. C# on the contrary has TONS of syntax and keywords. –  AndreasScheinert Dec 6 '12 at 9:13
    
The ability to simplify cross-platform development doesn't mean the language itself is simple. Something can be cross-platform yet still not simple in and of itself. –  Bryan Oakley Dec 6 '12 at 18:35
    
@Bryan Agreed - the design of Java took into account that cross platform programs were not (at the time) simple, and to create simple programs, you needed a simple language and needed to remove complexity of handling platform specific code in the program itself. –  mattnz Dec 6 '12 at 21:07
    
@Giorgio C# was a reimagining of Java. Java was intended to be both less complex than C++ (e.g. no multiple inheritance) and something far greater (e.g. vast standard library, garbage collection). –  Sean McSomething Mar 22 '13 at 17:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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