Right. I think the important distinction is whether an imperative language is used to describe things that could be done purely declaratively, as is the case with Gradle[1]. I think this happens all too often because the oldschool declarative system has some edge case that it can't handle, so someone reinvents it with a fake DSL which is actually a dialect of an imperative language, and now you have the worst of both worlds. I've always thought that what we needed was a way to allow both declarative and functional information to be provided, but with a clearer separation between the two. e.g. a build configuration language based on this approach might allow one to specify either 'buildArtifactId: "xyz123"' or 'buildArtifactIdExpression: (functional expression to compute a build artifact ID goes here)'.
I sort of tried to do this with the Factorio terrain generation system[2]. The first phase is to run a Lua program, which is imperative, but the result is an immutable object representing the terrain generation configuration, which in turn includes functional expressions, since a map where everything is constant would be boring.
[1] I f&!@#^ing hate Gradle; it is my go-to example of thoughtlessly mashing paradigms together because you can, resulting in something that nobody I have ever met really has really been able to work with except by trial and error.
I sort of tried to do this with the Factorio terrain generation system[2]. The first phase is to run a Lua program, which is imperative, but the result is an immutable object representing the terrain generation configuration, which in turn includes functional expressions, since a map where everything is constant would be boring.
[1] I f&!@#^ing hate Gradle; it is my go-to example of thoughtlessly mashing paradigms together because you can, resulting in something that nobody I have ever met really has really been able to work with except by trial and error.
[2] See https://factorio.com/blog/post/fff-200 and https://togos.github.io/togos-example-noise-programs/