Assembly language doesn't provide any datatypes. LISP does. Assembly language doesn't provide any type checking. LISP does. Assembly language doesn't provide automatic storage reclamation. LISP does. Assembly language doesn't provide naming. LISP does.
You also make a claim about L1 caches and locality of reference. Every LISP compiler writer, and every LISP garbage collector writer, knows about CDR-coding. We also know about how Cheney copying garbage collectors and their descendants like the Baker incremental collector compact data, precisely for locality of reference. The compiler writer of course is thinking about cache performance and how lines are mapped in particular target architectures.
You should probably educate yourself a little more about LISP if you are so interested in it as to make statements in a public forum.
I agree it's a somewhat odd comparison.
There are of course plenty of obvious and non-obvious ways to optimize linked lists, but even still they have poor performance characteristics, space efficiency and cache locality compared to alternative structures like arrays and even immutable arrays.
There's a reason Java, C#, Python etc store strings as immutable arrays; not only do they start from a generally better performance baseline than lists, but they too have well-understood optimization characteristics.
I thought CDR needed hardware support as opposed it being a general programming technique, is that not correct?
I've only ever read about it on FAQs like in the following:
http://www.cs.cmu.edu/Groups/AI/html/faqs/lang/lisp/part2/fa...
I am writing a new language with built-in garbage collection that I think is quite superior to other languages. I have created a full standard library with almost 1,000 built-in functions and none of my data structures (lists, maps, trees, stacks, indexes, tables etc) contain pointers or linked lists (that use pointers). I sold over 30,000 copies of a language/database system in 1987 so I think your last comment is quite inappropriate. I have know about Lisp since I started CS in University in 1975.
Linked lists are horrible data structures when being used as well as when being freed (your garbage collection comment). I use simple dynamic multi-typed arrays instead of linked lists (pointers) and they can be freed in 1 chunk or a bigger version can be freed with a few memory de-allocations. I get full cache locality and improved speed of allocation and de-allocation.
I would love to see an incremental GC that can copy all linked lists nodes into contiguous memory automatically. Nice trick if you can do it but that doesn't help you if your linked list doesn't cause a GC.
You could maybe say that linked lists are at the heart of the platonic ideal of Lisp. Naive interpreters might use linked lists in their internal representation. But real implementations of e.g. Common Lisp or Scheme provide a wide array of data structures (multi-dimensional arrays, hash tables, linked lists).
Far from it. Recursive functions and symbolic expressions were nothing like assembler back then.
> You can indent a Lisp program in any way but the language doesn't require any at all.
One can indent it in any way, but practically people use common indentation styles. Lisp also provides formatting&indentation via the pretty printer.
CL-USER 48 > '(DEFUN COLLAPSE (L) (COND
((ATOM L) (CONS L NIL))
((NULL (CDR L))
(COND ((ATOM (CAR L)) L)
(T (COLLAPSE (CAR L))))) (T
(APPEND (COLLAPSE (CAR L))
(COLLAPSE (CDR L))))))
(DEFUN COLLAPSE (L)
(COND ((ATOM L) (CONS L NIL))
((NULL (CDR L))
(COND ((ATOM (CAR L)) L) (T (COLLAPSE (CAR L)))))
(T (APPEND (COLLAPSE (CAR L)) (COLLAPSE (CDR L))))))
> I think with practice, some programmers developed an eye for the lack of structural cluesLisp has a lot of syntax and structural clues, but you just don't know them. You have to learn them, since much of, say, C syntax knowledge does not carry over to Lisp.
>and made some reasonable size code.
Like the 1 million lines of Lisp code of the Lisp Machine OS? Or the several hundred thousand lines of an editor largely written in Lisp (GNU Emacs)?
> Linked lists are poorly executed in modern computers that rely heavily on locality of data
Lisp nowadays usually does not execute linked lists, but runs compiled Lisp. Some data is in linked lists, but there are many other data structures not made of linked lists. Still the language runtime is often pointer heavy.
As for perf, 7 very popular and performant games were written in Lisp. Crash Bandicoot 1, 2, 3 as well as Jak and Daxter 1, 2, 3 and Racing.
I also know that Lisp or assembler can do anything/everything. I don't like polish notation or the lack of structure in Lisp programs. Everything is a function (with only a couple of exceptions).
And the tendency for functional compile-to-JS langs to emulate linked lists in Javascript and keep them the default data structure is downright laughable.
Lisp predated level 1 caches. I think it's better to design hardware around the software that runs on it (the Burroughs mainframe/Lisp machine approach), than design programming languages around the machines which run them (the C approach). In this case, it means finding a way to make non-local data references more efficient.
Lisp's original reputation for slowness predated the use of Level 1 caches, and was because many early implementations ran on interpreters.
Lisp DOES predate level 1 cache but we DO have level 1 cache now and it dwarfs all other optimizations on modern computers. Wouldn't it be nice if the hardware was designed to optimize our languages instead of the other way around but I live in this universe rather than an alternate one.
What matters is now, not decades ago.
The way things are now can be changed.
For most applications users care more about response times than CPU clock rates. Hardware has speeded up by several powers of ten (Moore's law) but software has at the same time slowed down (Wirth's law), resulting in little if any net gain, and that has nothing to do with the use of lists: most applications don't use them.
My website is www.rccconsulting.com where you will find an essay on the data structure I mentioned here called SLIST and some documentation and high level design for the system/language I am currently developing called MAX.
Users do care more about response times (as you say) and instantaneous and 1/2 instantaneous are considered equal by end users. Most user developed code doesn't need optimization but the data structures that under pin that user code should be as performant as possible, just in case.
Designing a language like Lisp or a special purpose language/system like I am creating have design criteria that is much different from the application programmer that is just trying to make stuff work. I have completed at least 1,000 projects big and small as an application programmer, as well as all the system programming I have done so I think I have a good incite into both points of view.
>> use of lists; most applications don't use them
You may be correct but most programs manipulate variable length character strings whether that is formatting, creating HTML documents, creating JSON data etc. Most currently used programming languages don't do variable length strings either well or efficiently. I also don't like the fact that almost all useful data must be manipulated and stored in database systems that reside somewhere other than my computer. My new system was designed to help solve that problem and more.
Your SLIST sounds similar to data structures which go by various names in different languages, e.g. list in Python or ArrayList in Java. Common Lisp vectors support that functionality too.
Your VCHAR presumably works in a similar way? I agree ASCIZ is a very inefficient way of representing strings, unless they're guaranteed to be very short.
At the top of my description of SLIST, I acknowledge that I may not be the first to define a simple structure like that but I can say that I never got the idea from somewhere else. These lists can be used as an autobalanced binary tree for small lookups? Are these other structures pointer free with next to no overhead even on a 64 bit compiler? If they can do all that my humble SLIST can do then I will have invented a very good data structure and there isn't anyone using linked lists with pointers, right?
Most languages have made strings read only so they aren't very useful for manipulating large and small amounts of variable text. Actually, my VCHAR struct just uses my buffers which are used whenever memory is needed. My language is object oriented but even more it is collection oriented so most objects don't allocate space just for themselves. When using my buffer routines, no buffer can ever use data that doesn't belong to it or overflow it's allocated space.
I have many local and global memory managers and my buffer structure keeps track of use, size and origin. Memory that is alloced globally is always on cache line boundaries and so I don't put headers on allocated data. All chunks of memory are tracked and can't get lost so I count on less memory allocations than most other languages (collections remember)
Compared to any alternative I have found (unicode etc), ascii is quite efficient. When I get around to adding any unicode support, it will be UTF8 so none of the current code needs replaced or will run slower than now.
Say you have (pseudocode)
Array(4 16 5 20)
What's its type? Array
Array<Int>
Array<4>
Array<Int 4>
Array(Int Int Int Int)
None of these lend themselves easily to paradigms other than imperative, true. But this is because they unnecessarily discard known information. The type of an array ought to be itself: assert Array(4 16 5 20) hasType Array(4 16 5 20)
=> Ok
assert Array(4 16 5 20) hasType Array<Int>
=> Error("Expected Array<Int> but got Array(4 16 5 20). Hint: Typeclass Array<Int> cannot be directly instantiated")
assert Array(4 16 5 20) hasTypeclass Array<Int>
=> Ok
Fully functional and referentially transparent.Now keep a straight face and say "L1 cache" once again.
Code layout/indentation is also an issue, but there's a single standard for Lisp, which Emacs is aware of.
$(patsubst %.foo,%.bar,$(foreach blah,$(VAR),\
whatever $(blah)))
People who can say with a straight face they find Lisp parentheses confusing have GNU Makefiles full of this crap, well debugged and all.> You can indent a Lisp program in any way but the language doesn't require any at all.
Off the top of my head, isn't this true of basically all languages? Except one, and it got a lot of criticism for it (Python).
What I should have said was that Lisp has no commands or structure that can't be changed. Some might argue that this is it's strength but I have seen hundreds of samples of Lisp and it looks very confusing. I don't normally program in C# or Java or many other languages but I can normally understand their code. (Lisp and functional languages are the most opaque to me)
My language uses a byte code interpreter and that byte code is in polish prefix notation just like Lisp. I wouldn't want to code in my byte code either (even if the byte codes were replaced with keywords instead of the binary code). Polish prefix notation is great for the compiler but not very good for people.
Beyond that, your objections seem to be based upon familiarity. I had similar ones before I started using Clojure more often. I think the notation is just fine - it's not much different from imperative languages except they place the parenthesis in a different spot - I think it's more the nesting than the notation, which isn't a common tactic in imperative languages.
I still use imperative languages during my day job so I can decipher imperative code easier, but I am much better at deciphering functional code than I used to be.
What you find easy to read depends on what you're used to reading.
You will have a better time on HN if you swap these two more often than not.
When I was in my 20's, I programmed at least 100,000 lines of Z80 assembler for the first micro computers. One project was at least 40,000 lines and so I know how difficult it is to program larger assembler programs. The biggest problem is that it is hard to see the structure of the loops and conditionals that we normally indent in higher level languages. (You can indent a Lisp program in any way but the language doesn't require any at all.) It is also difficult to recognize expressions. Both of these problems are also there in Lisp (unlike most other high level languages).
One last point about the linked list structure at the heart of Lisp. Linked lists are poorly executed in modern computers that rely heavily on locality of data, to optimize the L1 cache. Lisp was very easy on the compiler/interpreter writer but wasn't very good at optimizing the readability of the code for the programmer. (I don't want a religious war but I will point out that most programmers have never programmed in Lisp even though it was one of the first computer languages created.) Before I get a lot of dissing comments, I think with practice, some programmers developed an eye for the lack of structural clues and made some reasonable size code. You could say the same about some programmers making quite good large scale programs in assembler but that doesn't mean that writing in assembler or Lisp should be encouraged.