Does simplicity always improve readability?
I would say, maybe with a little bit of controversy, absolutely not.
You could hand me a class with 200 member functions in its public interface, and it may be the most humanly-readable public interface out there. It might be a joy just casually reading through such code and its documentation. However, I wouldn't call it "simple", because in spite of the readability, I would have to be concerned with how all these functions interact with each other, and potentially watch out for tricky edge cases resulting from misuse.
I would prefer a class with 20 member functions that weren't so easy to read to 200 that are, because "readability" is not the top priority to me in terms of preventing human error and improving the maintainability of code (the ease at which we can change it, i.e.).
However, this is all going to hinge on our personal definition of "simplicity". "Readability" typically doesn't vary that wildly among us, unless someone has acquired so much expertise and fluency that they consider regex to be very "readable", e.g., forgetting the rest of us mere mortals.
Simplicity
There was a time, long ago, where I thought "simplicty" meant "as easy to read as possible". So I would write C code with a lot of convenience functions, trying to improve the syntax and make things as easy to read and write as possible.
I designed very big, rich, high-level libraries as a result, trying to model a function for every natural human thought: helpers upon helpers upon helpers, all to shape the client code to a more readable syntax. The code I wrote back then may have been the most "readable", yet it was also the most "unmaintainable" and "complex".
Lisp
Yet I had a brief passion with LISP around the mid-90s (latecomer). It changed my whole idea of "simplicity".
LISP is not the most readable language. Hopefully no one thinks that extracting CDRs and CARs while invoking a recursive function with a boatload of nested parentheses is very "readable".
Nevertheless, after struggling to get my brain wrapped around the language's odd syntax and totally recursive ways of doing things, it permanently changed my idea of simplicity.
What I found with the code I wrote in LISP is that I was no longer making subtle errors anymore, even though the trickiness of thinking that way had me making more blatant mistakes (but those are easy to spot and correct). I wasn't misunderstanding what a function was doing and missing out on a subtle, unanticipated side effect. I was just having an easier time in general making changes and writing correct programs.
After LISP, simplicity to me became about minimalism, symmetry, flexibility, fewer side effects, fewer but more flexible functions that combine together in an infinite variety of ways.
I came to appreciate the mindset that the most reliable code of all is code that doesn't exist. While it's only a crude metric, I tend to see the potential for unreliability of code based on its quantity. Seeking the utmost syntactical convenience and readability tends to increase that quantity by a large factor.
Minimalism
With the LISP mindset embedded in me, I came to prefer minimalist APIs. I'd prefer a library with fewer but more reliable, flexible functions that are less convenient and potentiality harder to read than one which offers a boatload of "convenient" helpers and such which may make the code easy to "read" but potentially trip over more issues with unreliability and surprises that result from misunderstanding what one of these thousands of functions do.
Safety
Another thing about LISP was safety. It promoted minimal side effects and pure functions, and that was where I no longer saw myself making subtle mistakes, even though the difficulty of reading and writing in the language increased more blatant mistakes I could spot 10 seconds later.
Pure functions and immutable states became preferable to me whenever I could afford it, even if the syntax of:
sword = sharpen(sword)
... is a little less straightforward and detached from human thinking than:
sharpen(sword)
Readability VS. Simplicity
Yet again, LISP is not the most "readable" language. It can pack a lot of logic into a small section of code (possibly more than one human thought per line). I tend to ideally prefer one human thought per line for "readability", but it's not necessarily for "simplicity".
With this kind of definition of "simple", sometimes "simple" might actually somewhat compete with "readable". This is considering things more from an interface design point of view.
A simple interface means you need to learn far fewer things to use it, and potentially has greater reliability and fewer gotchas as result of its minimalism. A comprehensive documentation on the subject might fit a booklet rather than a massive volume of books. Nevertheless, it might require some more grunt-work and yield less readable code.
"Simple" to me improves our ability to understand the functionality in our system at a broad level. "Readable" to me improves our ability to connect each little line of code to natural language and thought and might speed up our understanding of what one line of code does, especially if we're not fluent in the language.
Regex is an example of what I consider "extremely simple". It's "too simple and too unreadable" for my personal taste. There's a balancing act for me between these extremes, yet regex does have that LISP-like quality of simplicity as I define it: minimalism, symmetry, incredible flexibility, reliability, etc. The problem for me with regex is that it's so simple that it has become so unreadable to the point where I don't think I'll ever become fluent at it (my brain just doesn't work that way and I envy people who can write regex code fluently).
So anyway, that's my definition of "simplicity", and it is completely independent of "readability" and may sometimes even interfere with the other, leading to a balancing act between a more "syntactically convenient" and readable but bigger library or a "syntactically inconvenient", less readable, yet smaller library. I've always found the true "convenience of understanding" and true "maintainability" priorities to align with the latter, with the strong preference towards minimalism even at some cost to readability and more natural human syntax (but not to the point of regex). YMMV.
a = b
is one operation,b + c
is a second, which meansa = b + c
is 2 operations. Chaining 2 functions/operators is still readable:foo(bar())
, ora = foo()
.