This made me reflect on whether good language design should limit expressiveness of code?
This made me reflect on whether good language design should limit expressiveness of code?
The "base language" would be boring, pedestrian, optimizing for zero surprises. But inside an expressive{} block, you could have macros, operator overloading, DSLs, first-class continuations, you name it.
Yes, I think so. "Smart" code is smart for 5 min, after that it becomes a liability
* Programming languages should be general.
* Programmers should be competent and disciplined enough not to misuse that generality.
I absolutely hate programming in languages like Java, designed for idiot programmers. I understand their place -- there are a lot of incompetent programmers, and we need to constrain them, and a lot of places with boring IT problems who won't be able to hire competent people -- but it's not something I'd ever want to touch. That sort of workplace and that sort of language would make me miserable.
> Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
Compare debugging something like git or hg (clever, simple data structure) to cvs or svn (non-clever, standard data structure).
Systems like git and hg don't just do more; they're also far more debuggable thanks to clever. That's not an IOCCC type of cleverness, but a deep, deep clever.
Likewise, consider general-purpose data stores (such as a KVS or an RDBMS) compared to a one-off data structures mapping directly to your data. The design of the original RDBMS was hyper-clever.
A wise man knows when to be clever and when not to be clever. I don't know of any programming language designer who can make that determination for me; it's too domain-specific. If you can rely on programmers to not be clever for inane reasons, you can allow them to be clever for architecturally-critical reasons.
You don’t think Brian Kernighan is wise?
So think more Python and less C, things like:
while (*a++)
Are expressive but they're unsafe and actually doing things the language should have built-in (in a safe way)I do a lot of my work in Python these days. One of the really nice things Python did is take the major design patterns in Lisp/Scheme, which were super-powerful but quite unreadable, and gave visually-distinct ways of expressing those.
For example, major design patterns like maps and filters are done as list comprehensions, which are nice.
Ditto for decorators.
The key thing is that I still have general-purpose functional programming (except for tail recursion, which I dearly miss), but I use constructs which don't have explicit Python semantic quite rarely. Still, there are times when I can do something which will e.g. cut architectural complexity in half, and that's well worth a little bit of magic code. I'll usually try to do that in an isolated, well-documented file which has the magic. That's enabled by having a language which relies on programmers having discipline rather than handcuffs.
It's a lot cleaner than the architectural contortions I see for any use of Java beyond its target (Java has a nearly ideal set of expressiveness for making an inventory management system, CRM, store web site, or similar types of database-backed applications).
As a footnote, the place for the type of C code you gave is low-level programming. That's a disappearing market, as even microwaves can now afford RISC chips in the tens of megahertz with modern memory managements, but for hardware, you really care not just what happens, but how it happens. I know what machine code while(*a++) will translate to, and for those sorts of systems, that's nice.
There's a magic to a sonnet that isn't found in blank verse. Limitations can do a lot to improve writing.
https://www.usenix.org/system/files/conference/usenixsecurit...
describing it as a way of circumventing security measures that try to ensure that a particular control flow is followed in a compiled binary. In that case the security goal could be seen as forcing the compiled program to behave in a way close to what a human writer (or reader) would expect, while this method gets around that. So in that way, it could still be a problem, because the programmer appeared to write specialized program X but it can potentially be induced to behave like unrelated program Y at run time.