I'm writing this as a summary of my thoughts about people who praise and value simplicity in programming languages, often when they learn the basics of programming and write their hello worlds, linked lists and Book classes. While being simple may seem as a good thing initially, not everyone realises the costs and trade-offs involved in making things easy, so I'd like to point them out. I wrote this primarily with Rust in mind, but you can apply this to other "complex" languages to.
Looking at popular languages, there are 3 routes you can take to make programming language easy and friction-less for new users:
1. Restrict what language can do. Without pointers, you won't have to explain what pointers are and won't have to introduce complex mechanism to deal with them. Without classes you will not need to explain inheritance and think hard about covering its corner cases. Without generics you will have very simple compiler and no one will ever be confused when looking at function signatures. If you take this path, you may proudly show that language spec fills just few pages, you can learn it in short time, won't encounter serious problems and other people will not write something you don't understand. It is also easy to demonstrate that you can write some useful programs that happen to fit within language boundaries. The obvious downside is that if you ever try to escape this prison, you'll hit a hard wall, and doing your job becomes either impossibly, or unnecessarily hard for no good reason. Examples: Go, Javascript.
2. Hide complicated things behind sophisticated mechanism that takes care of large part of complexity. This may take a form of a runtime, interpreter, garbage collector, and generally various forms of indirections and abstractions placed between you and computer. For many usecases those solutions work really well, and may indeed make you believe that you don't need to know the gory details that are hidden from you. The downsides are there too, though. Performance hit is one of them, and it may hit you hard if you encounter it. The underlying mechanism become so ingrained in your language and its runtime that getting around them will most likely be very hard. Reasoning about behaviour of complex mechanisms also becomes a problem. And "large parts" doesn't mean "all of it". Examples: Java, Python.
3. Give the developers ultimate freedom and let them do whatever they want. If the compiler never complains, beginners are happy. Here are your pointers and mallocs, go and multiply them. Add your ints to strings, cast pointers to whatever, and live happily ever after. The language is indeed small and simple, Downsides: the lists of "you should", "you shouldn't", reported data corruptions and CVE's fill large parts of language training materials. Example: C.
Now, all of those things are not necessarily bad on itself. Its unlikely that any of those downsides will bother you for the time when you learn the basics of the language, write some simple apps that have been written 1000 times before (and carefully selected to match language strong sides). There are even many people for whom the imposed restrictions leave enough space to do their job. Bur programming is very large territory and it actually not that hard to venture into area that is outside of "easy" zone. And the only reason why *you* may not encounter that is because someone else did.
That *someone else* ensure things work smoothly and efficiently for you. And when things *must* be efficient and reliable, simplicity gets in the way, wherever it came from. So:
[1] becomes non starter. If I *can't* achieve desired quality and language does not provide tools to solve complex problems, its useless. Yes, Go is nice for many things, but for many others it entirely unsuitable. You may live without generics, but keep in mind that Go authors *could not*.
You may think that threads are hard and async will solve all world problems, but you wouldn't use a webbrowser engine following this philosophy internally for a minute.
[2] Complex runtimes and GC makes programming easy most of the time. But they make reaching for ultimate performance and memory efficiency hard. There is a reason that most of the code on your phone is written in native languages (yes, even for android, large parts of it are native). There is a reason for not considering Java for video encoding, even if it could be done. If you are the one who writes garbage collector or something on similarly low level, such help is out of the question,
and you'll have to get your hands dirty.
[3] This one is easy, though I may be controversial. If you do *anything* I am relying on, I do not want to hear that you use such "easy" language, period. If you are careless enough to rely (edit: only) on people not making mistakes, I do not want to deal with you. And if I am working on ensuring high reliability, I will choose tools that provide as much guarantees as possible, artificial simplicity be damned.
And one day it might be you who need that. So appreciate existence of "complex" languages even if you are not needing them. Even if they make creating linked list non trivial and complain a lot about invalid lifetimes.
Note: I've skipped things like having good documentation, consistency, conventions and libraries. Those things are important, but have little to do with the language and are easily fixable.
Also I have no intention of claiming that some languages are better than others. It is not my point.
Looking at popular languages, there are 3 routes you can take to make programming language easy and friction-less for new users:
1. Restrict what language can do. Without pointers, you won't have to explain what pointers are and won't have to introduce complex mechanism to deal with them. Without classes you will not need to explain inheritance and think hard about covering its corner cases. Without generics you will have very simple compiler and no one will ever be confused when looking at function signatures. If you take this path, you may proudly show that language spec fills just few pages, you can learn it in short time, won't encounter serious problems and other people will not write something you don't understand. It is also easy to demonstrate that you can write some useful programs that happen to fit within language boundaries. The obvious downside is that if you ever try to escape this prison, you'll hit a hard wall, and doing your job becomes either impossibly, or unnecessarily hard for no good reason. Examples: Go, Javascript.
2. Hide complicated things behind sophisticated mechanism that takes care of large part of complexity. This may take a form of a runtime, interpreter, garbage collector, and generally various forms of indirections and abstractions placed between you and computer. For many usecases those solutions work really well, and may indeed make you believe that you don't need to know the gory details that are hidden from you. The downsides are there too, though. Performance hit is one of them, and it may hit you hard if you encounter it. The underlying mechanism become so ingrained in your language and its runtime that getting around them will most likely be very hard. Reasoning about behaviour of complex mechanisms also becomes a problem. And "large parts" doesn't mean "all of it". Examples: Java, Python.
3. Give the developers ultimate freedom and let them do whatever they want. If the compiler never complains, beginners are happy. Here are your pointers and mallocs, go and multiply them. Add your ints to strings, cast pointers to whatever, and live happily ever after. The language is indeed small and simple, Downsides: the lists of "you should", "you shouldn't", reported data corruptions and CVE's fill large parts of language training materials. Example: C.
Now, all of those things are not necessarily bad on itself. Its unlikely that any of those downsides will bother you for the time when you learn the basics of the language, write some simple apps that have been written 1000 times before (and carefully selected to match language strong sides). There are even many people for whom the imposed restrictions leave enough space to do their job. Bur programming is very large territory and it actually not that hard to venture into area that is outside of "easy" zone. And the only reason why *you* may not encounter that is because someone else did.
That *someone else* ensure things work smoothly and efficiently for you. And when things *must* be efficient and reliable, simplicity gets in the way, wherever it came from. So:
[1] becomes non starter. If I *can't* achieve desired quality and language does not provide tools to solve complex problems, its useless. Yes, Go is nice for many things, but for many others it entirely unsuitable. You may live without generics, but keep in mind that Go authors *could not*.
You may think that threads are hard and async will solve all world problems, but you wouldn't use a webbrowser engine following this philosophy internally for a minute.
[2] Complex runtimes and GC makes programming easy most of the time. But they make reaching for ultimate performance and memory efficiency hard. There is a reason that most of the code on your phone is written in native languages (yes, even for android, large parts of it are native). There is a reason for not considering Java for video encoding, even if it could be done. If you are the one who writes garbage collector or something on similarly low level, such help is out of the question,
and you'll have to get your hands dirty.
[3] This one is easy, though I may be controversial. If you do *anything* I am relying on, I do not want to hear that you use such "easy" language, period. If you are careless enough to rely (edit: only) on people not making mistakes, I do not want to deal with you. And if I am working on ensuring high reliability, I will choose tools that provide as much guarantees as possible, artificial simplicity be damned.
And one day it might be you who need that. So appreciate existence of "complex" languages even if you are not needing them. Even if they make creating linked list non trivial and complain a lot about invalid lifetimes.
Note: I've skipped things like having good documentation, consistency, conventions and libraries. Those things are important, but have little to do with the language and are easily fixable.
Also I have no intention of claiming that some languages are better than others. It is not my point.