• madnificent@lemmy.world
    link
    fedilink
    arrow-up
    1
    ·
    1 hour ago

    Disclaimer: I stopped reading at 3/4 of the article and started scanning because it looks like lack of familiarity looking for a scientific explanation. Then scanned parts again for a lengthy response to clear my thoughts. That may be wrong and I’ve heard the complaints but my experience is different. Much of why it doesn’t resonate is looking at it from a different perspective by different experience.

    I mostly write javascript and some lisp and a smaller portion of python, ruby and others. The lisp parens are substantially easier for me to scan than the Java syntax for everything except nested function calls which start with many open parens. Common Lisp doesn’t do that often so it is new to me like the Java syntax was new to me back in the day. Good as an abstraction if that’s what you get to work with.

    I would love for my experience to be different because then I’d enjoy Java.more(with,all){ the(); weird(); return symbols();}. But I do not. Lisp groups things starting with an opening paren up to the closing paren. No scanning for the type of grouping like (, {, or [. Simple and consistent. Indentation is done automatically based on the meaning of the code and parens do the logical grouping (it works just like it works in sentences (but deeply nested parens are weird (like deeply nested routines (and we should limit that)))). There are places where it’s nice to escape from parens and Common Lisp allows for that so you can create a mini language without the parens (other lisps allow for that too). It is not created often but there are cases where that helps a lot.

    Both java and lisp wordings have their pros and cons. Deeply nested function calls are often solved with a macro to flatten that in Lisp. You don’t have that syntax flexibility as easy in Java but you can make other abstractions to lower the pain. In the end it’s finding the right vocabulary and structure to explain the problem and the solution. Each language has its own tools for that. Lisp has less familiar tools but you can do more with them. Once you know it’s hard to settle for less but if you don’t it’s hard to see what you’re getting bound by. In the same way lispers don’t always see the many libraries available in python, pythonistas don’t see the limitations the language itself imposes on them.

    The article, to me, thus reads as the statement “parens feel hard to read to me” searching for a reason other than “I have not seen it as often”. I have seen far more C-like syntax than Lisp but I’ve seen a good share of lisp too. Structure is more apparant to me in Lisp like languages. It is cleaner for words to be split by spaces than,for,them,to,be,split,by,commas in an argument list.

    In my opinion, Lisps are hard to read because they use eq and eql and equal instead of === and ==; and setq and setf and let instead of =; and car and cdr instead of first and rest. Historic wording. Also in elisp I find it hard to find the right function name. Yet in our configuration DSL most non lispers choose the Lisp syntax over JSON but they only liked it after the JSON syntax became an option too. Until then they wanted JSON.

    I have noticed a difference in reasoning about code. A lot of Lisp code reads like an outline where you zoom in to the relevant spot. A lot of Java and Javascript reads like a series of commands you execute in your head sequentially. The languages lend themselves to such code even though they support both ways of writing. Perhaps that difference was not experienced by the author?

    This comment is really just another person’s experience but it’s a different experience that what’s projected in the article.

    To come to the conclusions from the article:

    • Claim: “prefix notation puts parentheses further apart”
    • Reply: The parens fill space and the whitespace shows what belongs together, it is the closest consistent grouping and allows arguments to be read by space separated words rather than hard to read commas or by newlines if that helps scanning the code. In case the arguments (or a subset of them) warrant specific grouping, lisps offers support for that in a mkre integrated manner than Java does.
    • Claim: “formatting practices do not help to track parentheses”
    • Reply: use a formatter, it does that. Lisp code reads like a nested structure you walk rather than a piece of code you mentally execute line by line. We don’t format whitespace at the start of the line in Java either, right?
    • Claim: prefix notation results in more left-nesting
    • Reply: use a macro, currying, or any other macro structure when it helps. Turn the language into whatever you need to express the solution. If I have too many parens I rewrite the code just like you’d do in amy other language. Executing Food.buy().bake().serve().eat() is a cool Java DSL and reads nicer when written in lisp as (-> Food buy bake serve eat) anyways so why write (eat (serve (bake (buy food)))) if your focus is not eat. Though if it is eat then do write that. Or perhaps write it in the other direction with compose. So many options if that’s the sort of code to write.
    • Claim: Lisps lacks or discourages features that align the evaluation and reading order
    • Reply: I agree and it’s good. Other programming languages focus on the execution of commands following one another. Lisp encourages a functional programming style where the structure makes meaning easier to navigate through the code. Both are possible in a variety of languages. That’s a choice though, not a problem. It is trivial to use abstractions that neatly express such an order even when the code around it is not made for it (with-food-plan (buy) (bake :lightly) (serve :hot) (eat)) and the function calls will be nicely indented on newlines by your editor if that’s the best use of the space.

    On the advice:

    • advice: “order notation such that related tokens (e.g., delimiters) are as close as possible”
    • reply: Lisp has that and more than other languages. You can make up your own syntax when the problem warrants it. For example the loop DSL for looping over lists. It’s just not always the best to read.
    • advice: “use the shape of code to communicate grouping”
    • reply: yes. The opening paren starts the group, the closing ends the group. The meaning of a group is fluid but consistent. Use newlines and auto-formatting for easy vertical scanning of lisp code.
    • advice: use associativity to prevent nesting delimiters
    • reply: not sure but I think the answer are DSLs or macros when things get too bad. But sure, readable code is nice. Context switches are hard.
    • advice: design syntax and semantics to align reading with evaluation order
    • reply: I disagree here but it’s the difference of functional versus procedural thinking. Code needs to explain itself. The order of evaluation is what a computer needs, I need an order of understanding. If I can have my way I’ll optimize the code to have the main structure and reasoning up front and the details and exceptions at the bottom. I don’t care about negative numbers being a special case early on through an early return, I want the know what the general algorthm is first. Some disagree. Evaluation order is super important for computers but I don’t care how my SQL query is executed, I care to understand it and for it to be fast enough. Otherwise I’d use a different technogy.

    Not mentioned in these are symbols such as a < b versus (< a b). I like the former better. But a < b < c has more room for interoretation than (< a b c) for me. An infix macro can easily solve the problem to read as (. a < b) and we can go further too.

    So, much of this is probably written with the best intentions and a real experience. I can see it being true for their point of view with their history. This is also just a quick thought and response tk put things in persoective for me. A response through a different lens with a different experience.