8 ms·
Is It Imperative to Be Declarative?
- threatofrain 4y agoEchoing the article, declarative is a degree and almost all if not all DSL's do not achieve declarative purity. The best places for a declarative DSL are for domains which are very elegant and well-studied, such as relational databases. Thus I generally don't pay attention to claims about declarative programming — it is rarely actually attempted despite the frequency of advertisement. The domain which Pulumi / Terraform targets is most definitely too messy to attempt a pure declarative DSL.
- flanked-evergl 4y agoTerraform has a non entirely declarative layer which generates entirely declarative representation which is then applied using providers. This may be a tenious difference from imperative, but it is the crux of it and this is what you want when managing resources.
- suralind 4y agoBut it's also limiting, for example, you may want to run some perform an action before a resource is deleted and then you have two options: a) create your own provider that will will handle the provisioning and deprovisioning under the hood b) use provisioner (e.g. local-exec) The first option is great if you have time and resources so create your own provider. The second option is what you're more likely to use if you are small and don't have a dedicated team. Also it's convenient if you can achieve 99% with existing providers just need to run one command, but doesn't always work (Terraform has many limitations regarding this).
- tekla 4y agoUhh, why would you ever use Terraform to do that? Its wild seeing people try and force Terraform to do things that the docs more or less YELL at you to not do. Secondly, I use TF and at least on AWS you use lifecycle hooks to do what you describe. If I saw someone using TF to do that,I would think they are incompetant.
- ryukafalz 4y agoNot every provider has lifecycle hooks.
- paulryanrogers 4y agoRight, and (as I understand it) vendor neutral is a selling point of Terraform
- 1letterunixname 4y agoIn terms of DSLs, this is the crux of Puppet vs. Chef. The danger (and power) of the Chef DSL is it allows imperative Ruby anywhere, including shops that liberally use monkeypatching "to put out fires". Puppet is a custom DSL that doesn't have this problem but it lacks the power of Chef. Declarative is generally even more limited than DSLs like Puppet and can't support complex logic. It maybe worth externalizing complex logic into "helpers" or other systems, but this creates a "Javascript frontend + something else backend" code-synchronization problem. Declarative seems "easy" and "looks like data" but it rapidly runs into limitations. (The other confusion with Chef is without unified_mode, there are 2 main execution phases that run on clients: compile-time and converge-time. unified_mode makes it easier for novices whereas 2 phase allows for the compile phase to adjust node settings when using an "API" model without databags or run_state.)
- eru 4y ago> Declarative is generally even more limited than DSLs like Puppet and can't support complex logic. Functional and logic languages would disagree. For configuration, have a look at https://dhall-lang.org/ https://dhall-lang.org/
- colordrops 4y agoNix is fully declarative (with flakes), supports complex logic, and is more powerful that chef and puppet. It is a bit more difficult to learn for those reasons as well.
- 1attice 4y ago+1. YAML is a terrible foundation for a declarative config. You need a language designed for declarative config. Some commenter above said that this space is too messy for a purely declarative language; someone else said Pulumi should be thought of as a macro language to generate a declarative spec. Instead of bolting on a whole Python interpreter to work as a macro language to generate a theoretical declarative spec, why not instead just write a declarative spec in a sanely declarative language? It's not that hard to learn Nix. Stop procrastinating, everyone, and go learn Nix :)
- qudat 4y agoI think this strikes at such a great line of reasoning: declarative vs imperative is the wrong abstraction. The thing I actually care about is: can I use a programming language or not?
- mkolodny 4y agoWhen a problem can be solved mindlessly - with a repeatable set of steps no matter the situation - imperative/declarative programming makes sense. Most real world situations are unique and require unique solutions. That's where AI really shines. You just describe your target, attempt to solve the problem, and pay attention to how far off you were from your target. The learning happens naturally. Neural networks are too complex - sometimes billions of variables - to decide what each neuron should do. We as a species have evolved to develop brains that are extremely adaptable. AI mimics our own natural learning process. And it's proven to be far more effective at solving unique problems.
- amarshall 4y ago> [AI] has proven to be far more effective at solving unique problems An extraordinary claim, I think. Source or evidence?
- mkolodny 4y agohttps://chat.openai.com/ https://chat.openai.com/
- lostcolony 4y agoWhen you've built a product using only OpenAI, and not a programming language, come back and tell us. While at it, come back and tell us when you've implemented a neural net using AI, and not a programming language, come back and tell us too.
- mkolodny 4y agohttps://github.com/features/copilot https://github.com/features/copilot
- lostcolony 4y agoYou don't think code is involved in that my dude? The input wasn't a description into an AI model, with copilot the model. It's code that calls to an ML model. Which is my point. The model was created with code. The model is deployed with code. It runs on infrastructure that executes a bunch of other code. Code takes in user input, puts it into the model, takes the resulting response, does something with it. There is no ML model that is a product in and of itself. ML is not a compiler. It is not a runtime environment. It does not understand business needs, it does not take direction. It certainly may be transformative, for good or ill, but it hasn't suddenly deprecated the need to code; far from it.
- deleted 4y ago[deleted]
- eyelidlessness 4y agoSigh. Declarative condition expressions are not control flow, they’re part of the definition. They are part of “what” and you could not define anything meaningful without them. The mistake is treating: if condition: a else: b As equivalent to: if condition: do a else: do b They might seem very similar, but they’re wildly different if you actually have the constraint. There is an implicit “do” somewhere in any program that has IO, but having it mixed in with a declarative program makes no sense and can’t make sense. In the SQL example, nothing happens if you reach the conditional and exit immediately. In the imperative example you have no way of knowing what happened without inspecting the resulting state, or the code that produced it.
- tpoacher 4y agoAssuming a is an expression, which could well be a call to a function, then the two are equivalent. Note that the argument here is one of declarativeness vs imperativeness, i.e. whether it is at all practically possible to ever have programs that have zero need for control flows. It is not one of whether a() is a pure vs a stateful function.
- aatd86 4y agoI don't understand how it is not control flow. I think they are always an artifact of imperative programming bleeding into a declarative framework. In a fully declarative fashion, you would just have: c where c is imperatively defined as being a or b depending on a condition/state. A declarative if statement doesn't make sense.
- rocqua 4y agoIn declarative systems, you want to explain the final end-state. Often your requirements on the final end-state involve some predicate logic. I want (A and B) or C. Using an Or makes sense, if you want your declarative logic to work on both windows and linux. Or you want configurable declarative logic, or you want to be easily able to manually change the files. A very natural way to do predicate logic is "if A is true, then B should be true". That is logically equivalent to "B or not A". But letting people write "if A, then B" is just nicer. Hence declarative logic is much nicer with "if statements". Perhaps another way to view this is that many declarative systems "build" their description of the desired end-state imperatively. I wouldn't say that applies here, but I could imagine cases where you want to say 'for all elements here' which might be best solved with a for loop.
- galaxyLogic 4y agoHere's a definition of "declarative program" I would start from, (trying to come up with a better definition) Declarative is when the interpretation or execution of a declaration in a program does not depend on the order in which you execute those declarations. Say you have 10 pure functions. The program --its interpretation-- is the same no matter how those functions are ordered in your source-code . The functions can depend on each other but no matter the order in which you call them the results are the same. But if those functions have side-effects, then the order in which you call them can have an effect on the end-result. It can cause an error if some initialization is not done before it is needed. That is not declarative programming then.
- aatd86 4y agoNot really sure what you mean. Alledgedly a HTML tree is declarative but sibling elemznts are ordered. You can't actually reorder these statements and expect the same UI tree. Usually, declarative is built upon imperative and simply means that implementation details have been abstracted enough to the point that we can build the program by describing its structure and it will build itself. As opposed as defining the build steps (they are predefined if you will).
- Timon3 4y agoI think you're mixing up the data with the statements. Yes, nodes in a subtree are ordered, but that doesn't mean you can't re-order the statements creating those nodes. For example you could insert the nodes in reverse order at the correct position. It wouldn't make any difference to the tree itself.
- aatd86 4y agoI must be a bit dense this morning :). I'm still not sure I understand. Defining insertion would be in the imperative portion of the code right? Since there, source order matters, you would have to change the subroutine that triggers insertion by changing the direction? When describing the tree structure however, listing the nodes (html nodes for instance) has to be in order, no? Creating those nodes can indeed be reordered provided there is no interdependence. the same way var a, b; c =a + b; can be rewritten: var b, a; c =a + b; Asking because it seems to me that commutativity is a hard sell here. Might be mistaken about what you mean.
- teo_zero 4y agoTIL that Prolog has loops. I can't imagine how you would use them, though.
- habitue 4y agoThis article doesn't really get at the core of the distinction between tools like Ansible, chef, terraform and pulumi/AWS CDK. There are two languages being discussed here: - the language the programmer writes in - the language that specifies the desired state of the infra. You want the language you're writing to be a good language (ie, a language you are productive in). It's very helpful for the language the config is specified in to be a declarative manifest. That doesn't mean you as a programmer have to write that manifest language directly. Pulumi and CDK are libraries that allow imperative languages to generate a declarative manifest. Terraform is a (very hamstrung) declarative language that is also a declarative description of the desired infrastructure state. It is hard to use because the language is bad. But the language is bad for no reason because it confuses the very desirable property that you want a declarative config with the totally undesirable property that you generate that config with a crippled declarative DSL. Ansible shows another side of this: it's a crippled declarative DSL that executes an imperative set of instructions to get the infrastructure into the desired state. The best you can say about the yaml straightjacket is that it causes you to organize your code with some structure, kinda like MVC web frameworks. But yaml's declarative nature doesn't impart any magic by itself. If you write a step that isn't idempotent, it just isn't idempotent. If you find yourself wanting to add templates, and loops, and references etc to yaml: this is a smell that you should not be writing yaml. You should use a real programming language to generate yaml. That's essentially what Pulumi and CDK are doing. You can think of your real programming language (python or typescript or whatever) as a macro language that outputs the declarative config. (For completeness, chef/bash deploy scripts are imperative languages that generate imperative commands to change the infra. Needless to say, this results in a mess usually)
- AaronFriel 4y agoPulumi does not generate a declarative manifest, your infrastructure program runs at the same time as the engine which applies resource operations. This allows you to use API calls, sleeps, and so on. It's a much more powerful model, and lets you use arbitrary computations between resources, using the output state of one to make an API call or some side effect, and plumb the result of that into the input of another resource. Full disclosure: I'm at Pulumi.
- xigoi 4y ago> > “In computer science, control flow (or flow of control) is the order in which individual statements, instructions or function calls of an imperative program are executed or evaluated. Within an imperative programming language, a control flow statement is a statement that results in a choice being made as to which of two or more paths to follow.” > This can be reduced to: > > “Imperative programs make a choice about what code is to be run.” No. You left out the part about order, which is the most important part.
- skaushik92 4y agoJust nitpicking here but doesn’t the property of being ordered follow from being able to choose between options at any instance? One analogy that popped up in my mind is sorting: if you can provide an answer to a choice between any two options in a list, in effect you can use that to order the list.
- xigoi 4y agoThat's an unrelated meaning of the word “order”. In this case, we have statements that all get executed, but in a specific order. There's no choosing between anything. What you're referring to is ordering in the mathematical sense, which means defining what is “bigger” in a certain sense than something else.
- dwenzek 4y agoThis post assumes that there is consensus around a formal definition of being declarative. This is hardly the case as highlighted by Robert Harper, an academic recognized for his work in the field of programming formalization , in his essay "What, If Anything, Is A Declarative Language?" [1]. [1] - https://existentialtype.wordpress.com/2013/07/18/what-if-anything-is-a-declarative-language/ https://existentialtype.wordpress.com/2013/07/18/what-if-any...
- Simran-B 4y ago> For various reasons, Terraform was ditched in favour of a python-based boto3 solution, and one of those reasons was that the restrictions of a more declarative language produced more friction than the benefits gained. I feel the same about CMake. It's horrendous and everything would be much simpler if you could use the full power of an imperative programming language. Conan on the other hand is Python-based and essentially a framework (though for a different purpose). With a nice set of built-in functions and a clean interface design, I believe that using a full programming language gives you many of the advantages of declarative languages without the oddities and an easy way to drop down to a lower level.
- brabel 4y agoIn the Java world there is also the debate between Maven (more declarative) and Gradle (less declarative, but also tries to pass as declarative), and the same conclusion is always reached: Maven make it very difficult to do complex things, therefore Maven builds tend to be very simple (sometimes lacking obvious features because of that) while Gradle projects tend to become utterly complex as it's just easy to use Groovy or Kotlin to create whatever mess you need the build to do... my argument to defend Gradle when this is pointed out is that if the build is doing intrinsically complex things, having a proper language to manage that complexity is the only sensible solution: people writing these builds are professional developers, if they can't keep complexity under control using a fully featured programming language, then they are just not very good professionals.
- samsquire 4y agoI wanted to be capable of bringing up an entire environment with one command using an orchestration of Kubernetes, Terraform, Ansible, Chef and Packer. I wrote https://devops-pipeline.com/ https://devops-pipeline.com/ it toplogically sorts a dot diagram file and executes a Graphviz diagram. In theory your code should produce an entire environment that is ready to use. It is infrastructure as code and pipeline's as code. It also runs parts of the diagram that can run in parallel in parallel Creating robust stateful code is an exercise in frustration. Just look at any command line utility that manages state of files or EC2 instances. If you run something and it fails then the files or infrastructure Is in an unknown state. This is the problem that both declarative and imperative tools have
- dustingetz 4y agoproposition: declarative computation is one that is compiled or interpreted into something with lower control flow. consider lisp: your DSL can have control flow if the macros process the control flow forms (if, lambda) into some lower thing (that lower thing often being lisp itself but after all macroexpansion). I.e. reactive DSL is declarative with respect to when recomputation happens and when memoization happens, the programmer does not specify these aspects they are implied. however the same DSL can still be imperative with respect to effect sequencing. another is programming with DAGs, the DAG captures control flow schematics as a value, abstracting away the actual evaluation rules (maybe the DAG is meant to be async, or reactive, or distributed). The DAG is declarative with respect to the abstracted evaluation rules, yet if there are effects in DAG nodes, we are not declarative with respect to those. We are however declarative with respect to how effects with a lifecycle are maintained and garbage collected, as that behavior is given by certain runtimes for the DAG.
- lifty 4y agoI think the article dances around the real issue when it comes to the declarative vs imperative debate. The discussion should always take into consideration the complexity of the system, and its dynamic nature. Systems tend to grow in complexity over time and the declarative constructs that were once enough to describe the state of the system start to require ever increasing complex hacks that resemble imperative code. At that moment the declarative interface for the system should be redesigned, with the new complexity moving into the imperative core, once again making the declarative interface/shell be congruent and simple. This process will probably never end, as we build more and more complex systems we will find new abstractions that better fit at modeling the state of the systems, and we have to go through that process of redefining the declarative models on an ongoing basis. If you look at the Kubernetes world, the same pattern played out. You have a declarative layer that is becoming ever more complex and hard to manage using tools like Helm, but then there is also a trend of encoding imperative operational knowledge in new frameworks and operators, that expose a much simpler PaaS declarative layer to users.
- ceceron 4y agoAFAIK there is no single generally accepted definition, what does it mean for a language to be declarative. Some people believe that pure functional languages are declarative because of the analogy with mathematics — computations are determined purely by the statement structure, not by the ordering of the statements. Some people (including me) have higher requirements — the declarative programming language should never tell what to do, should only define the problem without providing an algorithm to solve it. According to this definition, pure functional languages are far from declarative as much as the procedural languages. The only pure programming languages here (AFAIK) are some variants of logic programming (Answer Set Programming, Problog, ...), Constraint Programming (MiniZinc, Essence, ...), PDDL, some configuration languages (not all of them), etc. There is nothing wrong in having conditionals/loops in the declarative language, as long as they are used to define the problem, not the algorithm to solve it.
- soraminazuki 4y agoThe article asserts that anything that includes a conditional must be imperative because it dictates control flow. Under that view, the definition of the Fibonacci sequence would be imperative. F(n) = 1 (n = 1) F(n) = 1 (n = 2) F(n) = F(n - 1) + F(n - 2) (n > 2) But the above definition says nothing about how you should calculate the value of F(n). As a matter of fact, math tells us that the definition of F(n) can be converted to a formula that doesn't include conditionals. In other words, the conditional in the original definition of F(n) has no direct relationship to the actual control flow of programs that calculate F(n). It follows that F(n) is defined declaratively, invalidating the claim that declarative expressions can't contain conditionals.