Why imperative code is worse than functional code

But the Python solution isn’t even correct.

bad = [{"name": "Addition / Subtraction"}, {"name": "Multiplication / Division"}]
sections = [
    {
        "title": "Getting started",
        "reset_lesson_position": False,
        "lessons": [
            {"name": "Welcome"},
            {"name": "Installation"},
        ],
    },
    {
        "title": "Basic operator",
        "reset_lesson_position": False,
        "lessons": bad,
    },
    {
        "title": "Advanced topics",
        "reset_lesson_position": True,
        "lessons": bad,
    },
]
section_counter = 1
lesson_counter = 1

for section in sections:
    if section["reset_lesson_position"]:
        lesson_counter = 1

    section["position"] = section_counter
    section_counter += 1

    for lesson in section["lessons"]:
        lesson["position"] = lesson_counter
        lesson_counter += 1

print(sections)

Will give the lessons in the second section the wrong number

3 Likes

Ah, clever example! (And to save others the investigation, it’s because the same mutable dictionary is iterated over, and modified, twice).

I didn’t say it was correct, only it was easy to check. You prove my point :wink:

2 Likes

I think this is main argument in favor of why some good OOP practices (like encapsulations) are not universal principles but only there to solve some problems due to mutability and therefore less relevant for languages where things are immutable by default.

Great counter-example! Also quite plausible that you’d have a basic coverage over some sequence of topics, then Advanced coverage over exactly the same sequence. For each Advanced area you might start "Recap", "Installation", ... to load some extra packages.

(I was going to ask back on the O.P. with its talk of “key-value” whether the key was ‘lesson name’ or the combo ‘section name+lesson name’.)

This is a bit disingenuous because the Python solution works on a Json input and if Json as been parsed from a file (which I am pretty confident that it is what’s happening in the real project). There is no way in the Json format to describe to reuse and share data.

Would you say the Haskell version does not work if it was accidentally given a cyclic list?

It does work! It would return a lazily-consumable infinite list :slight_smile: EDIT: although on trying it I discover that infinite input seems to require the lazy State monad :frowning:

1 Like

There are a lot of Haskell versions, so I’d need to know which one you’re referring to, but I think a lot of the solutions would give an acceptable answer, especially if what you’re doing is serialising to something like JSON and streaming it.

The original problem is meant to work on a list of sections, where a section is a key-value data structure containing a list of lessons, where a lesson is also a key-value data structure. Nowhere in the problem statement is JSON mentioned, except for

Here is an example input (formatted in JSON for convenience):

and

The output should be (formatted in JSON for convenience):

I will agree that the code as given will probably work for whatever the intended use-case was, but “containing two references to the same object in a collection being traversed while performing mutation” is not some really obscure edge case, it’s something that occurs all the time.

2 Likes

I agree (thus the “a bit” at the begiining of my comment).

…and all of that is “a bit” of a:

Why? Because the questionable use of simple(ton) examples has probably occurred before:

  • no doubt there were various snippets of assembly code which purported to show the superiority of assembly over that “new-fangled” Fortran and LISP stuff.

  • there probably were analogous snippets of code showing the superiority of goto over structured programming.

  • and one can only imagine all the snippets of code purporting to show the superiority of manual memory manglement management over GC!

They are all examples of “storms in teacups”…the teacups found in child’s-toy dollhouses!


Getting back to the actual topic of this thread:

Mutation.

While The Anatomy of Programming Languages also nominates sequencing as being a problem:

  • arbitrary sequencing but no mutation: confluence.

  • arbitrary mutation but no sequencing: nondeterminism!

Standard ML and OCaml both illustrate this point - at first glance, definitions in both languages have little to no resemblance to the rambling sequences of statements found in the likes of Pascal or C. But that lack of visible sequencing is irrelevant: due to the relative ease of access to mutation both provide, Standard ML and OCaml are also imperative languages.


Alright, so what about Haskell and its use of seemingly-inexplicable interfaces?

…for something better (or a proof that none exists, analogous to that for the Entscheidungsproblem).

2 Likes

This is one of my favorite things about functional code. In imperative code, in order to understand the value inside a mutable variable, you must read its entire scope. In functional code, a value’s expression is all you need to understand it. You can navigate to its building blocks’ definitions with ease thanks to LSP too, though I wish that the Haskell language server had a way to also navigate to libraries’ definitions as well.

I don’t use LSP but I use vim and haskdogs which generate tags for all you dependencies, it’s amazing. Also using stack hoogle --server launch a server showing for all libraries (and your own) the doc but more importantly the annotated code (with hyperlink to definition). You can also define quite easly a mapping in your text editor to a web browser to the hoogle definiton of the word under the cursor.
(I don’t know if there is a cabal equivalent).

1 Like

I also use vim and I’ll try haskdogs, it seems like exactly what I need, thanks!

Perhaps the more modern question is not “imperative versus functional”, but formal syntactic code languages (imperative, functional, logical, …) versus machine generated computations (ML, GPT, etc). If one can give plain English descriptions, some AWS keys, and get back “a system”, the languages and transfer formats in-between may lose relevance. That’s if you take the MIT view, anyway. (See Sussman on why they switched from Lisp to Python.)

If, indeed.

As noted memorably by Dijkstra, plain human languages would only suffice for “trivial” usage (depending on how “trivial” is defined). For more rigour, a more precise and therefore restricted language is needed.

3 Likes

I can only hope that an A(G)I smart enough to write complete software from plain English descriptions will understand that it needs to explain its work and thus present the “system” using an easy to understand (e.g. functional/denotative) formalism.

The MIT view is very disappointing. They observed a problem: nobody understands software any more. And then they just decided to give up and stop teaching how to understand software. That seems like the opposite of what society needs.

2 Likes

I agree. I don’t know the MIT view but it would be silly to stop developping formally precise languages just because a few programming tasks can be described using ML. That would be as silly as to stop developping mathematics and proof-theory just because sometimes we can get by using only statistics.

According to @chrisdone, the replacing of Lisp with Python at MIT seems to be related to Java replacing Haskell at the University of Texas. So despite it usually being the more obnoxious of the two, the superficial simplicity of imperative code (and programming) continues to beguile.

…and seems destined to remain a novelty as more and more imperative “dance halls” appear, despite the goad of parallelism.

I don’t think it is related in this way. See the explanation from Sussman in the video that Chris linked above. Sussman is essentially saying that it became impossible to fully understand software systems as the software (and hardware) grew exponentially from 1980-1997 and so they quit. They transitioned to a “poke at it until it seems to do what you want” approach. The reason Python was chosen is simply because it had the largest robotics libraries at the time.

the last decades have shown in the Western world a sharp decline of people’s mastery of their own language …

Yeah, miserable old s.o.b.s have been complaining about the yoof since – oh – Socrates’ time.

We still have to get over the bump from an enterprise’s own description of what it wants (which might use some formal tools/notations, but won’t be in a programming language) to a ‘proof’ (I’m joking) that this particular suite of programs delivers to that description.

1 Like