3 ms·
> There is no objective criteria to define a "simple" language. Perl was simple to some people. That's nonsense. Here are several: - The Chomsky hierarchy: re
by chriswarbo 8y ago
> There is no objective criteria to define a "simple" language. Perl was simple to some people.
That's nonsense. Here are several:
- The Chomsky hierarchy: regular expressions (finite state machines) are objectively simpler than context free languages (pushdown automata), which are objectively simpler than Turing-complete languages (Turing machines).
- "Pure" languages (which only calculate an output, deterministically, using only the given input) are simpler than "impure" languages (which can also alter the world via irreversible effects, and those affects may alter subsequent behaviour, even across iterations)
- Untyped languages are simpler than typed languages, since all values are interchangable (this is sometimes called "unityped", since there's one big type)
- Globally scoped languages are simpler than locally scoped languages (whether lexical, dynamic, whatever)
- First-order languages are simpler than higher-order languages (just ask any compiler designer!)
- Statically-dispatched languages are simpler than dynamically-dispatched languages
- Languages with local control flow are simpler than those with non-local control flow (e.g. exceptions, GOTO, etc.)
Those are just off the top of my head. Of course, simple languages aren't necessarily better languages, since it depends on the task. The same goes for anything, e.g. building with Lego is simpler than building with welded metal, but Lego is not appropriate for building a car. The above list isn't making value judgements about those features, it's just stating which is objectively simpler (there's a reason we don't program everthing in SK logic!).
As for the languages being discussed here:
- Python is Turing complete, impure, untyped, locally-scoped, dynamically-dispatched with non-local control flow
- Perl is Turing complete, impure, untyped, locally-scoped, dynamically-dispatched with non-local control flow
- Dhall is not Turing complete, pure, typed, locally-scoped, statically-dispatched with local control flow
In particular, I don't see the point of advocating Python while using Perl as a negative example. As imperative, interpreted, dynamic scripting languages they're pretty much identical (see "LAMP stack" for example); arguing between such similar options is mostly subjective, and probably devolves into a tyranny of small differences.
On the other hand Dhall is a very different language. It is objectively simpler across many different criteria (although more complex by a few, like its types). In particular, due to its simplicity we can have much more confidence that a Dhall program is correct than in a language like Perl or Python. For example:
- If evaluating a Dhall program gives the right answer, we know that evaluating it again will give the same right answer, since Dhall programs cannot change their behaviour unless we change their input.
- We know, without even looking at a Dhall program, that it will not perform unintended or malicious actions like deleting files, sending emails, keylogging, etc. This is because the Dhall language is incapable of doing such things (it is pure).
- If we're able to run a Dhall program at all, the type system will have ruled out certain classes of mistake (note this is an objective fact; the holy war around typing is about whether that's worth doing or not)
To me, another advantage of using a limited, single-purpose language like Dhall for configuration rather than e.g. Python is that it can withstand pressure to add hacks, preprocessing and other complications. I've worked on applications which defined their configuration in the same language as the program, and it wasn't long before that "configuration" was branching on environment variables, hostnames, etc. to distinguish between systems (e.g. dev, test, staging, production). Once those braches were in place, it wasn't long before system-specific functionality started creeping into them (since "before everything else" can be an easy place to add patches). Once the available functionality started depending on code from the "config" file, it wasn't long before an override mechanism was needed to trick the "config" into which system it should pretend to be on. At that point we need config for the config, and the cycle continues.
Sure you could blame bad developers, but that's only useful with hindsight. Pretty much every segfault, security issue, crash, bug, etc. can all be backsplained as avoidable mistakes made by bad programmers. Yet we still, as a community, decided to create automatic memory management, sandboxes, restart loops, bug trackers, etc. because we accept that we will make mistakes, and it's better to mitigate their damage, or avoid giving ourselves that power/responsibility in the first place, than it is to point fingers and assign blame after a catastrophe.
Truly bad programmers are those who refuse to automate tasks: piling up mental burdens until eventually something slips, rather than letting the machine deal with it. Infinite loops are a simple example: personal anecdotes do not solve the halting problem; making a language which always halts does (for that language).
Enforcing policies using a linter can be a good idea, as it makes the machine responsible. Yet linting is usually a last resort, since it's necessarily limited (especially in a language as dynamic as Python, where behaviour can be redefined in non-obvious ways). Also, a machine-enforced language subset is essentially a different language. It also seems disigenuous to pose a solution involving hypothetical linters that don't yet exist, after raising concerns about abandonment for an established, feature-complete project.
- icedchai 8y agoSometimes you need those hacks. I'd rather have the flexibility...
- KirinDave 8y agoTo be fair, Dhall is a whole hell of a lot more flexible than YAML. That's kinda the idea, it's proposing a principled compromise between XML and "an embedded language in an interpreted turing complete language module." It's not something you see very often, and it's even more rare to see as a separated executable that uses *nix pipes and files for delivery when needed.