Live data from Hacker News

Why I still Lisp

mendhekar.medium.com

181–190 of 240 posts

Re: Why I still Lisp

#181
post #136

Earlier quoted context omitted.

> What thing that violates a type check would be "perfectly fine to do"? Here is an example limitation of typescript's type system that I routinely run into while developing real code [1]. I look at it like this. If you consider all possible programs, some are invalid, some are valid, and some are valid and useful. A type system's job is to reject as many invalid programs as possible while accepting as many valid pro…

Sometimes the type system is forcing you to think in terms of what it is that you are passing around. In this case, getEmails() isn't expecting a group of students or a group of faculty, but rather a group of people that can be emailed. You can introduce an interface of that type and have it inherited by both Student and Faculty and use that in the method for clarity and type-safety without over-relying on union type…

I appreciate the effort you’ve both put in to concrete examples. I think yours gets to a point that I haven’t often seen stated. You’ve named your interface Person, but perhaps even Emailable could serve the purpose. The problem is that you had to name it. Naming well is hard, and I believe strong type systems often create a need for more names. It’s a cost I don’t often see considered in the tradeoff.

Re: Why I still Lisp

#182
Here we go again. Another LISP fan boy articles. And the usual HN responses/arguments. LISP is and has always been a niche language with limited impact on the world. It was fun to learn and play with but I don’t want to use it for real work. A few will disagree. That’s fine. You do what you prefer and best of luck.

Re: Why I still Lisp

#183
post #21

The author of the article, Anurag Mendhekar, is one of the authors in the original paper on AspectJ [1], which introduced Aspect-Oriented Programming. The origins of AOP are in Smalltalk and the Meta-Object Protocol, I think. I really liked Aspect-Oriented Programming, despite its great issues with mutually interfering aspects etc. I wonder if it will make it as a big paradigm, but I hope it does. [1] https://www.cs.…

I have used aspectj in somewhat unhealthy dose in my project. Mostly for reasons not even intended as an use to aspect. We have to work on giant configs reified as giant java objects. And I have was able to collect enough metadata about the code using aspects and keep them tied to the live objects in such a way that I was able to simulate creation, transformation and move of method calls. yes, a byte code parser and…

> not a hacker's language but ecosystem comes with hackers toolbox

I have always loved calling Java the mullet of programming languages for this reason -- a shallow investigation reveals a GC'd OO language meant for getting down to the business of some boring insurance or finance apps. Around the back, it's got enough dynamic features for a full party.

Re: Why I still Lisp

#184
post #43

Earlier quoted context omitted.

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 lan…

I 100% agree that disastrous codebases are every bit as likely in other languages. But it somehow hurts more in a lisp. I think that the syntax really is the culprit. In a language like Java, the Byzantine syntax and semantics enforce some minimum level of structure on the code. It's not much, but it's something, just enough to give an experienced programmer a few extra heuristics they can use to make sense of what t…

> you can't quickly tell whether some thing you're looking at is data, a function, or a macro, or what

First of all, there are elements that are unmistakably data: "abc", 123.0E-13, #(1 2 3), :keyword :symbol.

The ambiguity is that a compound expression headed by a symbol could be anything. In order to to be fooled, we just have to read the entire top-level form from the outside in.

Well, that's what language is. For instance, if I'm saying "Bob believes that the Earth is flat", but you only catch my speech starting on at word "the", it looks like I'm saying that the Earth is flat. To get the real meaning (the belief is attributed to Bob), you need the whole sentence.

Or, until you hear the "nai" at the end of a long Japanese sentence, you have no idea that it's going to be negated.

Re: Why I still Lisp

#185
post #103
post #99

Earlier quoted context omitted.

I think it is important distinguish the necessary from accidental complexity. Macros are typically more difficult to understand but if done well that would be because they are sinking complexity from a bunch of code. For example, if a macro implements variations of repeating construct, you are removing those variations from your entire codebase and putting complexity of dealing with that into a single macro. Now, the…

> sinking complexity from a bunch of code Sometimes macros provide domain-level constructs. This creates very dense code - which can improve code understanding. One thing I would recommend to put extra effort into macros, especially with these aspects: One should write documentation what the macro expects and what it does. This way this has not to be inferred from reading the often quite complex code. Document the im…

With those things in place, macros can absolutely be a net positive for code understanding. And if I saw that being done with any regularity at all, that would be great.

As I get older and more jaded, though, am coming to think that, in an office setting, it is a mistake to choose a language is optimized for maximizing the effectiveness of a thoughtful programmer. It's much more valuable to minimize the damage that can be done by a careless programmer.

One of the most sobering realizations of my career was that the most effective way to become your team's 10X programmer is not to work in a way that lets you be 10X more efficient than your colleagues. It's to work in a way that forces your colleagues to be 10X less efficient than you.

Re: Why I still Lisp

#186

Earlier quoted context omitted.

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.

I have noticed another indicator of good design is how easy it is to add specific fixes/features without having to think too much about how many places you'll need to make changes. Interesting point about no. of test cases. I tend to end up with several combinations because I prefer to focus on integration tests more for crud-type applications (a test configuration type/class comes handy in such scenarios).

Re: Why I still Lisp

#187

Earlier quoted context omitted.

> And such errors happen all the time, the same way without syntax checks typos happen all the time. No they don't, because syntax is richly varied and nested, even in programs whose "type story" is bland. For instance, in some numerical program, there are lots of opportunities to make typos in the syntax, but the type of just about everything may be either float or else array of float (possiby string , if it has any…

> Note that functions like sin and cos have exactly the same type signature, yet it is disastrous if you mix them up. Static type checking doesn't help. I agree with you. I am hard-pressed to imagine types (where it's static analysis or anything at all) offering any help in catching inadvertent swaps of sin and cos. One thing that types could help with is avoiding confusion between e.g. radians and degrees. Even this…

Unit tests, maybe not, but it's commonly accepted even in statically-typed communities that property-based tests are practically as good to guarantee properties which a stronger type-system would catch.

For example in Haskell almost all of the abstractions (Monoid, Semgroup) use property-based testing rather than proofs.

Re: Why I still Lisp

#188
post #87

Earlier quoted context omitted.

You might be one of those experienced developers who has gone through their entire career without ever meeting a well designed, beautifully architectured application, and therefore concluded, sensibly, that all real-world applications look like shit if you look inside, and you seem to have come to believe that this is the only possible way. I have a different experience. Code that is well designed makes mistakes look…

> a well designed, beautifully architectured application I've seen everything during my career, bad code with lots of bugs, bad code running stable. Nice code full of bugs, and nice stable code. The reason something was stable was never how the code looked, but how battle tested the product was. You will learn, don't worry. Plus, at a certain point, it's about tradoffs and compromises. I would love to see highly opti…

> I would love to see highly optimized code that is easy to read.

That that's a trade-off is [just] a deficiency in our programming languages and tooling around them. As we evolve are young field (and if you've had a long career, then it is even younger to you!) I trust we will find more and more highly-optimized code that is easy to read.

Re: Why I still Lisp

#189

Earlier quoted context omitted.

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.

I have noticed another indicator of good design is how easy it is to add specific fixes/features without having to think too much about how many places you'll need to make changes. Interesting point about no. of test cases. I tend to end up with several combinations because I prefer to focus on integration tests more for crud-type applications (a test configuration type/class comes handy in such scenarios).

As an example, if testing a 'send' function that takes a sender, content/media type, and recipients where recipients can be a single contact or a group, one shouldn't have to check that all combinations of content/media-type works with single or group recipients and other variable option variables. If decomposed in orthogonal ways K+L+N+M tests and perhaps a handful overall edge cases should do and not KxLxNxM if each variable dimension has K, L, N, M possibilities. If not cleanly separated in the implementation structure, the cross product of test cases are needed.

Re: Why I still Lisp

#190

Earlier quoted context omitted.

There is no limit on the number of problems easier to solve using dynamically typed languages. For an individual hacker, dynamically typed languages make a lot of sense. I don't forget what types my functions accept as I am writing a program. All static typing can accomplish is slow me down when I'm trying to bang out something. This is why Python (for instance) is loved by data scientists, researchers, and startups.…

The auto-completion is purely Python's dynamic-dispatch problem though. Lisp has symbol-based auto-completion which doesn't suffer from the same issue (search is a different story!). This sounds terribly controversial, but I would love to know /when/ the static-typing pays off compared to a looser approach like sound-gradual typing (where you basically export types at a boundary and make sure that you don't violate t…

The fascinating thing about Python is the ability to write functions where the parameter can intake multiple data types.

I haven’t quite seen another language handle it this elegantly as Python does.

Then, inside the function, you can check the parameter’s data type, and handle it appropriately. And error out immediately if the wrong type is passed in.

This allows you to operate on the data at a more logical level (what it implies), as opposed to just at the technical level (what data type it is).

For example, you can pass in a single string, or a list of strings. And your function can check the type and handle it appropriately.

In C++ and Java, because of the rigidity of the function declaration, in order to do something like this, then you would need to create multiple functions to handle each of the different types that you want to allow. Then you’d need to create a wrapper function to dispatch it to its appropriate sub function. That becomes a complete mess after a while.

Post reply on HN