The Nix language also doesn't need to exist. They want to write pure lazy declarative derivations - great, you can do that in any existing language. It's a matter of style and APIs. You don't need to spend years developing a brand new language from scratch. Not to mention that many derivations end up calling a Bash script underneath anyway because at some point you actually need to perform an action in the real world. How would a derivation looked like if written in <insert your favorite scripting language> with lazy APIs?
The Nix language is basically what you'd get if you were designing a DSL for declarative configuration of extremely deeply nested trees. Nearly every "feature" in the language is for making that easier. You could probably write a Nix -> JSON compiler and end up with something completely unreadable because the language hides so much of what's actually present in the fully resolved tree.
That's not true. The language needs to be declarative. if you use your favorite lang and develop a DSL around those APIS, that DSL would be declarative.. also the language itself, isn't that complicated.... it's really quite minimal. It has its roots in ML. I honestly think people expect everything to look like javascript or C++ and it's a shame honestly.
Pulumi is a great example of declarative APIs built with imperative programming languages. SwiftUI is another.
Personally I have nothing against the Nix language, and use it without issue, but it's untrue to suggest that the language itself requires uncommon support for this kind of thing.
Ooof... Pulumi et al are terrible to write and read. Why should I care about writing 'new' in front of all my declarative configuration? What happens when an if statement depends on a concrete value? How would that even work? The leakiness of the abstraction is too terrible to even consider.
Terraform et al, despite not being my favorite, have much simpler semantics than Pulumi. It's not always a good idea to write DSLs into languages with huge paradigm mismatches.
Just as a point of order. You offer no case for Pulumi and your one actual discussion of the semantics is misplaced as it deals with if expressions, not statements. Stratified ifs that occur at the non-recursive areas of the language are usually not a problem for these change management systems.
I'm not offering a case for or against either, to be clear - and neither are you - indeed you went so far as to say effectively you wouldn't even bother considering the semantics since they _must_ be awful.
The semantics of the Pulumi runtime are probably fine, but the semantics of the DSL layer that preceeds that when mixed with the sensible semantics of the Pulumi runtime are a recipe for disaster. This is based on my extensive experience with declarative DSLs in imperative languages. The impedance mismatch is high. Nothing to do with Pulumi's internal state management, but it's beholden to javascript.
Personally I see it as similar to typed vs untyped languages. You can add typing to untyped languages or you can just use a typed language. The language used shapes the structure and some are easier to reason about than others (to some people).
Meh... the nix language being as it is makes it a lot easier to write these things with less cruft. Every attempt I've seen at introducing laziness into a language like python, c++, rust, javascript, etc just seems to require a lot more unnecessary keywords and helper functions and cruft.