Live data from Hacker News

Why I still Lisp

mendhekar.medium.com

41–50 of 240 posts

Re: Why I still Lisp

#41
post #38
post #17

> I have never had a static type checker (regardless of how sophisticated it is) help me prevent anything more than an obvious error (which should be caught in testing anyway). Obvious in retrospect is not the same as obvious. And such errors happen all the time, the same way without syntax checks typos happen all the time. And "caught in testing" is 2 extra steps removed from caught immediately by the syntax checker…

> What thing that violates a type check would be "perfectly fine to do"? One good example is where you might treat records or "product types" as maps Let's say you want to write a function that can capitalize all the string fields in the object passed in. In a dynamic language, you could map over the values and apply capitalization trivially. It would be a one-liner. In a static language, you'd have a few options, bu…

It's pretty easy to do in Typescript and loses no type safety (without needing to assert or cast anything)

    type T = { [k: string]: number };
    
    const t: T = {
      one: 1,
      two: 2,
      three: 3,
    };
    
    const makeUpperCaseKeys = (v: T): T => {
      const keys = Object.keys(v);
      return keys.reduce((p, c) => {
        const key = c.charAt(0).toUpperCase() + c.slice(1);
        return { ...p, [key]: v[c] };
      }, {});
    };
    
    console.log(makeUpperCaseKeys(t));
    // {
    //   One: 1,
    //   Two: 2,
    //   Three: 3
    // }

Re: Why I still Lisp

#42

> What improves (and guarantees) software quality is rigorous testing. To deliver high quality software, there is no other solution. This is 100% false. You can’t inject quality into a bad design via testing. You can’t guarantee quality or correctness through testing. Testing is the second worst place to find errors. You get a MUCH higher roi by producing thoughtful written designs and getting them peer reviewed. And…

Testing tends to validate design from the point of testability. If it feels like the code is resisting testing, that usually ends up being an indicator of bad design (though not always vice versa).

This is where we are now. We know how to make testable designs, since effort has been put towards it.

What we lost is being able to distinguish good vs bad designs in other key aspects. One indicator I use is the number of test cases that are needed for covering. A poorly separated design will need to test many combinations having not isolated the factors.

Re: Why I still Lisp

#43
post #8

I think Lisp is going to live forever as a niche tool for people who "get" it. I use Clojure on a daily basis. Not necessarily because it is best Lisp, but rather because I am working with Java applications and being able to reuse the same Java code I have already developed is a huge boon to me. If I was able to choose, I would be using Common Lisp. The way I use it is to quickly develop adhoc tools and PoCs and more…

Honestly I’ve seen just as many disastrous codebases written in highly structured, statically typed languages. Any language with intrinsically interesting features tends to attract inexperienced (or just bad) developers who don’t appreciate the tradeoffs of their tools and design decisions, and think the tool is a panacea. This leads to disastrous codebases, and is not at all limited to lisps or dynamically typed languages. I can point just as many disasters written in statically typed languages, and they tend to be the “interesting” ones with fancy type systems in the ML family like Scala, Haskell, and Rust. (I am a huge fan of both Lisps and ML-family languages.)

I think the important point is to be very aware of this risk and consider it when making technical decisions. Sometimes the tradeoffs are worth it to use a powerful tool, depending on the team and the product, and sometimes you’re better off using boring tools that won’t distract smart engineers.

Re: Why I still Lisp

#44

Wow. I thought I recognized that name - the author of this post interviewed me for a job several years ago when I was first learning how to code. It didn't work out as I was waaaaaaay too junior at the time but I'll always remember that interview fondly. My background was more in math and my interests were in PL theory, so he quizzed me on the lambda calculus, and turned me onto Essentials of Programming Languages by…

You should apply again, the company the author works for is looking for people “Proficient in Java and C++ with strong object-oriented design skills”.

Re: Why I still Lisp

#45

> Languages based on the λ-calculus make it really easy to “play back the code” in your head. This really depends on the expression.. I've seen behemoth expressions such that you have no choice but write down intermediate results, or start explicitly breaking it down into sub-bindings so you could step through the code. And yes, you can usually step through subexpressions in the debugger, but if you have to debug any…

> I also noticed there is a tendency in lispy languages to avoid introducing variable bindings just for the sake of naming the subexpression, because it often comes with a `(let ((name (subexpression))) rest-of-code)`, which also results in extra tabulation for the rest of the body. Compare with variable introduction in languages like python/js/c++/rust, etc., where such thing wouldn't cause touching the rest of the…

