As the Sample Programs collection grows, I often like to reflect on what I’ve learned. In particular, I enjoy comparing and contrasting languages and their features. After playing with over 100 languages myself, I figured I’d share my personal list of the coolest programming language features.
Now, normally these types of articles are designed as clickbait. For instance, I could have easily titled this article Top 10 Coolest Programming Language Features—and to be fair, I considered it—but, I felt like this article would be better served as a living document. In other words, I plan to make additions and changes as I learn more about programming languages.
So, make sure you check back every once in awhile, and don’t forget to give it a share. At any rate, let’s get right to it.
Features List
For your convenience, I've provided a list of links to each cool feature.
- Extension Methods
- Macros
- Automatic Properties
- Optional Chaining
- Lambda Expressions
- Gradual Typing
- Immutability
- Multiple Dispatch
- Destructuring
- Inline Testing
- Inline Assemblers
In the following sections, you’ll find an ever-growing collection of cool programming features for your perusal. When you’re done browsing, feel free to share some of your favorites in the comments.
Extension Methods
One of the coolest programming language features I’ve had the chance to explore is extension methods. When I first heard about extension methods, I was implementing Hello World in Kotlin. Of course, they’re completely unnecessary for such a trivial program, but I did get a chance to learn of their existence.
If you’re not sure what extension methods are, they allow us to tack on methods to existing classes without extending the class directly. For instance, let’s say we really like the String class in Java, but we think the class could benefit from a mutation method. Currently, the only way we can create a mutation method is by creating our own class which extends String:
public class StringPlusMutation extends String {
public String mutate() {
// Add mutation code
}
}
Meanwhile, in Kotlin, all we have to do is write a method which directly extends the String class:
fun String.mutate():
// Add mutation code
Now, anytime we create a String, we can call mutate on it as if mutate were a part of the original set of public methods in String.
Of course, I should mention that extension methods have their drawbacks. For instance, using our example above, what happens if the String API gains a mutate method? That would be one tricky bug, but it’s probably safe to say it’ll rarely happen.
Regardless, I would personally only ever consider using extension methods for rapid prototyping. Let me know when you use them in the comments.
Macros
Another one of the coolest programming language features I’ve come across is macros. When I first discovered macros, I was playing around with Hello World in Rust. After all, the print functionality in rust is implemented as a macro.
For those of you that don’t know, macros are actually a metaprogramming feature. More specifically, macros allow us to modify the language directly by adding rules to the abstract syntax tree. These rules are generated through pattern matching.
That said, the explanation above is pretty dense, so let’s take a look at an example in Rust:
macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
}
This rule was taken directly from the Rust source code. As we can see, the print macro has one pattern matching case which essentially accepts any number of arguments and attempts to format them before printing.
If the pattern matching syntax is confusing, it’s probably a good idea to learn a bit about regular expressions. The regular expression syntax is similar to the pattern matching syntax.
Of course, as you can probably see, macros are an extremely complex feature. In fact, they are often difficult to write and equally difficult to debug. That’s why, even in Rust’s documentation, macros are considered a feature of last resort.
Automatic Properties
In addition to macros and extension methods, one of the coolest programming language features is automatic properties. I first learned about automatic properties when I discovered them as a bit of syntactic sugar in C#. Since then, I wrote a bit about them in Hello World in C#.
Basically, automatic properties are just shorthand for getters and setters in object oriented programming languages. For instance, let’s say we have a Person class, and we want the class to have some name field. After all, people have names, so it makes sense to give the class this field. Let’s go ahead and implement this in Java:
public class Person {
private String name;
}
Now, if we want to be able to set the name, we’ll probably want to write a public method to update the private name field. Colloquially, we call these methods setters because they set a property of an object. However, officially, they’re called mutator methods.
In Java, the following creates a mutator method:
public setName(String name) {
this.name = name;
}
Already we have six lines of code, and we can’t even request the person’s name yet. To do that, we write a getter or accessor method:
public getName() {
return this.name;
}
In languages with automatic properties, we can completely remove these six lines of boilerplate code. For instance, in C#, the following class is identical to the one we just created in Java:
public class Person
{
public string Name { get; set; }
}
With automatic properties, we can reduce six lines of code to a single line for every field we want to expose—wonderful!
Optional Chaining
Up next in the list of coolest programming language features is optional chaining. I first discovered optional chaining when I was writing Hello World in Swift. Of course, the feature isn’t all that useful for implementing Hello World, but it’s still an interesting concept to explore.
Before I can really explain optional chaining, we have to get a grasp of what an optional value is. In Swift, variables cannot be empty. In other words, variables cannot store a value of NIL, at least not directly. This is a great feature because we can assume that all variables contain some value.
Of course, sometimes variables need to be NIL. Fortunately, Swift provides that through a boxing feature called optionals. Optionals allow a user to wrap a value in a container which can be unwrapped to reveal either a value or NIL:
var printString: String?
printString = "Hello, World!"
print(printString!)
In this example, we declare an optional String and give it a value of “Hello, World!” Since we know that the variable stores a String, we can unconditionally unwrap the value and print it. Of course, unconditional unwrapping is typically bad practice, so I’m only showing it for the purposes of showing off optionals.
At any rate, optional chaining takes this concept of optionals and applies it to method calls and fields. For instance, imagine we have some long chain of method calls:
important_char = commandline_input.split('-').get(5).charAt(7)
In this example, we take some command line input and split it by hyphen. Then, we grab the fifth token and pull out the seventh character. If at any point, one of these method calls fails, our program will crash.
With optional chaining, we can actually catch the NIL return values at any point in the chain and fail gracefully. Instead of a crash, we get an important_char value of NIL. Now, that’s quite a bit more desirable than dealing with the pyramid of doom.
Lambda Expressions
We likely couldn’t make it through a list of the coolest programming language features without talking about lambda expressions. Now, to be fair, lambda expressions aren’t a new concept (see: Hello World in Lisp). In fact, they’re older than computing. That said, lambda expressions continue to appear in modern languages—even as new features in established languages like Java.
To be honest, the first time I heard about lambda expressions was about three or four years ago when I was teaching Java. Back then, I didn’t really know what lambda expressions were, and I was hardly interested in them at the time.
However, a couple years later, I started playing with Python which has tons of open-source libraries that leverage lambda expressions. So, at some point, I had to use them.
If you’ve never heard of lambda expressions, you may have heard of anonymous functions. For simplicity, they’re synonymous. The subtle difference is that lambdas can be used as data. More specifically, we can package up the lambda expression in a variable and manipulate it as data:
increment = lambda x: x + 1
increment(5) # Returns 6
In this example, we have essentially created a function, stored it in a variable, and called it like any other function. In fact, we can even make a function return a function, thereby dynamically generating functions:
def make_incrementor(n):
return lambda x: x + n
addFive = make_incrementor(5)
addFive(10) # Returns 15
Now, that’s cool!
Gradual Typing
If you’ve been around coding a bit, you’re probably familiar with the two main varieties of typing: static and dynamic. Of course, let’s not confuse these terms with explicit and implicit typing or even strong and weak typing. All three pairs of terms have different meanings.
To me, one of the coolest programming language features is the intersection between static and dynamic typing called gradual typing. Basically, gradual typing is a language feature which allows the user to decide exactly when they want static typing—otherwise, assume dynamic typing.
In many languages that support gradual typing, this feature manifests itself through type annotations. Type annotations are pretty much what you would normally see in an explicitly typed language, but the annotations are optional:
def divide(dividend: float, divisor: float) -> float:
return dividend / divisor
Here, we have a fully annotated Python function which indicates the expected input and output types. However, we can just as easily remove the annotations:
def divide(dividend, divisor):
return dividend / divisor
Now, I believe nothing is stopping us from passing pretty much anything into this function in either case. However, the first option opens up opportunities for static type checking which can be integrated into IDEs and other static analysis tools. I’d say that’s a win-win.
While I’ve chosen to use Python as an example, the first time I encountered gradual typing was during my research for the Hello World in Hack article. Apparently, Facebook really wanted to improve on PHPs typing system.
Immutability
Another one of the coolest programming language features is immutability. When I first discovered immutability, I was actually in a course on high-level languages. In this course, we had an assignment where we had to compare and rate the features of about 10 different languages. Of those features, one of them was value semantics, a feature that implies immutability.
Of course, what is immutability? As it turns out, immutability describes variables—or rather constants—that cannot be changed after creation. Often, immutability is manifested in strings in many languages. That’s why it’s usually considered a bad idea to use concatenation in a loop:
my_string = ""
for i in range(10):
my_string += str(i) # Generates a new string every iteration
print(my_string) # Prints "0123456789"
In fact, you may notice that I never use concatenation in my Reverse a String in Every Language series for that exact reason. Of course, language developers are aware of typical pitfalls, so they do a good job of optimizing our mistakes.
Anyway, I had never actually seen a language implement immutability beyond strings until I played with Hello World in Elm. In Elm, variables are immutable just like in math, so the following code snippet throws an error:
a = 2
a = a - 5
Here, the issue is a matter of recursion. First, we define a
. Then, we attempt to redefine a
as a function of itself. To those of us who typically use imperative languages, we wouldn’t even bat an eye at this syntax. But to a mathematician, something is just deeply wrong with that second equation.
Of course, the beauty in immutability is the ability to trust a value after it is created. At no point will you have to worry about it changing behind your back.
Multiple Dispatch
Like lambda expressions, multiple dispatch isn’t exactly a new programming language feature, but it’s one of the coolest. That’s because, it allows us to do fun things like have different implementations of the same method in an object hierarchy.
Recently, I was reminded of this feature as I was writing the Hello World in Julia article. Apparently, Julia is a numerical analysis language like Python and R, and Julia supports general-purpose programming. Unlike Python, however, Julia supports multiple dispatch.
At this point, I should probably make a distinction between single and multiple dispatch. Single dispatch is a programming language feature which allows users to define the same method in different ways in an object hierarchy. For instance, consider the following:
pikachu.tackle(charmander);
charmander.tackle(pikachu);
Here, we assume we have two objects, pikachu and charmander, in some Pokémon hierarchy. Both objects override some generic tackle method. When we run this code, the JVM is able to dispatch the proper tackle method.
Of course, things can go poorly in a single dispatch language because the method selection is only dynamic for the caller. As for the parameters, we’re stuck relying on static types.
So, let’s say that charmander was instantiated as a generic Pokémon. With single dispatch, pikachu is going to use the generic Pokémon tackle method, not the charmander-specific one. As a result, pikachu could miss the tackle.
With multiple dispatch, this is hardly an issue because the method selection process occurs at runtime. Naturally, the proper tackle method is issued, and pikachu lands the tackle.
If I butchered that explanation, let me know in the comments. For a much better explanation, I recommend Eli Bendersky’s article titled A Polyglot’s Guide to Multiple Dispatch.
Destructuring
Remember when I mentioned pattern matching? Well, destructuring—also known as iterable unpacking—is another form of pattern matching used to extract data from collections of data. Take a look at the following example from python:
start, *_ = [1, 4, 3, 8]
print(start) # Prints 1
print(_) # Prints [4, 3, 8]
In this example, we’re able to extract the first element of the list and ignore the rest. Likewise, we can just as easily extract the last element of the list:
*_, end = ["red", "blue", "green"]
print(end) # Prints "green"
In fact, with pattern matching, we can extract whatever we want from a data set assuming we know it’s structure:
start, *_, (last_word_first_letter, *_) = ["Hi", "How", "are", "you?"]
print(last_word_first_letter) # Prints "y"
Now, that has to be one of the coolest programming language features. Instead of extracting data by hand using indices, we can write a pattern to match which values we want to unpack or destructure.
Inline Testing
To be honest, I wasn’t sure what to call this feature because I’m not sure it has a formal name. That said, inline testing is one of the coolest programming language features I’ve ever seen.
I first came across inline testing in Pyret, a language designed for programming education. In Pyret, unit tests are a part of the basic syntax. In other words, we don’t have to import any libraries or build up any suites to run tests.
Instead, Pyret includes a couple of clauses for testing within the source code:
fun sum(l):
cases (List) l:
| empty => 0
| link(first, rest) => first + sum(rest)
end
where:
sum([list: ]) is 0
sum([list: 1, 2, 3]) is 6
end
Here, we can see an awesome list sum function. Within the function, there are two basic cases: empty and not empty. In the empty case, the function returns 0. Otherwise, the function performs the sum.
At that point, most languages would be done, and testing would be an afterthought. Well, that’s not true in Pyret. To add tests, we include a where clause. In this case, we test an empty list and a list with an expected sum of 6.
When the code is executed, the tests run. However, the tests are non-blocking, so code will continue to run barring any catastrophic issues.
Regardless, I love this feature just in terms of honest maintainability. Testing is never forgotten in the development process when using Pyret.
Inline Assemblers
Oh, you thought inline testing was the only cool inline feature? Meet inline assemblers: one of the coolest programming language features I first learned about when writing Hello World in D.
As it turns out, an inline assembler is a programming language feature which allows a developer to tap directly into the system architecture. When using a language that has inline assembler support, the following code is completely legal:
void *pc;
asm
{
pop EBX ;
mov pc[EBP], EBX ;
}
Here, we have what looks like a mix between C/C++ and assembly programming, and that’s essentially what this is. We have written code that works directly with the underlying architecture, so we know exactly what’s happening.
I find this feature really interesting because languages tend to opt for abstraction when given the opportunity. With D, we can totally forego the built-in functionality and write a custom assembly-level implementation ourselves.
What Are Your Favorite Features?
Did your favorite feature not make the list of coolest programming language features? Let me know in the comments below, and I’ll check it out! Of course, don’t forget to give this article a share if you enjoyed it. I’m sure others will too.
At any rate, thanks for taking some time to check out my work. If you liked what you saw, consider subscribing to The Renegade Coder. That's where I do most of my writing. In fact, this article is a cross-post from that site, so why not check it out?
Top comments (45)
I'd like to throw in Pattern Matching from C# 8 and F# as one of the coolest language features.
In both these examples we first check if there was a value (using an
Option<T>
in F# or a nullable type in C#), then checking if there was or wasn't a first name to determine the name of the person to print.I totally ❤ using pattern matching in code over nested
if
blocks!That F# syntax is really pretty! Know anyone who would want to add some new F# snippets to the collection?
TheRenegadeCoder / sample-programs
Sample Programs in Every Programming Language
Sample Programs in Every Language
Welcome to the Sample Programs in Every Language repository! What began as a simple 100 Days of Code challenge has expanded into a fun project Within this repository, you'll find a growing collection of simple programs in just about every programming language to date.
Learn More
Originally, I had planned to have an article written for every code snippet in this repository However, in the interest of growing this collection, I removed the pull request merge article requirement As a result, not every code snippet in the repository has an associated article, yet.
Of course, we're adding articles every day, and we're tracking our article progress under the issues tab Feel free to request your favorites from there, and we'll try to move them up the queue. If you can't wait, consider writing the article yourself. Prospective authors can find directions in the contributing doc…
Also, I'd be interested in learning more about pattern matching. I've seen it in other functional languages like Racket, but I don't know a lot about it.
I'll have a look at getting an example up there for you 😊
I love C#
There is a feature in Kotlin that I haven't seen in any other programming language and I think is the coolest feature ever.
Extension lambdas: It's a lambda where you specify the value of 'this', where 'this' is the implicit object where to find functions or fields. For example, the function apply() has a lambda as argument where the value of 'this' is the object used to call apply() (Kotlin lambdas are delimited by
{}
)It creates an instance of StringBuilder and calls the method append() without having to write
this.append()
. In java you have to write this instead:This also works with properties, so you can easily build SDLs:
Oh, so this is pretty cool. Let me try to understand it better. Instead of writing a constructor with ten parameters, you can expose properties that can be set with an extension lambda?
yes, basically, but it has a lot more uses!, for example there is a library that allows you to write html using extension lambdas and it looks like this:
they have the same flexibility as normal lambdas but with a lot less boilerplate
Wow that’s elegant. I imagine you get the added benefit of type checking and whatnot, right?
Yes!
Great article Jeremy! Thanks.
Funny because I didn't know what extension methods were and instead of some voodoo thing they are just what you can achieve in Ruby with open classes:
or JavaScript extensions using prototype inheritance:
Optional chaining should be added to all languages with the concept of
null
😭en.wikipedia.org/wiki/Extension_me...
"The Ruby community often describes an extension method as a kind of monkey patch." 😀
But yes, they can be useful.
Wow. Clearly, I haven’t played around enough with ruby or JavaScript. I really thought Kotlin was changing the game. Haha thanks for the tip!
You can do this weird BS in PHP. I liked it when I super junior and starting out but now it horrifies me as quite the bad idea.
Disclaimer: I didn't atually test the above.
Woah, that's wild. You can literally initialize objects and run methods using strings?
Yeah. Heck you can get even weirder.
You can reference variables with it too like above. In php this whole thing is called variable variables.
You can get weirder too. I'm not gonna redefine the above class because I'm lazy but:
Hahaha in a weird way, I find this syntax amazing. The idea that everything is just a string is really a funny concept, and it would make a great language for obfuscation. Good luck trying to figure out what anything does.
Kind of reminds me of Tcl: "strong internationalization support: everything is a Unicode string"
I wish to make the disclaimer that while the above is possible it's not super common anymore. You might find some of that fun in framework or library code instead of using or in addition to reflection. You would also see it in legacy code, especially version 4 and below. I found that syntax really cool when I just starting out at programming as well, now I see it as a really strange and even powerful language feature, but one that should almost never be touched. :P
Php arrays are equally BS though. PHP doesn't have real arrays, as in the sequential memory array concept. Everything is essentially a hash map. This causes some weird indexing things. The official docs explain it much better than I can.
php.net/manual/en/language.types.a...
Also for all it's weirdness, php docs at least are really good for the most part. Also PHP is not as bad as people make it out to be at least version 7.1+ and beyond. Though it still is fucked. :P
Also php tried to do the whole everything is unicode thing I believe in version 6 but abandoned it.
What a great post! It's really kicked off some good discussion.
Now... to business!
Macros
Alas! Alas, that you should have stumbled upon macros in Rust of all places! Macros in Rust are horrible - look at that syntax:
A whole new and weird 'pattern matching' language to manipulate Rust's AST. No wonder we're not meant to use it - it's horrible!
macro_rules!
? More likemacro_sucks!
.My friend, if you want to see and do macro programming right, you need to get yourself a Lisp. Preferably Common Lisp, but Racket, Scheme or Clojure will do in a pinch. Because these languages exhibit homoiconicity, which is to say that the representation of the language - the way you write it - is a data structure of the language. You write Lisp - as lists!
This means that, when it comes to changing the program with a macro, you're using the same language (Lisp) to manipulate the list structures that are the syntax of Lisp. No weird embedded pattern matching language - just the same stuff you've been writing all along (only occuring before evaluation which takes a bit of getting used to...). Code is data! Data is code!
Try them today - Lisp macros are fun and easy!
(Whether they're a good idea or not is more contentious...)
So, I've actually written a pretty basic Lisp interpreter (in an imperative language no less), so it makes sense that you can manipulate the language with itself. In fact, I believe Racket has a ton of support for dialects, but I haven't gotten a chance to play around with that feature myself.
Thanks for the tip! I know C has macros as well, and they're arguably worse the Rust's, so I guess I could have used a worse example. haha
Pattern matching! I've only been familiar with variable unpacking from Python and then I learned some Erlang. Many people don't like Erlang's syntax but pattern matching is great! I understand that F# and OCaml also have that.
Haskell types. I've been toying with language construction lately and it's very nice.
This would take an entire class hierarchy in Java.
And third, string interpolation is very handy.
Wait, so you can write an entire language grammar in Haskell like that?! I once wrote a compiler in java, and I ended up just using ANTLR to generate the syntax tree (and a huge string of If statements to clean up that tree). This would have been a lot more fun to work with.
Yes it's from the parser generator example
haskell.org/happy/doc/html/sec-usi...
I understand you can do the same in OCaml and F#, they say ML languages are well suited for compiler construction for that. I've been playing with yacc-like Java parser generators and that seems such a time saver compared to a Java class hierarchy.
Edit: you still have to define production rules though, just like in Yacc.
The C/C++ preprocessor is still a feature I miss in virtually every other language I ever touch. The ability to transmute the actual code before it is parsed is invaluable in those environments. It also ties in directly with the inline ASM on your list, where the preprocessor can be used to select the proper ASM architecture for the given platform.
A great example of this is used in crypto libraries. They generally have a basic C/C++ implementation, but also optimized versions of certain routines for x86, x86-64, AES-NI, ARM, ARM-NEON, and more.
It is also nice to have platform-specific or build-specific flags that can toggle various parts of code on/off, or change things up entirely. This helps when porting code for example, because the path to a particular file may not be the same between Linux, BSD, MacOS, and Windows.
One last trick to mention. The preprocessor can also modify the linker. In one of my projects, I have preprocessor directives to link in static libraries. These libraries are compiler specific, so instead of creating countless different build scripts, I have a single CPP file with them all listed with different #ifdef tags to target each compiler.
Given that the C pre-processor can usually be invoked without the language compiler (eg: gcc -E), it can and indeed has been used to pre-process other languages, Wikipedia has a nice list of abuse at the end here:
en.wikipedia.org/wiki/Preprocessor
Of course many people think pre-processing is bad (mostly I agree):
stackoverflow.com/questions/321791...
literateprogramming.com/ifdefs.pdf
Very cool stuff! I try to stay away from languages like C/C++ because I don’t love managing my own memory. That said, I’m always surprised with how powerful those languages are.
Self-managed memory does add some issues, but it also affords some great advantages, too! Last year I worked on optimizing a web server for a micro controller that only has 80KiB of RAM so it required a lot of custom fine-tuning of memory management to get the thing to perform well.
Here is an example of one method I converted from a C++ managed memory library to some unmanaged code to help reduce the RAM consumption:
gist.github.com/darkain/23da34f00e...
I'd say another great language feature is generics. I'm not sure if C# was the language that first created this feature, but it was my first exposure to it.
Some references for those interested:
Good one! I forgot about generics. They're used all the time in Java as well when you want to specify the type of some collection (i.e.
ArrayList<T>
,LinkedList<T>
, etc.).I guess we kind of just take generics for granted. It would probably take me to program in a language that doesn't have generics (like VB6) to really appreciate it.
Top 10 Coolest Programming Language Features! You won't believe number 9!!!
Haha exactly! Number 3 will blow your mind.
Have you tried Groovy? It has most of what you list here, and for someone that's familiar with Java it doesn't take much getting used to.
Oddly enough, I've just started playing with Groovy:
Add Article for Hello World in Groovy #33
Merged the script #20. Never wrote the article.
I'm in the process of trying to get groovy files to run with docker (and writing a hello world article). Any good tutorials or documentation you know of for Groovy?
I liked Venkat Subramaniam's book, "Programming Groovy".
Hello World is just...
println "Hello World!"
That sure beats the heck out of: