5 ms·
_My_ main objection to lisp is that it's confusing. I don't mean the syntax is hard to grasp. I mean the way it looks. It becomes very confusing when the progr
by hasenj 9y ago
_My_ main objection to lisp is that it's confusing.
I don't mean the syntax is hard to grasp. I mean the way it looks. It becomes very confusing when the program grows in size.
This is not unique to Lisp. It applies to all dynamic languages that don't have strong tooling support (IDE's with intellisense).
(Maybe I am wrong about Lisp being dynamic; my only experience has been with "arc"; and I have had someone tell me before that common-lisp has static types)
I used to be happy about programming python and javascript in a plain text editor (vim).
However, as I was doing my first intermediate size project, I realized that I've hit a limit.
My project was in Javascript (frontend) and I couldn't keep track of what was going on anymore. Each unit of code is understandable on its own but the whole thing is a mess to look at. When I need to change the inputs or outputs of a function, I have no idea if I've done it correctly or not; due to the lack of type checking.
I absolutely need to make sense of what is what. Having everything look the same makes me confused. And I've come to realize that tooling support is of the utmost importance. Having an editor like vim with cool tricks is nice, but what I really need is to "rename variable" or "rename function" automatically across all usages in the project.
- dorfsmay 9y agoThey are IDEs, and if you think about it for a minute, Lisp languages have to be the easyest to implement IDEs for, as their syntax is exactly the AST and easy to parse.
- dualogy 9y ago> if you think about it for a minute, Lisp languages have to be the easyest to implement IDEs for, as their syntax is exactly the AST and easy to parse I wouldn't think the parsing stage has ever been the top bottleneck or chief complexity/complication for IDE/tooling developers..
- kazinator 9y agoIf every feature of a programming language syntax can be used in about 100 kilobytes of code, and your project is 3000 kilobytes, that's a 30:1 "sameness ratio" at best. If you use every language feature in that program, any 3% (if not more) of your program will look the same as some other 3%. Most programs don't exercise every language feature throughout most of their code, so their pieces look even more self-same than that. In Lisp, we have to learn to factor in the identity of the operators into what is "same": learn not to see (defclass bear (animal) ..) as being the same "same" as (block foo (init) ...). When you're reading Lisp code, you're seeing chunks like this: xxxxxx xxxxxxxxxxxxxxxxx xxxxxx xxx xxxxxxxxxxxxxxxx xxxxxxx xxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxx You have to train yourself to see the upper left corner of this blob before any other processing: (defun xxxxxxxxxxxxxxxxxx xxxxxx xxx xxxxxxxxxxxxxxxx xxxxxxx xxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxx The meaning of the rest of it depends on that one; it has to look different from other blobs that have something else in that corner.
- sc4les 9y agoHave you tried Cursive for Clojure lately? It does a lot of the things really well
- gumby 9y agoThis could be simply familiarity. Back in the 80s I wrote a large system (100s of Kloc) in Common Lisp (Cyc) and it was clear and easy to follow...for a Lisp programmer. I don't say "familiarity" as some sort of insult. I find human-generated Lisp, Forth, Postscript, and TECO clear. I find APL code impenetrable, but I know my APL-using friends (well, some Well Street variant) find it as clear as a bell. And machine-generated C code is, well, opaque. Now what I like about the lisp syntax is precisely what (if I understand you correctly) don't: it fades into the background so I can concentrate on the algorithm. This means the C/C++ code (mostly C++ these days) I write for myself or in my small workgroup is visually unlike traditional style guides: node* foo(node& first, node& last){ if(first_fails_qualifier(first)) return nullptr; if(last_fails_qualifier(last) ) return nullptr; if(!some_other_precondition(first, last) return nullptr; // OK, we have valid arguments ...do some processing on the args... return (wanted_first_p() ? &first : &last); } I find the aggressive use of { on its own line distracts; you want the interesting stuff in your fovea (so the preconditions are easy to scan; the algorithm is set apart, and the return clearly returns one type, doing a late discrimination). but YMMV
- greenshackle2 9y agoI never thought that I would miss writing C, but writing Python in a fairly large system, I miss the type checking. Some of the ease of use of dynamicity is paid back in the added costs of writing more tests. In my experience a big downside of highly dynamic languages that let you hack the language itself, including Python and Lisp, is that they give programmers quite a bit of room to shoot themselves in the foot by designing language-altering atrocities. On the Python system I currently work on, I've found atrocious uses of metaclasses that make classes behave in unintuitive ways. Don't get me wrong, I love using Python and Lisp for my own projects, and I don't like Java very much, but I've come to appreciate its one big advantage for large software systems: it limits the damage that can be done by mediocre programmers.
- lispm 9y ago> When I need to change the inputs or outputs of a function, I have no idea if I've done it correctly or not; due to the lack of type checking. Well, the good news is Common Lisp has runtime types and some implementations even support limited forms of compile time checking. The Common Lisp Object System allows you to use classes. One then gets nice runtime errors. CL-USER> (defmethod add ((a number) (b number)) (+ a b)) #<STANDARD-METHOD COMMON-LISP-USER::ADD (NUMBER NUMBER) {1003ECEF53}> CL-USER> (defmethod add ((a string) (b string)) (concatenate 'string a b)) #<STANDARD-METHOD COMMON-LISP-USER::ADD (STRING STRING) {1003FDC323}> This works then: CL-USER> (add 1 2) 3 Now this will get a runtime error, because there is no method for these arguments: CL-USER> (add "1" 2) One can also declare types. For example that something is an integer or a subset of integers... CL-USER> (defun baz (a) (flet ((foo (a b) (declare (integer a b)) (+ a b))) (foo a "b"))) The SBCL compiler then complains, that above code has a type error: ; in: DEFUN BAZ ; (FOO A "b") ; ; caught WARNING: ; Constant "b" conflicts with its asserted type INTEGER. ; See also: ; The SBCL Manual, Node "Handling of Types"