This is so true, I have seen it happen with so many projects. It always starts with a cute declarative DSL, and inevitably imperative / flow control structures emerge, at which point you wonder why they didn't use a real programming language in the first place and save you the hassle or learning a half baked imperative DSL.
- Puppet
- CMake
- Terraform
- ...
All these started with pure declarative DSL then incrementally created a nightmarish imperative monstrosity.
Ant did not include IF THEN ELSE, unless you added the contrib package.
If you understood the paradigm, you could write branches in Ant files simply using properties and guards on properties ("unless"). Using IF in Ant was basically admission of not having understood Ant.
This said, I used Ant for a very limited amount of time.
As of Ant 1.9.1, you can use 'if' and 'unless' attributes on any task or element in a target. I stopped using Ant a long time ago, but this was a pleasant discovery when I had to pick up an old Ant based project recently.
I agree, that is what I meant: there were people who installed Contrib to have <if> element, but in reality you did not need that you could just use Ant's built-in features like you said. In my opinion installing Contrib to use <if> was a demonstration of not having understood how Ant works.
For new .NET SDK style projects you hardly ever need to customize the defaults and I know it's used for more stuff than .NET, but I just wanted to give an example where it actually doesn't suck. Also, you may not need to do everything in MSBuild, for some more complex stuff, you can use something like Cake (https://cakebuild.net/) in .NET for example and skip the programming in XML.
.NET made into my toolbox before it was announced to the world, thanks to be working at a MSFT partner that was selected to be part of the Portuguese launch event for .NET with ready made products.
Never seen any big corp using alternative .NET build tools, rather wrestling MSBuild, or before it came to be, nmake.
You say that, but people in OCaml keep bemoaning the use of mostly declarative s-expressions in the Dune build system. Imagine the reaction if MSBuild used an actual Scheme.
"Modern CMake" is more about scoping all properties to the targets that they belong to (including stuff like what you also need to link against if you link against target foo) than about language features. The CMake language hasn't changed much except correcting some early weirdness about "if" and the addition of generator expressions, which are fortunately not often needed.
> All these started with pure declarative DSL then incrementally created a nightmarish imperative monstrosity.
"Huh?" I asked myself when you mentioned that Terraform is now imperative somehow. Took a look at the website again, and seems to still be HCL, and still be declarative. Am I missing something? How exactly is Terraform today a "imperative monstrosity"?
> Terraform has modules which are an elaborate method of doing function calls
... What? How is modules a function call? It's just a hierarchy, everything about/with modules is still declarative.
> HCL 2 has loops and conditionals. It is most definitely imperative.
So what? Just because there is loops and conditionals doesn't mean it's suddenly imperative.
How exactly you do loops in HCL? Last time I used it, you still used declarative configuration for that, and use `for_each` as an declared option, you don't "call for_each which returns config", all that happens inside of HCL/TF, because it is declarative.
Did something change like yesterday or are people even here on HN so ignorant about what declarative vs imperative actually means?
You "call" a module with arguments. You can call them multiple times. In every way that matters they are just like a function call.
I don't understand why there is a distinction between for each in a standard language vs for_each in HCL2. They are both do something by iterating over something else at runtime. The syntax isn't what matters here.
I think maybe you are mistaken in your own distinction between declarative and imperative.
Imperative: Tell the computer how to do something, by instructing it what to do.
Declarative: Tell the computer what you want the result to be like, and the computer figures out how to do it.
for_each in Terraform is very much declarative, just like modules. Compare how you'd do the same thing with JS or any other (imperative) language you know, and I think it must be clear what the difference between the two is.
Those boundaries are pretty fuzzy. The complexity of the logic with conditionals and loops in a module means that you have pretty much stopped describing what it should like and instead described how to make it look the way you want it.
I have read terraform modules where I had to execute the logic to know what got produced which moves it from your imperative description to the declarative description as far as I'm concerned.
People love to hate on Maven's XML but at least it's been mostly the same since 2006. There are conditionals in profile activation expressions but they are very limited by design. Declarative done right, IMO
- Puppet
- CMake
- Terraform
- ...
All these started with pure declarative DSL then incrementally created a nightmarish imperative monstrosity.