Dhall's really cool because you can use it even if your tooling doesn't support dhall. There is direct JSON/YAML support with dhall-json: https://github.com/dhall-lang/dhall-json
If you wanted to generate something like an NGINX config (or, for example, TOML or Terraform) you could use dhall-text: https://github.com/dhall-lang/dhall-text
Dhall is very unique among configuration because it's "distributed", meaning that Dhall can load any file as a dhall expression, and has builtin URI resolvers to make even remote endpoints part of local configuration. This is excellent for, say, CI integration.
Dhall has "semantic hashing" so that if someone does change a dhall dependency in a surprising way, the dhall script will refuse to continue (and give a very clear error about what changed, where it was looking for the change, and why it's stopping).
Dhall is a secret superpower for project configuration. Especially as of the 1.14+ releases, it's become an increasingly go-to tool for me. Even in just one-off JSON generation scripts, I find it to be a lifesaver.
Dhall is really similar to Nix in that regard, though in practice I've never seen Nix used for real configs (sadly). Usually trying to do so in Nix ends up being really ugly because the Nix features don't translate directly to concepts in the config language.
I dabbled in using Nix for this sort of thing, but it's rather painful to invoke the "Nix language" itself. In Nix 1.x we can evaluate a Nix expression (e.g. a templated string) like this:
That Nix code could be a file, or an import, or whatever. This is slightly improved with Nix 2.x:
$ nix eval '(Nix code goes here)'
Still, it's not particularly well suited to string processing from the commandline like this. We're closer to Nix's comfortable territory if we use it to build a config file, e.g.
$ nix-build -E 'Nix code goes here'
Or, more likely:
$ nix-build myConfigFileDescription.nix
In my experience this is more useful than trying to use Nix as a string processor. Still, if we're using Nix in a project or system, we might be better off using it to build the whole project (e.g. with a 'default.nix' file) or system (using a NixOS module or something).
From what I've seen, Guix takes compatibility with non-Guix systems a little closer to heart, e.g. for generating standalone packages that don't require Guix to install/use.
First, Dhall is quite unique in the design space of languages. Most (configuration) languages are either forbidding any user-defined functions/variables at all (like XML or JSON) or are Turing-complete (like having configuration directly in Python). Both of these approaches have downsides and Dhall is a compromise between those.
Second, the world of programming is not just Python. I like Python, but it is certainly not a focus of programming language research. Your statement sounds like a fallacy that if anything new could be invented, then it would have happened already.
Third, it is rather obvious that you unfortunately don't understand what Dhall is about and therefore any arguments you make are rather weak.
Python is a Turing complete language that can do anything. Dhall isn't. That lack of power means that a configuration language can still do a lot, but stick to its mission of configuration. It produces a final value (probably a map or list). Your real program reads that value and does the real work. Why complicate your real program with that? Offload it to dhall and you get a consistent configuration for free!
Think of all those places (e.g., Chef and Circle) where people try to encode graphs and processes in YAML. Dhall could do much of the same work of producing a simple spec, but without the fear of infinite loops or nonsensical Bash parameters hitting a function.
Dhall is such a simple language (really just function application and and some built-in datatypes and access principles) that it doesn't seem terribly costly as opposed to, say, embedding a complex graph into YAML (risking structural errors) or Python (risking extremely complex behavior and execute-only configuration). If what you really want is a declarative set of instructions to your real program, Dhall is probably one of the most awesome tools in the open source world for making it.
You sound like a marketer trying to sell a fridge on a phone call.
> Why complicate your real program with that? Offload it to dhall and you get a consistent configuration for free!
Why complicate my projects pipeline and force my team to learn yet another tool that may just be abandonned in 3 months?
> Dhall could do much of the same work of producing a simple spec, but without the fear of infinite loops or nonsensical Bash parameters hitting a function.
Last time I wrote an infinite loop in Python was... I can't remember. Maybe 5 years ago?
Nonsensical is subjective. Maybe Dhall only makes sense to you.
> Dhall is such a simple language
There is no objective criteria to define a "simple" language. Perl was simple to some people.
> If what you really want is a declarative set of instructions to your real program, Dhall is probably one of the most awesome tools in the open source world for making it.
Or you could write a nice Python library, with clean API, and eventually a linter that makes sure the Python configuration file is a restricted subset of Python.
> You sound like a marketer trying to sell a fridge on a phone call.
I've got no stake in Dhall and I'm not a contributor. Check my submission history to see the sorts of things I try to do at HN if you're curious what my agenda here is.
> Why complicate my projects pipeline and force my team to learn yet another tool that may just be abandonned in 3 months?
Dhall's substantially older than this and open source, so its not really an attrition risk in 2018.
But I'd argue your pipeline is already complicated. My CircleCI2 flow got enourmously simpler when I was no longer struggling to represent complex concepts in YAML and could just produce an object graph in Dhall and then render it to the right YAML. I've also switched to using it to generate json for mesos API calls to make sure I get the fields right.
> Or you could write a nice Python library, with clean API, and eventually a linter that makes sure the Python configuration file is a restricted subset of Python.
I grant, this is possible. But why does having it "in Python" matter? How does that help people writing Golang or C# or Ocaml or Scala or Ruby?
Dhall's decision to template out more standard files is a smart one, it means it can serve as a stand-in and let programs that do the heavy lifting of a product or process (e.g., a Python ML binding or airflow process) use their normal tooling and do what they love.
If you're mad it is written in Haskell, I dunno what to tell you other than that it's like "jq". The host language doesn't matter because you invoke it for its outputs.
There is no single economic perspective I can offer that can decide what tool is right for your org. Personally, I think that's an unfair question, since any answer I have would be uninformed to your specific circumstances. It'd always be wrong.
I'm sorry I can't work out what you like from this conversation. I've used this tool, I like this tool, and I'm comfortable with it. As such, I thought I'd share it since there's also a TOML article on the front page today.
Actually, believe it or not, economics is not the only measure we have to respect. There is joy in simplicity and understandability that does not need to be mapped to costs on a number line.
> 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.
To 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.
Of course anything can be done in Python, but why would we? I'm forced to use Python at work yet I still reach for other tools to manage the deployment process. I know many languages and I expect my team members to do the same, or let me teach them. It is not clear what your point is.
If you wanted to generate something like an NGINX config (or, for example, TOML or Terraform) you could use dhall-text: https://github.com/dhall-lang/dhall-text
Oh, did I say terraform? Someone's already on supporting that directly: https://github.com/blast-hardcheese/dhall-terraform
Dhall is very unique among configuration because it's "distributed", meaning that Dhall can load any file as a dhall expression, and has builtin URI resolvers to make even remote endpoints part of local configuration. This is excellent for, say, CI integration.
Dhall has "semantic hashing" so that if someone does change a dhall dependency in a surprising way, the dhall script will refuse to continue (and give a very clear error about what changed, where it was looking for the change, and why it's stopping).
Dhall is a secret superpower for project configuration. Especially as of the 1.14+ releases, it's become an increasingly go-to tool for me. Even in just one-off JSON generation scripts, I find it to be a lifesaver.