Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Give it enough time, every declarative language becomes a programming language. This is happening with all config files, markup languages, data formats.

The distinction between code, config and data is being erased. Everything is a soup now. Data is application, configuration is code. Code is an intermediate, volatile thing that is generated on the fly and executed in the temporary lambda containers.





> every declarative language becomes a programming language.

Overly pessimistic, lots of non-programming languages remain non-programming languages. Just because one of the most widely used declarative languages start adding conditionals doesn't mean the whole world is turning upside down...

> The distinction between code, config and data is being erased.

As as lisp programmer, I love it. Get rid of treating things differently, make everything the same and make everything work with everything, code should just be data.


> Get rid of treating things differently, make everything the same and make everything work with everything, code should just be data.

"Code should just be data" doesn't imply the converse, though; there's arguably utility in having data that isn't code, even with the premise that code should be data.


Regardless of should's or should not's, data is always code.

> Just because one of the most widely used declarative languages start adding conditionals doesn't mean the whole world is turning upside down.

The question still is: why is CSS becoming a programming language? And who decides on this, anyway?


Becoming? CSS is already Turing-complete (https://stackoverflow.com/a/5239256), even without if() function.

Why? Because of enormous JS bloat. Pure CSS solutions are more performant and backwards-compatible (don't raise exceptions which abort the code).

Who decides? CSS Working Group.


Or they are performant now. But once people start writing CSS code the same way the write JS code, they stop to be. You can still write super-tight code in ASM (or eve C) and it will be blazing fast. Almost nobody does it, because it's too hard. Once people start writing CSS the same way, it'll become slow and bloated too.

The big performance sink in CSS is rule matching, or layout if you consider that to be part of CSS.

Efficient evaluation of expressions is a solved problem.

Having conditionals would actually improve performance because you can use fewer rules.


I am not a CS expert, but this does not look like a full implementation of rule 110, nor is it even pure CSS (there is HTML involved).

What I see in the SO answer is an interface for Rule 110 with an additional set of instruction (written in a natural language) for the user to execute manually. So you can use CSS + HTML to create an interface for a Rule 110, which is then written in a natural language around that interface. The answer even states that (very relevant) caveat.

> [...] so long as you consider an appropriate accompanying HTML file and user interactions to be part of the “execution” of CSS.


SO comment:

> The formal definition (simplest) of Turing Machine is simply a tuple of states set, symbol set, initial state, accepting states set and a transition function. There is no crank in it. By computation we mean somebody needs to apply the transition function faithfully on the tape which is exactly like the clicking in this case. More formally, a model of computation can be viewed as a set of rules somebody needs to follow to do the computation. In that sense, I think CSS is Turing-Complete.

There is even a "CPU emulation" in pure CSS: https://dev.to/janeori/expert-css-the-cpu-hack-4ddj and pure CSS fetch: https://dev.to/janeori/100-css-fetch-and-exfiltrate-512-bits...


The web should always have been a programming language, with all the usual constructs available in both the display and markup layers.

But instead of a single unified standard library for the industry we got a sprawling, ludicrous mess of multiple poorly thought-out semi-compatible technologies, with an associated sub-industry of half-baked fixes and add-ons.


As always, hindsight is 20/20, but when you're living it, the half-baked decisions and add-ons are a product of you figuring it out on the fly. You don't have the knowledge of which proposal will solidify into an industry standard, and you don't know which vestigial implementations will be a nightmare for backwards compatibility down the line.

The context is also lost. Javascript was famously coded in a day or whatever and called 'javascript' not ecmascript as marketing to compete with Java. Besides that well known case there's presumably thousands of esoteric business decisions made back then which shaped the "sprawling, ludicrous" landscape, and which are now lost to time.

Yes, the web should have always been a programming language. And the flying cars of 23xx should have never used a z-debuffer doodad.


> with all the usual constructs available in both the display and markup layers.

I'm glad the transition to mobile web accelerated on more battery efficient GPUs was possible due to the model instead of Alan Kay's idea that websites should render themselves, where each website would have needed to be upgraded for GPU support for compositing.


Because modern UI toolkits like Flutter proved that UI should just be code, not separated into three different languages. In this case, adding conditionals can remove the need for js in some cases, which is good.

Considering how this is seems to be designed... I don't think that's the reason?

I mean looking at the mdn docs it's just a replacement for regular other syntax https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/V...

So instead of having a css for x which defines e.g. dark mode and light mode separately, you can now define it via a single css rule.

Where previously the "tree" forked at the beginning and attributes were set multiple times, depending on various criteria - now you set it once, and evaluate it's value depending on criteria

    div {
      background-image: if(
        style(--scheme: ice): linear-gradient(#caf0f8, white, #caf0f8);
        style(--scheme: fire): linear-gradient(#ffc971, white, #ffc971);
        else: none;
      );
    }

It looks like simple syntactic sugar to me

I should have read the docs for it then. Thanks.

Please provide evidence for that proof.

A gentle reminder: conditionals aren't new to CSS; @supports and @media are conditionals; so are style queries.

if() just codifies behaviors and hacks [1] developers were already doing.

[1]: https://lea.verou.me/blog/2020/10/the-var-space-hack-to-togg...


Yeah, code is data, data is code. Every Lisp programmer knows that.

If only Lisp had better presense in modern code editors. Emacs is not enough, especially on Windows where it is super slow. I think this is what actually stops newcomers to start with Lisp and not Python

> I think this is what actually stops newcomers to start with Lisp and not Python

What stops newcomers is knee-jerk reactions about the (lack of) syntax, it's scary to see something that doesn't look like Algol, because everyone who does mainstream programming uses Algol-like languages.

Introduce lisp to anyone who knows programming since earlier, and 99% of them will have a adverse reaction to s-expressions, before they understand what's going on. Once they understand, it makes a lot of sense obviously, but not everyone even has that kind of open mindset where they could understand if they wanted to.


My crackpot theory is that what stops newcomers is how unergonomic "(" and ")" are to type on typical keyboards. If mainstream lisp dialects used square brackets instead, we'd all be programming in it!

> If mainstream lisp dialects used square brackets instead, we'd all be programming in it!

You've almost convinced/nerd-sniped me to write a(nother) new lisp where we'll be using brackets for forms and lists and no parenthesis in sight. It's a wild theory.


It's just a reader macro, parse out quotes, other reader macros, then replace [ -> (, ] -> ) in the rest and throw into (read).

I find lisp to be a very non ergonomic language and am happy that python is the default.

Can you quantify that?

Let's just say that the weights of opening and closing parentheses do not cancel out.

I've had way more issues with proper indentation in Python and YAML than I have with parenthesis in lisp. Meaningful whitespace is about the worst idea I've seen in a programming language.

You would need to show that, including the parens, the average Lisp program requires more tokens than Python.

I'm not sure that's true. Because Lisp has a lot of facilities for writing more concise code that are difficult to achieve without the parens.


>> Just because one of the most widely used declarative languages start adding conditionals doesn't mean the whole world is turning upside down.

You need to look at a large terraform project.


I spent more time than I'm willing to on large Terraform projects. How exactly is this relevant to declarative vs imperative or even my comment at all? I don't see what the "gotcha" is supposed to be here.

> > The distinction between code, config and data is being erased.

> As as lisp programmer, I love it.

You make bad engineering decisions because you consider the advantages, but not the disadvantages. <https://news.ycombinator.com/item?id=29231493>


You make bad comments because I can't understand the point you're trying to make. I'm am engineer, I make choices based on informed tradeoffs, anything else would be sub-standard. Not sure why you think I only consider advantages, but I'm afraid asking you for clarification will just lead to more ramblings.

The disadvantages are in the post I linked to.

Alright, I guess I'll reply to that with another comment you can go and read then: https://news.ycombinator.com/item?id=38373081

Fun way of having a conversation.


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.


- Visual Studio project files are XML files that are interpreted line by line, and can contain variables, branches, and loops. Hell on earth.

They are badly copied Ant build files.

Ant came first, then when Microsoft redid the VS project format, they created MSBuild.

As incredible as it may sound, Ant is still easier to deal with than MSBuild.


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.


It sure did, you use conditions, no need for contrib.

https://ant.apache.org/manual/Tasks/condition.html

The else part is easily done by repeating and negating the condition.

Two other advantages of Ant that MSBuild lacks in a sane way to this day, are macros, and proper documentation.


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.

https://ant.apache.org/manual/ifunless.html


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.

Nice, I was basing my answer on what was there initially.

I always liked Ant, as I don't suffer from XML allergy.


The legacy version of MSBuild was really bad, but the modern MSBuild project files for .NET are actually quite concise and clean by default?

Only if you are happy with defaults and don't require any build logic.

Also you forgot MSBuild is used for everything, not only .NET.


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.


Horrible. Would’ve been much nicer if they’d reached for Scheme.

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.

Why doesn't the OCaml build system use OCaml?

You don’t want a language with non-determinism, arbitrary IO, impure functions etc. for build configuration ideally.

I guess the answer to your question is OCaml has unmanaged side effects.


They don’t know how good they really have it :)

what's even worse that schema uses extremely generic types with attributes denoting actual type.

Makes reading it even harder, and any possible constraints due to type safety go out of the window, so we get worst of both worlds.


Wesnoth the game also has that via WML. Looks very ugly and obfuscated.

CMake was never declarative AFAIK?

CMake today is effectively an eso-lang / Turing tarpit with some “modern” declarative conventions that people try to push.


"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.

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

What's the old adage? Software expands until it can send email?

> 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. HCL 2 has loops and conditionals. It is most definitely imperative.

This is not necessarily a problem except that they had to live in the original HCL v1 landscape which makes them awkward syntactically.


> 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.


I think cmake kind of needs conditional checks though.

Conditional expressions are declarative. For example, every template language worth its salt has conditionals.

A programming (i.e Turing complete) language requires recursion or a construct of equal power.


There is no recursive program that can't also be created by adding in more conditionals. It's turtles the whole way down.

You need unbounded recursion. Conditionals alone can’t do that. If you have some kind of conditional go to/jump if expression that’s a different matter.

You can emulate recursion with iteration and a push-down stack. If it doesn’t either recurse or offer both iterations (loops) and something that can act as a stack (at least an array or so) then it’s not Turing complete though. I have yet to see a stack or user-manipulable arrays in CSS.

You can't add all possible conditionals for every kind of loop/iteration, such as dynamic and infinite.

> The distinction between code, config and data is being erased.

This distinction never existed in LISP. Greenspun's tenth rule in action.


An if conditional doesn't make a programming language. You need recursion to have Turing completeness.

CSS already has all sorts of conditionals that are if() in disguise!

For instance a selector like .foo means "if the class is foo then select this style block'.

CSS is thoroughly condition-driven already.


You have to give it to CSS, it's held out for a lot longer than most.

not as much as you would think, the if statements don't really affect the css crimes scene because pretty much everything was already possible before

But then why was it added?

Because it's silly to rely on hard to read hacks when you could just add an if() function.

Yup. It's the same reason nested CSS was added. It doesn't really add any new functionality. Just makes your CSS neater (or way messier when misused). it's syntactic sugar really

We can blame von Neumann (et al) and his infernal architecture, where memory stores both instructions and data.

You can blame whoever invented the word "if", as soon as you can branch based on data you can just write an interpreter that turns data into instructions, no matter the architecture.

Or lambda. Or Forth commands. You can create an 'if' with few atoms.

You need more than if for Turing completeness though.

You need conditionals and loops. Recursion counts as looping.

Correct. You need at least 2 ifs.

You need unbounded recursion no?

That's actually what two ifs could be.

Was the case against the goto statement so good we can't mention it?

More or less, I meant how this would be inlined in assembly with a goto that could goto back where the branching originated from.

FWIW, you can make software that runs on Harvard architecture chips. They feature distinct address spaces for ROM and RAM. It's been a while, but it's how Atmel/Microchip AVR micros work.

https://en.wikipedia.org/wiki/Harvard_architecture

That said, I'm unaware of any programming language (outside assembler) that takes that split to heart in a higher-level way.


von Neumann did not invent the von Neumann architecture. Not even a little bit.

If you want to reason that the hardware is at fault, you should be blaming the Eckert-Mauchley architecture.


Not really, most of these configuration as code systems are not executed directly on the CPU but rather interpreted in which case a separate data-only memory would not stop anyone.

I hope I get to see the next thing after browser applications in my lifetime. I fully understand the advantages, but it has grown so fast and so wild I think it has to eventually fall down by its own weight and complexity despite its immense success.

It's not that the presentation layer need conditionals, it's that the layers under it have grown full of hacks that need more hacks to work around them, because the web was designed to grow documents, not programs.

If the web had been designed for applications in the first place, the presentation layer probably wouldn't need conditionals at all.


Those who don't use lisp are destined to re-invent it - poorly.

An interesting example is the Dhall language: https://dhall-lang.org/

It is a configuration language with general programming features, but it is decidedly _not_ Turing complete. It seems to sit at a sweet spot between "just JSON, no programming convenience at all" and "full-blown programming language with nontrivial toolchain".


Unfortunely too many people are afraid of opening parentheses being posited on the far left instead of the middle of the text.

It was shocking the first time I showed a lisp program to a (particularly "annoyed by everything") non-lisp developer who never apparently saw s-expressions before. Lots of knee-jerk reactions of "Oh my god so many parenthesis" and "How could anyone program like this?" while they sat there smug with their TypeScript codebase having more special characters, syntax and the same amount of parenthesizes, only because the opening parenthesis is one symbol to the left, instead of in the middle of the calls...


So why do people still design declarative languages?

OP is not being very precise (and in a way that I don't think is helpful). There is nothing imperative in an if expression. Declarative languages can be Turing complete. Declarative languages are a subset of programming languages.

Wishful thinking? Maybe they are tired of all this and want to make something good again, and so the cycle continues.

If you can mostly stick to the declarative way, it's still a benefit. No Turing-complete language completely prevents you from writing "bad" code. "You are not completely prevented from doing things that are hard to understand" is a bad argument. "You are encouraged to do things that are hard to understand" is a good one (looking at you, Perl).

It’s the cycle of newcomers to <field> looking at the existing solutions and declaring “this shit is too complicated, why did these morons design it this way? Check out my DSL that does everything and is super simple!”

Then time passes, edge cases start cropping up and hacks are bolted on to accommodate them. Eventually everything struggles under the weight of not having loops, conditionals, etc. and those are added.

After some time, the cycle begins anew.


> So why do people still design declarative languages?

Cost.

If money were no object, you would only hire people who can troubleshoot the entire stack, from React and SQL all the way down to machine code and using an oscilloscope to test network and power cabling.

Or put another way, it would be nice for the employer if your data analyst who knows SQL also knew C and how to compile Postgres from scratch, so they could fully debug why their query doesn’t do what they expect. But that’s a more expensive luxury.

Good software has declarative and imperative parts. It’s an eternal tradeoff whether you want the convenience of those parts being in the same codebase, which makes it easier to troubleshoot more of the stack, but that leads to hacks that break the separation. So sometimes you want a firm boundary, so people don’t do workarounds, and because then you can hire cheaper people who only need to know SQL or React or CSS or whatever, instead of all of them.


CSS is already a programming language long before if() function. You can even emulate CPU in it: https://dev.to/janeori/expert-css-the-cpu-hack-4ddj

“Now”? This has always been the case.

can someone interpret this as not a skill issue?

i want better, declarative, interactive, fast UIs

CSS is the best answer we have


Von Neumann devastated

dont be such a doomer

I've been observing this, off and on, for decades now. Is there an actual formal proof or law named after someone at this point?



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: