DEV Community

Discussion on: Why do we write JavaScript like this?

 
wulymammoth profile image
David • Edited

My point is that your examples are identical except for having hidden or not hidden the implementation of the procedures from immediate inspection.

Hard disagree -- please, do not try to shoe-horn this statement into a discussion about imperative and declarative programming. That statement is what's described as an abstraction.

The consequence is that your definition of 'declarative' becomes 'a procedure with a hidden implementation'.

Thus making all procedural programs declarative by simply moving the bodies of the procedures into a hidden library somewhere.

This is very reductionist -- by your definition, style isn't even relevant, and "expressiveness" matters little. Case in point -- recursive function to produce the n-th Fibonacci versus an iterative non-recursive Fibonacci function. They both produce the same result. The recursive version makes excruciatingly explicit the relationships between arguments whereas the iterative version is less so being decorated with mutable variable set-up and a boilerplate loop.

This means that the examples can be transformed from procedural to declarative and back again depending on where the procedures you call are defined.

You may believe this to be absurd, but you have to understand that this is your and specifically only your worldview. I will say, though, if you go back up and visit the Stack Overflow link, there will be people arguing similarly to you, but it is in the minority. If you're looking to relish in your own definition, it's a worthwhile visit. Me? I try not to engage in that behavior...

That said, thank you for sharing a link to my alma mater -- what you've quoted actually supports my original point more than yours:

  1. "our programs are explicit directions for solving a problem; the problem itself is implicit in the program" -- simply read as, "step-by-step procedures to produce a desired result for a given problem"
  2. "declarative programming turns this around" -- read as, "result to the problem"

I'm unsure how you read that differently than I. You're absolutely correct that the quote you've shared gets at the "central concept" as you've described. It re-iterates every single response that I had shared previously

In a declarative system, we describe the problem in sufficient detail that a solution can be automatically discovered -- the problem is made explicit; the solution is implicit.

I'm going to highlight that you're literally building your own worldview -- this is your "system", whereas I'm talking about a paradigm and/or style that I take no credit for. There are no hard boundaries on such things only a generally agreed upon subjective (yeap) blurry/fuzzy understanding of it. This explains why there's people going back and forth on it on the Stack Overflow thread like you and I are. But the generally agreed upon idea about what declarative (style [not your system]) is holds true.

Your highlight of my example employing reduce and labeling it imperative is just plain wrong IMO. I'm going to hard disagree here. By that measure, writing a SELECT query in SQL is imperative style. Your line of reasoning is orthogonal to what is written both in Wikipedia and academic literature (the one that you've shared) from the EECS program at UC Berkeley.

I'm going to hard disagree with your assertions that my examples are wrong. It may not speak to you, but you've not managed to change my mind. The only thing I got was someone trying to push their worldview on someone else, illustrated in you saying that my functions are the same. Yes, they produce the same result, but they are written in a completely different style and "imperative" versus "declarative" is about style, and I think you'd be hard pressed to find someone disagreeing with the following being an adequate idea about what the differences between the two styles are:

// you literally have to read the entire procedure to understand what's going on
// discoverability is here, but at what cognitive cost?
function main() {
  let left = 0, right = str.length-1;
  while (left < right) {
    if (str[left] !== str[right]) return false;
    left++; right--;
  }
  return true;
}

// declarative - what's the cognitive cost?
function main() {
  return str === str.split('').reverse().join('');
}
Enter fullscreen mode Exit fullscreen mode

If they're the same, you've just contradicted yourself. The second version literally describes the relationship that you went out of your way to highlight to me in a roundabout way to try and impose your worldview. Which one more so exhibits the "...sufficient detail that a solution can be automatically discovered..." (literal quote)? I'm going to come back to the idea that you didn't show a preference for the latter, because it wouldn't support this world that you've found yourself in that you've created for yourself. I'm willing to bet that most people, and especially beginners would prefer the latter to describe what a palindrome is rather than the former, but you wouldn't admit that, would ya? If they're the same, I beg not to program or review code written by those that see no difference. Maybe I'm dumb and lazy, but I prefer not to need to signal my smartness by telling others that I can read through cryptic expressions in the presence of alternatives.

That said, you've not convinced me beyond the shadow of a doubt that my understanding is incorrect, but I'll acknowledge and admit that you've made it abundantly clear to me that an alternate view of the paradigms (not your system) exists.

My final points (rhetorical questions):

  • why invent DSLs or SQL since we can all write line-by-line instructions for the machine?
  • why have any methods or functions in programming languages at all?
  • why don't we just dump everything in a single file?
  • why do programmers concern themselves with style?

Imperative and declarative programming are really about style and why do programmers care? The explicit reason is expressiveness - does it adequately describe and express what we seek to accomplish AND/OR the relationships between arguments/inputs such that I don't have to concern myself with the details at a granular level. The latter is more in line with what you've suggested, but they are not mutually exclusive. In fact, functional programming languages, in which some of have its roots in lambda calculus is all about this as I'm fairly sure that you're aware of. Functional programming in most languages, when we squint, look just like formulas with a label slapped onto them... a declaration, so to speak

Thread Thread
 
pentacular profile image
pentacular

Let's consider your reduce example.

I think you've claimed that this example is declarative?

const result = array.reduce(add);

Is this example also declarative?
I think that you'll have a really hard time justifying a 'no' here, but let's see. :)

const result = reduce(array, add);

How about this one?
You've classified this kind of thing as non-declarative earlier, so it'll be interesting to see your decision this time.

const reduce = (array, reducer, state = 0) => {
  for (const item of array) {
    state = reducer(state, item);
  }
  return state;
}

const result = reduce(array, add);

Or this one?

const sum = (array) => {
  let total = 0;
  for (const item of array) {
    total = add(total, item);
  }
  return total;
}

const result = sum(array);

And one last one -- declarative or not?

const result = ((array) => { let total = 0; for (const item of array) { total = add(total, item); } return total; })(array);
Thread Thread
 
wulymammoth profile image
David
  1. Yes
  2. Yes
  3. reduce is implemented in an imperative style, but the usage is declarative
  4. Same as 3 — implementation is imperative and usage is declarative
  5. Imperative

The result statements each have a declarative expression, but your reducers are written in an imperative style. Pretty much all your examples are declarative with the last example as the exception, where you’ve baked an imperative reducer into the IIFE. This is precisely why I state that it isn’t mutually exclusive in a paradigm-less or mixed paradigm language like JavaScript. Functional programming to functional paradigm is declarative programming to declarative style.

I don’t think you’d disagree that all your result statements simply look like assertions of the relation between the what’s on the left hand side and what’s on the right hand side (like in math). At some point or another the implementation whether remaining in the domain of a high level language or not will evidently have imperative code or instructions (the procedures). Some languages make it easier to express things in strictly one paradigm.

This whole discussion could’ve been about whether JS is a functional language. Where we disagree is really on premise — you’re talking about purity and I’m not. Just like the folks that would argue against Scala being a functional language. But here I am stating that it just has functional facilities, but yet someone refuses to hear me and assumes that what I’m asserting is that the language is functional. This is absurd. Lol.

Just let me be wrong if it’ll make you feel better. I’m not here to stroke anyone’s ego. I think it would’ve saved both you and I time if you gave examples of declarative JS from the outset. But scrolling back, I can’t find a definitive example illustrating the stark difference between imperative and declarative JS in your eyes. You went and made an attempt to elucidate with Prolog that is a classic declarative language. It would help many others if you showed us (even contrived examples) of declarative JS rather than speaking in the abstract.

Show us the light, Yoda! For we are all padawans.

Thread Thread
 
pentacular profile image
pentacular

Thanks -- that was useful.

The only difference between the examples was the degree of procedural abstraction.

Which backs up my theory that that is what is being confused with declarative programming.

This could have been about if JS is a function language if you wanted to confuse declarative programming with functional programming, but that would be regrettable in my opinion.

Although it's understandable, since a functional style in a procedural language is mostly about leveraging procedural abstraction.

If you can find an example of declarative programming in JS that isn't actually just procedural abstraction, that would be great.