When would shadow binding help create more readable code? (I agree with everything else in your post)

Re: Why I still Lisp

#46
post #38

Earlier quoted context omitted.

> What thing that violates a type check would be "perfectly fine to do"? One good example is where you might treat records or "product types" as maps Let's say you want to write a function that can capitalize all the string fields in the object passed in. In a dynamic language, you could map over the values and apply capitalization trivially. It would be a one-liner. In a static language, you'd have a few options, bu…

It's pretty easy to do in Typescript and loses no type safety (without needing to assert or cast anything) type T = { [k: string]: number }; const t: T = { one: 1, two: 2, three: 3, }; const makeUpperCaseKeys = (v: T): T => { const keys = Object.keys(v); return keys.reduce((p, c) => { const key = c.charAt(0).toUpperCase() + c.slice(1); return { ...p, [key]: v[c] }; }, {}); }; console.log(makeUpperCaseKeys(t)); // { /…

That's great! Are you making the argument that I won't be able to find an example where doing some transform in a type-safe way is awkward in TypeScript, or just that this one example can be done in TypeScript?

By the way, my example was meant to be more like User -> User where there are some string values and some other types of value. You want to do the transformation in a generic way, but still have the type-safe object come out the other end with all the expected keys.

Re: Why I still Lisp

#48
post #17

> I have never had a static type checker (regardless of how sophisticated it is) help me prevent anything more than an obvious error (which should be caught in testing anyway). Obvious in retrospect is not the same as obvious. And such errors happen all the time, the same way without syntax checks typos happen all the time. And "caught in testing" is 2 extra steps removed from caught immediately by the syntax checker…

> What thing that violates a type check would be "perfectly fine to do"?

A typical example, in dynamic programming languages, is to treat numbers as strings and vice-versa; evaluate lists in boolean context; and so on.

> If value is not a numeric type, square is not going to be happy. And that's the case with most (all?) dynamic code.

Some programming languages will be glad to accept a string and treat it as a number -- see Duck Typing (https://en.wikipedia.org/wiki/Duck_typing).

Re: Why I still Lisp

#49
post #8

I think Lisp is going to live forever as a niche tool for people who "get" it. I use Clojure on a daily basis. Not necessarily because it is best Lisp, but rather because I am working with Java applications and being able to reuse the same Java code I have already developed is a huge boon to me. If I was able to choose, I would be using Common Lisp. The way I use it is to quickly develop adhoc tools and PoCs and more…

> You have to be really incompetent to write a typical Java service in a way where it is no longer possible to develop it at all, Disagree. Anything can be made write-only. > but in Clojure it is just enough to get couple of people that are intelligent enough to write macros but not experienced enough to understand the dangers of lack framework forcing the structure of your application. Sentence doesn't parse on mult…

Agree with him. Coming from an OO background I always cringed at the 15,000 line classes with 2000 line methods. Side effects everywhere.

In my naivety I thought functional programs with their emphasis on lack of side effects could help. I then encountered a project that was totally functional but written entirely by people with no functional experience. The entire application was unmaintainable even in the most basic parts.

> Doesn't parse

> Macros

Macros modify code structure at runtime so obviously that is fraught with danger.

> Framework forcing structure

Lisp languages in general have a do it yourself attitude not found in others. While there are frameworks it's common to find projects that have invented from the ground up entire web frameworks, db access and orm.

Imagine if every project you encountered in Java reinvented Rx Java, Hibernate, and Spring.

Re: Why I still Lisp

#50
post #9

> What improves (and guarantees) software quality is rigorous testing. To deliver high quality software, there is no other solution. This is 100% false. You can’t inject quality into a bad design via testing. You can’t guarantee quality or correctness through testing. Testing is the second worst place to find errors. You get a MUCH higher roi by producing thoughtful written designs and getting them peer reviewed. And…

I agree that testing is not a panacea, but I also don't think it is completely divorced from design. I see testing and design as cooperative processes, I agree that design is almost always the highest yielding process in any non-trivial program, but I think of testing almost as a design phase that tries to invert the design to look for weaknesses.

I suspect what he’s referring to is the fact that so many people think that, because they have 100% code coverage in their tests, they have quality software. I’ve seen so many times a team claim that with pride when it’s brutally obvious to anyone who looks that the product is broken. They just don’t seem to be able to reconcile that problem when asked about it.

What you test matters every bit as much as how much you test. Tests require thought and design as well. Too many developers don’t seem to understand that.

Post reply on HN