News for hackers. Stuff that matters.
Re:Lisp and Haskell (2017) by _ph_ on Sunday July 15, 2018 @06:32AM (#17534637)
I have to say, this is a very bad blog post. There are things to critisize in Common Lisp. And of course there is a valid discussion about static vs. dynamic typing. But the author gets a lot wrong and that kills the validity of his criticism. What is left, is a very negative article, which might discourage people to check out Common Lisp, which would be a pity. Even if you do not end out as a permanent Lisp programmer, learning Lisp can teach you a lot about programming.

Before I comment about some aspects of the blog, about my background: I am a professional Lisp programmer, in the recent years I used Common Lisp less (working more with Scheme-style Lisps as they are provided by my work environment), but I have implemented (and sometimes still have to maintain) reasonably sized productive applications in Common Lisp.

The blog starts with the remark that coming back to his code after months took an hour - I consider this quite a reasonable time. You might be lucky and look at a function which can be modified without the consideration for its environment, but often you have to spend quite some time before you can do changes - this has very little to do with the language.

Then the example he basis his blog post on - I think it has several issues, some already pointed out by other posters. Padding should be a required unsigned integer, not a keyword param - if you omit it (it then becomes NIL), the function will error. While current SBCL compilers even warn about the map function is called, older ones don't give a good warning and not a great error message at run time. But the main issue here is: map is the wrong function to use in this context. Map, as he used it, builds up a string from the return results of the functions it calls in the iteration, but this string is not used by the algorithm, because it writes to the string output stream s instead. Directly looping over the characters in s with "loop" would have been the better way to do it here. Interestingly, I don't think I have ever used map in my Lisp programming career so far.

The rest of the post focusses on two things, that Common Lisp doesn't have enough libraries, and static vs. dynamic typing. Funny though, that he praises Python, where the availability of libraries certainly is great, without acknowledging, that Python is way more dynamically typed than Common Lisp. The side comment "Macros are missing, but you can live without macros after all." is hand-wavingly dismissing one of the strongest features of Common Lisp. They should be used with care, but macros are what puts Common Lisp ahead of most other languages - you can, inside your project, make careful adjustments and extensions to the language itself.

So, yes, the amount of libraries has some point, but attacking the one guy, who did most to give all Common Lispers easy access to lots of libraries, for "not writing tests" is not strengthening the argument. And while the Common Lisp community indeed could use more active contributers and more libraries, blog posts like this rather deter people. It would have been more productive to call for contributers. And from my own practical experience: yes libraries are very valueable and sometimes essential to start a project. But once you become a maintainer of production software, they can be also quite a liability, as you depend on a piece of software you don't maintain.

This leaves the critique of the lack of static typing in Common Lisp. First of all, yes, Common Lisp is not a statically typed language. If that is a blocker, use a static typed language, but then don't praise Python. There are many reasons which speak for static typing - and that is also a reason I have added Go to the programming languages I use. A proper static type checker can be quite a help developing. Interestingly in this context, Go uses a very limited type-inferencing, so that usually the type declaration of the function parameters is enough so that you don't have to explicitly type local variables. Which brings us back to what Common Lisp offers, especially SBCL: optional static typing. You can declare the type of any function parameter and the return results of functions. You can declare the type of any local variable. Depending on your "optimize" settings (speed/safety), SBCL will insert the necessary type checks and use the type information in its type inferencing engine, and create type errors, wherever it can detect them. With fully-typed code, SBCL can generate code which matches and occasionally even exceeds the output of gcc. So, Common Lisp has a lot to offer, which the author had not tapped into.

Re:Lisp and Haskell (2017) by YouAreGreat on Sunday July 15, 2018 @07:31AM (#17534778)
> what Common Lisp offers, especially SBCL: optional static typing

Common Lisp offers optionally unsound static typing.

(SBCL doesn't change that, that's why it inserts runtime checks.)

Re:Lisp and Haskell (2017) by _ph_ on Sunday July 15, 2018 @09:00AM (#17535060)
I am not sure what you mean by "unsound static typing", care to explain?

SBCL does offer optional static typing as it goes beyond Common Lisp and can perform static type checking across compilation units.

If you have a lisp file like:

  (defun foo (x) (declare (fixnum x)) (* x 2))
  (defun bar () (foo 3.5))
Where bar has a static type error by calling foo with a float value, compiling the file with SBCL will give you the expected static type warning:

  ; file: foo.lisp
  ; in: DEFUN BAR
  ;     (FOO 3.5)
  ;
  ; note: deleting unreachable code
  ;
  ; caught WARNING:
  ;   Asserted type FIXNUM conflicts with derived type
  ;   (VALUES (SINGLE-FLOAT 3.5 3.5) &OPTIONAL).
  ;   See also:
  ;     The SBCL Manual, Node "Handling of Types"
Re:Lisp and Haskell (2017) by YouAreGreat on Sunday July 15, 2018 @09:40AM (#17535182)
A sound type system would have guaranteed that no program execution ever calls your function foo with the wrong type of argument. SBCL doesn't offer any such guarantee.

If some part of your program extracts values from a heterogeneous list and calls foo on one of them, SBCL will not be able to statically guarantee that it is a FIXNUM at runtime. It can't reject the program either, that would require seriously subsetting the language.

Re:Lisp and Haskell (2017) by _ph_ on Sunday July 15, 2018 @10:46AM (#17535442)
SBCL will issue a compile warning, that it cannot guarantee that you call the functions only with FIXNUMS.
Re:Lisp and Haskell (2017) by YouAreGreat on Sunday July 15, 2018 @12:45PM (#17535961)
Whoa. Will SBCL emit false-positive warnings all the time when you dare to use lists in a Lisp, or does it at least try hard to infer specialized list types, going above what's expressible using the standard LIST type?
Re:Lisp and Haskell (2017) by _ph_ on Sunday July 15, 2018 @01:01PM (#17536019)
No it doesn't emit false positive warnings when using lists. That is FUD. But if a function explicitly requires fixnums, and you pass something of type t, it might warn (depending on the optimize settings).
Re:Lisp and Haskell (2017) by YouAreGreat on Sunday July 15, 2018 @02:03PM (#17536260)
You didn't answer the question if SBCL infers specialized list types. I'll assume the answer is "no".

In that case, everything extracted from a list is T and you'd have to get that warning you mentioned above.

Such warnings would very likely be false-positive, unless Common Lisp programs are buggy as hell most of the time—assuming that would be the real FUD, no? Therefore, the non-FUD conclusion is to expect a high rate of false-positive warnings in typical list-using programs.

TBH, I suspect those false-positive warnings you mentioned aren't bona fide warnings, but some kind optimizer stream-of-consciousness log stream.

Re:Lisp and Haskell (2017) by _ph_ on Sunday July 15, 2018 @03:08PM (#17536516)
List elements are of type t, and of course acceptable to pass to all functions which take t as an argument, so no false-positive warnings.
Re:Lisp and Haskell (2017) by YouAreGreat on Sunday July 15, 2018 @04:02PM (#17536770)
Are you saying that the happy path of SBCL static typing—given you also want to use lists, and also not be inundated with spurious warnings—is to declare everything to be of type T?
Re:Lisp and Haskell (2017) by _ph_ on Sunday July 15, 2018 @04:28PM (#17536896)
No, I am not. Perhaps you read up a bit about Common Lisp and SBCL before we continue the discussion.
Re:Lisp and Haskell (2017) by ernst_klim on Sunday July 15, 2018 @02:22PM (#17536346)

  (defun sum (lst)
    (let ((acc 0))
      (dolist (x lst)
        (setq acc (+ x acc)))
      acc))

  (sum '("a" "b" "c"))
gives me a runtime error. Does sbcl support parametric polymorphism?
Re:Lisp and Haskell (2017) by YouAreGreat on Sunday July 15, 2018 @04:18PM (#17536841)
The problem as I see it is the type for lst.

Common Lisp has a (CONS α β) type for cons cells with member types α and β, but its LIST type is defined as (OR (CONS T T) NULL), basically more of a binary tree type, where T is the Common Lisp "any" union of all types.

A useable (LIST α) type would be something like μβ.(OR (CONS α β) NULL), but that's not expressible within standard Common Lisp. I expect it to very hard to infer too, especially with CONS cells being mutable.

Re:Lisp and Haskell (2017) by qazwe on Sunday July 15, 2018 @08:47AM (#17535015)
++.