Something which, for example, declares the problem to be solved, rather than specifies how to solve it, regardless of how much procedural abstraction that solution involves. :)

At this point I'm interested in understand how some people have come to think of declarative programming like this -- once it is understood it may be clear how to correct it.

It concerns me because, much as "moron" was once a meaningful technical term that has been reduced to a meaningless schoolyard insult, it seems that "declarative" is being watered down into something similarly meaningless, and I find this disappointing.

Thread Thread
 
wulymammoth profile image
David

I mean, a functional style doesn't mean it's not "functional" (programming)...

The only difference between the examples was the degree of procedural abstraction.

I don't disagree here. But hey, we're not all mashing machine code, so we're all operating at one abstraction (as leaky as they may be) or another.

Furthermore, specificity matters only in particular contexts. As human beings, we can't help but make associations -- we constantly hang leaves upon existing branches (even if seemingly the wrong one to someone else at the time). And while on the one hand, precision matters... but mostly when that precision would result in the wrong result or idea. This is why I'm so annoyingly pedantic at times. But here, in the absence of a succinct phrase to describe the difference in writing boilerplate code versus non-boilerplate code, I believe "declarative" (in spirit) is an apt way to describe what's going on if we are in agreement that code readability is the context. At least it's a commonly used way. I don't think we need to course correct here, but rather people familiarize themselves with etymology, such that it avoids misrepresentation in the wrong context.

While I agree with you on both "declarative" and "moron" now, we must understand that language, too, evolves. I think it's a healthy mindset to also be an observer as it evolves and step in from time to time, like you have, to provide some historical context. It's hard, I know, as someone who used to frequently argue with people about the "correct understanding" or "correct meaning" of something, before someone told me to not be so one-dimensional and accept both. Funny, but it's definitely made things easier in some respects, though, more complex and/or intricate which we often fight against. But hey, we're engineers/developers and if we don't do it, we shouldn't expect others to do it, too as we continue to abstract over a complex world

Thread Thread
 
pentacular profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
pentacular

At this point you can't speak meaningfully about declarative programming. :)
How long before you can't talk about functional programming?
Until everything is one vague blur.
Spinning in an echo,
Chamber?

Thread Thread
 
wulymammoth profile image
David • Edited

Conflation is a valid concern, but if we believe the best in people, and there are almost always truth seekers among us, we will eventually discover the most minute of differences. We use analogies all the time and they’re okay even if not perfect analog so long as we acknowledge that. It’s really how people learn.

Blurred concepts and terms will always have people to clarify them but I wouldn’t lump that into echo chamber-ism. It is such only for those that spend an entire career in one ecosystem and never step out of their comfort zone to have their fuzzy ideas challenged, conceptualized differently, or placed against in the context of a different domain.

When I think echo chambers, I think JavaScript and its immense cargo culting of front end frameworks and libraries. It’s almost taboo to speak out against React without hearing the common talking points and refrains that its large community of users have adopted to combat dissenters or people suggesting other libraries or frameworks. Dan Abramov of Redux/React and Facebook engineer spoke out against a YouTuber that kept making fun of Angular. I say this because at least with echo chambers it’s easier to spot them and avoid them.

We also can’t teach anyone that isn’t ready to learn, and we tend to forget that some of the smartest people are the most hard-headed and often feel attacked if something or someone challenges their long-established beliefs. It causes tons of cognitive dissonance and often bars them from further learning. I recently had a discussion asking my cousin, a former Google engineer and heavy JS user if he’s checked out SvelteJS or some of the other micro-libraries, and I simply got, “why subject myself to a lack of support?” (not verbatim). That’s classic “straw manning” (just because of this, then it must mean that). What he actually meant was, “I just need to build something and it’s what I’m familiar with and don’t want to spend the time considering all the options right now”. That would be a much better premise to start on and would be fine, but we all know that people don’t say that, because we don’t want others to misconstrue that as being lazy. I’ve been in enough of these conversations now to be able to read between the lines and avoid an entire discussion on trying to share something I find fascinating to someone else when they’re not looking to have me do that.