I just sampled a few posts and they all seem to be Common Lisp related.
Except for the EVERY TIME I COME TO THIS GROUP thread. I don't know
*what*'s up with that but it doesn't seem to have to do with any flavor
of Lisp at all. Not unless Scotty uses Lisp to program a transporter beam
that's fueled by thallium, anyway.
> Are there any Clojure users here? Or is this group specific to Common
> Lisp?
Whether Clojure is a lisp would be subject to discussion.
In any case, I believe there are clojure specific groups or mailling lists.
> I just sampled a few posts and they all seem to be Common Lisp
> related.
Yes. There may also be discussions about other lisps that don't have
specific avenues, and that are not ridiculous lisps (like eg. newlisp).
> Except for the EVERY TIME I COME TO THIS GROUP thread. I don't know
> *what*'s up with that but it doesn't seem to have to do with any flavor
> of Lisp at all. Not unless Scotty uses Lisp to program a transporter beam
> that's fueled by thallium, anyway.
You need to learn how to use a killfile.
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
This group is not specific to CL.
I'm trying to learn some Clojure; see my post in the thread
"Remove element from list and return the element".
This group is not dedicated to Common Lisp, but it is mostly populated
by CL users. Other dialects generally have their own newsgroup or
mailing list.
That said, variety never hurts. Just be willing to set up some
software/wetware filters to improve the SNR.
Google groups is not very good anymore. Pointing a "real" newsreader
(i.e. a standalone program) to eternal-september.org works much better.
- Daniel
> Deeyana <d.aw...@hotmail.invalid> writes:
>
>> Are there any Clojure users here? Or is this group specific to Common
>> Lisp?
>
> Whether Clojure is a lisp would be subject to discussion.
It's a Lisp. Prefix notation, homoiconicity, macros, lists, the works.
> In any case, I believe there are clojure specific groups or mailling
> lists.
Perhaps. But that wasn't what I asked.
>> I just sampled a few posts and they all seem to be Common Lisp related.
>
> Yes. There may also be discussions about other lisps that don't have
> specific avenues, and that are not ridiculous lisps (like eg. newlisp).
"Ridiculous" Lisps?
>> Except for the EVERY TIME I COME TO THIS GROUP thread. I don't know
>> *what*'s up with that but it doesn't seem to have to do with any flavor
>> of Lisp at all. Not unless Scotty uses Lisp to program a transporter
>> beam that's fueled by thallium, anyway.
>
> You need to learn how to use a killfile.
Pardon me?
> On 01/27/2011 07:56 PM, Deeyana wrote:
>> Or is this group specific to Common Lisp?
>
> This group is not dedicated to Common Lisp, but it is mostly populated
> by CL users. Other dialects generally have their own newsgroup or
> mailing list.
>
> That said, variety never hurts. Just be willing to set up some
> software/wetware filters to improve the SNR.
Alrighty then. I don't know why people are arguing about thallium in this
newsgroup but if that sort of thing is a common enough occurrence ...
> Google groups is not very good anymore. Pointing a "real" newsreader
> (i.e. a standalone program) to eternal-september.org works much better.
You're preaching to the choir there. Unless you meant that as a subtle
dig at XanaNews. :)
> Are there any Clojure users here? Or is this group specific to Common
> Lisp?
Empirically it has become specific to CL. In many ways it would be
better if it wasn't, but for a very long time (probably at least 10
years, and maybe getting on for twice that long) the great majority of
the non-CL people who crop up here have been trolls (many people will
remember the person who used to post here pushing some other language
with a fairly-clearly commercial agenda, and we have a current example
of someone who tends to post rather childish insults about CL), which
has polarised the situation to the extent where discussion of non-CL
Lisps has become difficult.
> Alrighty then. I don't know why people are arguing about thallium in
> this newsgroup but if that sort of thing is a common enough occurrence
> ...
That is crossposted nonsense, and probably quite common in unmoderated
newsgroups. Since it is crossposted, it is also easily identifiable...
Nicolas
> It's a Lisp. Prefix notation, homoiconicity, macros, lists, the works.
One of the things that makes a lisp is minimal syntax (it's the minimal
syntax that enables the homoiconicity). Clojure has significantly more
syntax (three different types of semantically different parens last
time I checked) than common lisp or scheme which makes clojure much
less lispy imho.
Last time I looked, clojure also visits the brokeness that is java's
classpath on its users completely unnecessarily - compare abcl where
one can simply (load "/arbitrary/path/to/file.lisp"). In clojure you
can't do this unless you do some classpath related dance *when you
launch clojure* - this makes it a much less dynamic language imho, and
again, less lispy.
Its ties to the JVM rule out TCO - also less lispy. In general, clojure
is more like a java with lisp macros than a lisp. A java with lisp
macros is still much nicer than java, but still significantly less
lispy than common lisp or scheme.
warmest regards,
Ralph
--
Raffael Cavallaro
Lisp is not about minimal syntax per se, it's about representing programs as trees and to have program text closely mirror the corresponding tree in the general case.
Clojure has a syntax for lists - () - vectors - [] - and maps - {}, as well as numbers and strings and other stuff, and uses all these kinds of objects to represent expressions. Not that different from CL (which lacks syntax for vectors and maps). Clojure does use vectors and maps in a few places where CL uses lists, which is a little awkward compared to the general Lisp tradition, but imho that's not enough for not qualifying Clojure as a Lisp.
> Last time I looked, clojure also visits the brokeness that is java's
> classpath on its users completely unnecessarily - compare abcl where
> one can simply (load "/arbitrary/path/to/file.lisp"). In clojure you
> can't do this unless you do some classpath related dance *when you
> launch clojure* - this makes it a much less dynamic language imho, and
> again, less lispy.
I don't use Clojure, so I don't know about this issue. If that's the case, it's quite unfortunate, but still, it doesn't make Clojure "not a Lisp". You can always add / to the classpath and hide that behind a launch script. Not pretty, I agree.
> Its ties to the JVM rule out TCO - also less lispy.
ABCL has the same problem, and it's a Common Lisp. TCO is an implementation detail.
> In general, clojure
> is more like a java with lisp macros than a lisp. A java with lisp
> macros is still much nicer than java, but still significantly less
> lispy than common lisp or scheme.
Not quite. Clojure is not a (mostly) statically-typed, class-based OO language like Java, it's a dynamically typed, functional language like Scheme.
I mean, I don't particularly like Clojure. I think that the main reason for using it - concurrency-friendly data structures and constructs - should have been a library on top of CL or Scheme. But nevertheless I fully recognize it as a Lisp, even if a Lisp that I don't like.
Bye,
Alessio
> Clojure does use vectors and maps in a few places where CL uses lists,
> which is a little awkward compared to the general Lisp tradition, but
> imho that's not enough for not qualifying Clojure as a Lisp.
I think this is a critical difference in fact. I don't have a problem
with special syntax for data types at all (using as many types of
parens as you like). But special syntax for, well, syntax, is annoying
and limiting, because it commits too early to what that thing is.
Clojure is not severely affected by this, but it does have it to some
degree.
> ABCL has the same problem, and it's a Common Lisp. TCO is an
> implementation detail.
LispMs also did not do TCO!
Nor, it would seem, References: headers. :P
> Last time I looked, clojure also visits the brokeness that is java's
> classpath on its users completely unnecessarily - compare abcl where one
> can simply (load "/arbitrary/path/to/file.lisp"). In clojure you can't
> do this unless you do some classpath related dance *when you launch
> clojure* - this makes it a much less dynamic language imho, and again,
> less lispy.
Others have already refuted much of what you wrote there, but I'm going
to take a personal crack at this one:
(eval (read-string (slurp arbitrary-file)))
There. :)
> (eval (read-string (slurp arbitrary-file)))
If that actually is how you do that, then I think you've made Raffael's point.
Actually, we wouldn't ordinarily do that; I can't recall ever finding
classpaths bothersome.
However, it serves to refute Raffael's claim that it's flatly
*impossible* to load and run arbitrary Clojure code from an arbitrary
filesystem path.
And it could always be nicened up. Wrapped in a function, say. If one
wants to run the code during startup eval can be avoided:
(defmacro load-arbitrary-file [file]
(read-string (slurp (if (string? file) (File. file) file))))
The contents of the file will be parsed through the reader into sexps and
then just incorporated into the source where the macro call was.
TCO is also not reliable in some other Common Lisp implementations.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> Last time I looked, clojure also visits the brokeness that is java's
> classpath on its users completely unnecessarily - compare abcl where
> one can simply (load "/arbitrary/path/to/file.lisp"). In clojure you
> can't do this unless you do some classpath related dance *when you
> launch clojure* - this makes it a much less dynamic language imho, and
> again, less lispy.
I don't think this has been the case for a long time. It's been a while
since I used clojure, and it wasn't the case then. There was some very
complicated code in the runtime to make it possible, but it was
implemented.
David
> > Last time I looked, clojure also visits the brokeness that is
> > java's classpath on its users completely unnecessarily - compare
> > abcl where one can simply (load "/arbitrary/path/to/file.lisp"). In
> > clojure you can't do this unless you do some classpath related
> > dance *when you launch clojure* - this makes it a much less dynamic
> > language imho, and again, less lispy.
>
> I don't use Clojure, so I don't know about this issue. If that's the
> case, it's quite unfortunate, but still, it doesn't make Clojure "not
> a Lisp". You can always add / to the classpath and hide that behind a
> launch script. Not pretty, I agree.
user=> (load-file "G:/source/clojure/bottles.clj")
9 bottles of beer on the wall, 9 bottles of beer.
Take one down and pass it around, 8 bottles of beer on the wall.
8 bottles of beer on the wall, 8 bottles of beer.
Take one down and pass it around, 7 bottles of beer on the wall.
7 bottles of beer on the wall, 7 bottles of beer.
Take one down and pass it around, 6 bottles of beer on the wall.
6 bottles of beer on the wall, 6 bottles of beer.
Take one down and pass it around, 5 bottles of beer on the wall.
5 bottles of beer on the wall, 5 bottles of beer.
Take one down and pass it around, 4 bottles of beer on the wall.
4 bottles of beer on the wall, 4 bottles of beer.
Take one down and pass it around, 3 bottles of beer on the wall.
3 bottles of beer on the wall, 3 bottles of beer.
Take one down and pass it around, 2 bottles of beer on the wall.
2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 9 bottles of beer on the wall.
nil
Common Lisp has 'syntax' for vectors:
#(1 2 3 I am a vector)
And happily, it would occur to no lisp programmer to use vectors eg. in
a macro such as:
(let. #((v 1)
(u 2))
(+ v u))
There's clearly no point in doing such a thing.
I'd say using s-expression vectors is mostly a hack to be able to use
[] as enclosing characters in source code.
In CL it is possible to use [] for that, since the language does not
use it and it can be changed to do so.
Since CL does not use it by default and generally nobody does that in
CL, real CL source code lacks the 'visual clue' of []. Which is
nothing I care about.
And yet it did occur to at least one Lisp programmer: Rich Hickey.
> There's clearly no point in doing such a thing.
There clearly is, and it is this: Clojure makes a distinction between
code that's a data structure and code that's executable. For example, a
list of let bindings is not itself executable; it doesn't start with an
operator followed by whatever the operator takes as arguments. It's just
a list that's interpreted as data. In such situations Clojure uses
vectors; so usually when you see a parenthesized list in Clojure the
first item in the list is an operator and the rest of the list is
operands.
It makes things a bit clearer without destroying homoiconicity. It's very
easy for Clojure macros to transform or output the vectors where needed,
and it even makes it easier for macro code to tell when it's looking at
an operator + operands versus "just a list".
It also simplifies the heck out of auto-indent implementations for
Clojure IDEs. Instead of having to guess, or have special rules for
particular operators like let, when it should indent by one space (lists-
as-data) or by two (lists-as-operator-operands-expressions), it can just
indent parenthesized lists by two and vectors (and hashmap literals) by
one.
There have been a lot more in the past.
>> There's clearly no point in doing such a thing.
>
> There clearly is, and it is this: Clojure makes a distinction between
> code that's a data structure and code that's executable.
Discussions about syntax are boring.
Among the major reasons why people are interested in Clojure is that it
somehow appeals to the idea that it is a "new" Lisp dialect, as if that
by itself already meant anything; that it somehow makes parallel
programming easier, which is only true for a narrow scope; and that it
runs on top of the JVM, which is true for some other implementations of
some other Lisp dialects as well. It seems to me that the latter is
probably the main reason, because Clojure makes a few compromises in
order to be able to run on the JVM - other Lisp dialects have a somewhat
harder time to integrate smoothly with the JVM, if they want to stick to
their original specs.
I don't care at all about JVM, to the contrary, I think the JVM is a
pretty bad set of compromises that is only relevant because it has
industry adoption - but from a technical perspective, it's just junk.
I can understand that if you absolutely must use the JVM for some
non-technical reasons, you might as well want to do it with a layer on
top that makes it somewhat more bearable.
But why would you want to do that if you have a real choice? (Don't say
"libraries" now... ;)
> I can understand that if you absolutely must use the JVM for some
> non-technical reasons, you might as well want to do it with a layer on
> top that makes it somewhat more bearable.
>
> But why would you want to do that if you have a real choice? (Don't say
> "libraries" now... ;)
Easy, portable host interop.
Common Lisp (other than the variant that runs on the JVM!) provides no
easy, portable facilities for presenting a user interface, networking,
threading, or even (last I checked) simply working with files. (Even C
has a standard facility for file I/O!)
Anything on the JVM that can painlessly instantiate and use Java objects,
on the other hand, immediately gets file I/O, graphics/GUI/user
interface, networking, threading, and a big load of other tools for free,
and in a way that works without changing the code on Windows/x86, MacOS/
PPC, Linux/Alpha, and a broad variety of other host architecture/OS
combinations.
Difficult, but not impossible, as long as the discussion remains
on a solid technical ground and doesn't descend into openly anti-CL
or trollish behavior. Enquiries into the history of Lisp and/or Lisp
Machines are usually received well and responded to generously, even
marginally trollish ones such as "Why does CL have so many different/
non-orthogonal/weirdly-named ways to do X?". Occasional questions on
technical minutia of Emacs Lisp are tolerated, to a point. And though
it doesn't often happen without devolving into a food fight, serious
discussion of obscure technical points vis-a-vis CL & Scheme *has*
been known to happen on rare occasions. ;-}
None of which takes away from your main point, of course.
-Rob
-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
No. I just feel the need to occasionally remind GG users that there's
a better way, and it can be had for cheap or free. Your post seemed
like it might attract the relevant demographic.
- Daniel
What kind of file I/O do you think CL lacks?
Clojure has its own group:
http://groups.google.com/group/clojure
comp.lang.lisp is used for Common Lisp, since Common Lisp is the
canonical Lisp language that has 'Lisp' in its name
and is in the core Lisp tradition (Lisp-1.5 Maclisp ZetaLisp).
Most of the 'incompatible' Lisp dialects like [Clojure, Scheme, Logo]
have their own groups.
> On 29 Jan., 02:00, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> On Sat, 29 Jan 2011 01:28:38 +0100, Pascal Costanza wrote:
>> > I can understand that if you absolutely must use the JVM for some
>> > non-technical reasons, you might as well want to do it with a layer
>> > on top that makes it somewhat more bearable.
>>
>> > But why would you want to do that if you have a real choice? (Don't
>> > say "libraries" now... ;)
>>
>> Easy, portable host interop.
>>
>> Common Lisp (other than the variant that runs on the JVM!) provides no
>> easy, portable facilities for presenting a user interface, networking,
>> threading, or even (last I checked) simply working with files. (Even C
>> has a standard facility for file I/O!)
>
> What kind of file I/O do you think CL lacks?
Well, for starters, there is no portable way in Common Lisp of
determining whether a file is a directory or not. That seems like a
pretty basic piece of filesystem-interface functionality to me.
In Clojure, of course, this is easy:
(import [java.io File])
(defn as-file [str-or-file]
(if (string? str-or-file)
(File. str-or-file)
str-or-file))
(defn directory? [f]
(if f (.isDirectory (as-file f))))
user=> (directory? "/bin/sh")
false
user=> (directory? "/bin")
true
user=> (directory? "/foo/xyzzy")
false
And this will work anywhere a JVM will work.
(Of course, paths themselves tend to be system-specific. "/bin" will
produce false on a Windows machine or an older Mac, for example.)
> On Sat, 29 Jan 2011 01:28:38 +0100, Pascal Costanza wrote:
>
> Easy, portable host interop.
>
> Common Lisp (other than the variant that runs on the JVM!) provides no
> easy, portable facilities for presenting a user interface, networking,
> threading, or even (last I checked) simply working with files. (Even C
> has a standard facility for file I/O!)
So open is a no-op then? It is really rather easy to work with files,
also considering nice things like with-open-file and so on.
For everything except user interfaces there are easy enough wrapper
available to bridge between implementations (if you actually use that at
all). What's so hard about that?
Also, doing a good job on GUI is kind of a complicated job, isn't it?
Because in any case, with most GUI systems you have to do so many things
just to get your data on the screen, getting to know the specifics of
that particular systems isn't so much more work anyhow.
Anyway, last time I checked, programming with Swing was a nightmare. It
may certainly be that using it with a Lisp (or any more dynamic
language) and macros might decrease the pain to acceptable levels -
still doubting it, though.
(I'm actually open to suggestions about good GUI frameworks, e.g. in the
sense of a nice default, but customizable, inspector-like behaviour
... so, like SLIME/GTK with presentations etc. or something? Couldn't
really be friends with McCLIM during my last try.)
> Anything on the JVM that can painlessly instantiate and use Java objects,
> on the other hand, immediately gets file I/O, graphics/GUI/user
> interface, networking, threading, and a big load of other tools for free,
> and in a way that works without changing the code on Windows/x86, MacOS/
> PPC, Linux/Alpha, and a broad variety of other host architecture/OS
> combinations.
(I guess it's now common to use Java in lectures; that unfortune fate
happened to me at least, so therefore I'm strongly biased -.-, at least
against the language.)
Just to concentrate on the tools and not starting about the other
points: Eclipse? Maven? Seriously? For one thing every time I've got
to touch one of the myriads of XML files necessary to configure that
fine piece of art, I'd rather write me a Makefile by hand (which I'm
doing, if possible). Currently I'm wrestling with Maven, next on that
list: merging two projects, one with some slow as hell compiling GWT
Java-to-Javascript features. The joy.
(If those are not particularly good examples, what are those good
tools then?)
So no, every single time debugging something in the linux/x86-64/sbcl
repl is more fun and productive than waiting for Java-based tools to get
their act together. </rant>
Simple is really a matter of perspective. I guess if you have to get
your application to work on most of the platform supported by the JVMs,
using ABCL can work, but imho working on Commons Lisp based
cross-implementation solutions (which naturally will then run on the JVM
via e.g. ABCL) seems to be more fitting?
Cheers,
Olof
--
No god. No kings. Only man.
So you are saying, the ANSI Common Lisp standard has file i/o, but
that lacks
features.
> In Clojure, of course, this is easy:
>
> (import [java.io File])
>
> (defn as-file [str-or-file]
> (if (string? str-or-file)
> (File. str-or-file)
> str-or-file))
>
> (defn directory? [f]
> (if f (.isDirectory (as-file f))))
That does not look easier to me than using any of the already existing
portable libraries for CL that provide that functionality.
>
> user=> (directory? "/bin/sh")
> false
> user=> (directory? "/bin")
> true
> user=> (directory? "/foo/xyzzy")
> false
>
> And this will work anywhere a JVM will work.
>
> (Of course, paths themselves tend to be system-specific. "/bin" will
> produce false on a Windows machine or an older Mac, for example.)
That was a nice try, but CL is used since 1984 and inherits
functionality
from before that. We found out how to how to check if a pathname
is a directory some time ago, even though this function is not
listed in the ANSI Common Lisp standard, but in some library.
> On 2011-01-27 21:36:06 -0500, Deeyana said:
>
> > It's a Lisp. Prefix notation, homoiconicity, macros, lists, the
> > works.
>
> One of the things that makes a lisp is minimal syntax (it's the
> minimal syntax that enables the homoiconicity). Clojure has
> significantly more syntax (three different types of semantically
> different parens last time I checked) than common lisp or scheme
> which makes clojure much less lispy imho.
This fellow is simply an anti-Clojure troll. Don't feed him.
>
> Last time I looked, clojure also visits the brokeness that is java's
> classpath on its users completely unnecessarily - compare abcl where
> one can simply (load "/arbitrary/path/to/file.lisp"). In clojure you
> can't do this unless you do some classpath related dance *when you
> launch clojure* - this makes it a much less dynamic language imho,
> and again, less lispy.
This troll is lying.
> On Sat, 29 Jan 2011 01:28:38 +0100, Pascal Costanza wrote:
> Common Lisp (other than the variant that runs on the JVM!) provides no
> easy, portable facilities for presenting a user interface, networking,
> threading, or even (last I checked) simply working with files. (Even C
> has a standard facility for file I/O!)
Hmm, when did the ability to do file I/O go away? I'm not really sure
what you mean by this.
Most of the others have largely defacto standard interfaces (which are
often just wrappers around the implement's native interface).
> Anything on the JVM that can painlessly instantiate and use Java objects,
> on the other hand, immediately gets file I/O, graphics/GUI/user
> interface, networking, threading, and a big load of other tools for free,
> and in a way that works without changing the code on Windows/x86, MacOS/
> PPC, Linux/Alpha, and a broad variety of other host architecture/OS
> combinations.
"Painlessly" is actually a bit of a stretch. Clojure comes closer than
any other lispy thing I've found. Clojure is also closer in allowing
definitions of classes that other Java programs can use, but it's still
fairly awkward to use.
What annoyed me the most about Clojure is that it wasn't really a
general-purpose language. There is an intense focuse on parallel
programming and immutable data, and other paradigms take back-seat and
are often just plain unpleasant to use. Even the multi-threading on
Clojure doesn't work very well when I/O gets involved.
Common Lisp really is the closest thing I found to truly a general
purpose programming language. It's much nicer to adapt the language to
my problem rather than forcing the solution to fit the language.
Also, being on the JVM is fine if you want to interface with Java
libraries. As soon as you want to use a library that is native, it is
quite a bit more work than something like CFFI.
David
> Tim Bradshaw <t...@tfeb.org> wrote:
> +---------------
> > Deeyana said:
> | > ...any Clojure users here? Or is this group specific to Common
> Lisp?
> >
> > Empirically it has become specific to CL. In many ways it would
> > be better if it wasn't, but for a very long time [...] the great
> > majority of the non-CL people who crop up here have been trolls
> > [...], which has polarised the situation to the extent where
> > discussion of non-CL Lisps has become difficult.
> +---------------
>
> Difficult, but not impossible, as long as the discussion remains
> on a solid technical ground and doesn't descend into openly anti-CL
> or trollish behavior.
Correction: "ascend into openly anti-CommodeLang behavior".
The gall of this troll. He can critisize any dialect that he
wants to, but if anyone critisizes his dialect, that person
is a "troll".
> Enquiries into the history of Lisp and/or Lisp
> Machines are usually received well
By whom? The CL hyenas?
> and responded to generously,
You generously share your programming incompetence and
your irrational religious fanaticism?
> even
> marginally trollish ones such as "Why does CL have so many different/
> non-orthogonal/weirdly-named ways to do X?".
To ask a non-worshipful question about CommodeLang that contains
a hint of disrespect is "trollish". Rob, you are a stinking punk.
You are the apotheosis of trolldom.
> Occasional questions on
> technical minutia of Emacs Lisp are tolerated, to a point.
You mean the hyenas let the offender live? How gracious of them.
Actually, if the hyenas didn't "tolerate" the questions it wouldn't
matter. They are powerless.
Robbie boy, you suck. You truly suck.
You are a smug, conceited, prissy pansy. However, I'm
sure your mommy is very proud of her little boy.
Disciples of CommodeLang are the lowest of the low, the vilest
of the vile, and the dumbest of the dumb.
This newsgroup is comp.lang.lisp, not comp.lang.commodelang.
If users of CL don't shut up, they will no longer be "tolerated"
here.
Let the "trolls" tell it:
Paul Graham:
The good news is, it's not Lisp that sucks, but Common Lisp.
Jeffrey M. Jacobs:
CL is a nightmare; it has effectively killed LISP
development in this country. It is not commercially viable
and has virtually no future outside of the traditional
academic/defense/research arena.
Dick Gabriel:
Common Lisp is a significantly ugly language. If Guy and I
had been locked in a room, you can bet it wouldn't have
turned out like that.
Bernard Lang:
Common Lisp did kill Lisp. Period. (just languages take a
long time dying ...) It is to Lisp what C++ is to C. A
monstrosity that totally ignores the basics of language
design, simplicity and orthogonality to begin with.
I can't tell if I should killfile you or what. You sometimes post
lisp solutions to things, but then you foam at the mouth for a bit.
Other people who I would totally have figured to have killfiled you
haven't, so obviously they either think you provide value to the
group or are at least amusing.
I will say that if many Ruby programmers are like you, I'm never going
to write in that language because interacting with them will suck. You,
personally, have driven me away from it because every time I look at
that language, I think of you and your actions. I used to be neutral
about learning Ruby, now I'm disinclined.
Well, unless someone paid me a lot of money to do so... I'd write
insurance software in Unlambda with fresh infant blood if the money
was good enough...
-pete
> On 29 Jan., 04:10, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> In Clojure, of course, this is easy:
>>
>> (import [java.io File])
>>
>> (defn as-file [str-or-file]
>> (if (string? str-or-file)
>> (File. str-or-file)
>> str-or-file))
>>
>> (defn directory? [f]
>> (if f (.isDirectory (as-file f))))
>
> That does not look easier to me than using any of the already existing
> portable libraries for CL that provide that functionality.
First of all, you only have to do it once, and then you can just use
directory? anywhere you need it.
Secondly, what "already existing portable libraries for CL"? It's not
part of the language standard. If you need a third-party library for it
at all you've already lost some portability.
>> user=> (directory? "/bin/sh")
>> false
>> user=> (directory? "/bin")
>> true
>> user=> (directory? "/foo/xyzzy")
>> false
>>
>> And this will work anywhere a JVM will work.
>>
>> (Of course, paths themselves tend to be system-specific. "/bin" will
>> produce false on a Windows machine or an older Mac, for example.)
>
> That was a nice try, but CL is used since 1984 and inherits
> functionality
> from before that. We found out how to how to check if a pathname is a
> directory some time ago, even though this function is not listed in the
> ANSI Common Lisp standard, but in some library.
Admitting that this kind of basic functionality is missing from the
language's standard library, decades after it was a known problem with a
known solution, helps make my point for me, so thanks. :)
> For everything except user interfaces there are easy enough wrapper
> available to bridge between implementations
First of all, "for everything except user interfaces there are easy
enough ..." in a programming language comparison is like "for everything
except steering there are easy enough ..." in a comparison of makes of
car.
Well, technically, more like makes of car *factory*.
Secondly, wrappers and bridging between implementations is something JVM
hosted languages simply don't even have to worry about. Nor those
languages' users.
> Also, doing a good job on GUI is kind of a complicated job, isn't it?
Yes; all the more reason not to complicate it further by requiring
developers to choose and use third-party libraries with assorted
different feature sets, portability limitations, and what-not.
> Because in any case, with most GUI systems you have to do so many things
> just to get your data on the screen, getting to know the specifics of
> that particular systems isn't so much more work anyhow.
At least with the JVM you only need to get to know the specifics of *one*
particular system, the minimum possible, and then you can implement UIs
on Macs and Windows machines and Unix boxes and on and on -- and in Java
and Clojure and Scala and multiple other languages, too.
> Anyway, last time I checked, programming with Swing was a nightmare. It
> may certainly be that using it with a Lisp (or any more dynamic
> language) and macros might decrease the pain to acceptable levels -
> still doubting it, though.
Doubt no more. Macros to automate common actions, plus a variety of
helper functions, helps tame the mess enormously, and your higher level
GUI code can be nicely lispy. As for the lower level stuff, you can reuse
it in multiple projects.
> Just to concentrate on the tools and not starting about the other
> points: Eclipse? Maven? Seriously? For one thing every time I've got
> to touch one of the myriads of XML files necessary to configure that
> fine piece of art, I'd rather write me a Makefile by hand (which I'm
> doing, if possible). Currently I'm wrestling with Maven, next on that
> list: merging two projects, one with some slow as hell compiling GWT
> Java-to-Javascript features. The joy.
>
> (If those are not particularly good examples, what are those good tools
> then?)
For Clojure? Leiningen on the compile tools side, and a number of IDE
options, including plugins for all of these: Eclipse, NetBeans, IDEA,
vim, emacs, and TextMate. Generic text editor + Leiningen + lein repl
actually can go a very long way.
> So no, every single time debugging something in the linux/x86-64/sbcl
> repl is more fun and productive than waiting for Java-based tools to get
> their act together. </rant>
Slow startup? Easily solved: start up a repl once and then leave it open.
Unless you're stuck at an 80s-retro command line box or something you've
got at least multiple term windows if not a proper GUI, and multitasking.
> What annoyed me the most about Clojure is that it wasn't really a
> general-purpose language. There is an intense focuse on parallel
> programming and immutable data, and other paradigms take back-seat and
> are often just plain unpleasant to use.
I haven't met a problem yet that Clojure's immutable data, plus a
sprinkling of refs and atoms, couldn't easily solve. The one time you
tend to want to do a good old-fashioned iterative loop bashing a mutable
structure in place is when you really need speed or to limit stress on
the GC, and then you can always use Java arrays or fall back to actual
Java for one class.
> Even the multi-threading on Clojure doesn't work very well when I/O
> gets involved.
Clojure has a good fit for concurrent I/O tasks in its agent objects. You
can also use Java's Thread class, java.util.concurrent, and so forth.
> Common Lisp really is the closest thing I found to truly a general
> purpose programming language. It's much nicer to adapt the language to
> my problem rather than forcing the solution to fit the language.
Did I mention that Clojure has a full Lisp macro capability? They're
hygienic by default but you can escape that if you really must. ~'symbol
will put raw non-gensym symbols in your macro's output and allow
deliberate name capture.
> Also, being on the JVM is fine if you want to interface with Java
> libraries. As soon as you want to use a library that is native, it is
> quite a bit more work than something like CFFI.
These days, there are Java libraries to fit nearly any purpose and the
Hotspot JIT means there's rarely ever a desire to use native code purely
for speed. And those Java libraries lack the portability issues one
commonly encounters with C or CL libraries. Scientific computing?
JScience will work wherever Hotspot runs. Web serving? There are native
Clojure libraries for that, now -- compojure for one -- and ditto. There
are even some Clojure libraries that can be used with both Clojure and
its .NET port, and thus anywhere reached by either the JVM or the CLR.
> On 28 Jan., 01:56, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> Are there any Clojure users here? Or is this group specific to Common
>> Lisp?
>>
>> I just sampled a few posts and they all seem to be Common Lisp related.
>> Except for the EVERY TIME I COME TO THIS GROUP thread. I don't know
>> *what*'s up with that but it doesn't seem to have to do with any flavor
>> of Lisp at all. Not unless Scotty uses Lisp to program a transporter
>> beam that's fueled by thallium, anyway.
>
> Clojure has its own group:
>
> http://groups.google.com/group/clojure
The day I resort to google groups for anything like this is the day I
hang up my official geek hat and pick some football team to start
cheering for. :)
You can do all these things with any Scheme or Lisp implementation that
runs on the JVM.
What does the _language_ offer?
> These days, there are Java libraries to fit nearly any purpose and the
> Hotspot JIT means there's rarely ever a desire to use native code purely
> for speed. And those Java libraries lack the portability issues one
> commonly encounters with C or CL libraries. Scientific computing?
> JScience will work wherever Hotspot runs. Web serving? There are native
> Clojure libraries for that, now -- compojure for one -- and ditto. There
> are even some Clojure libraries that can be used with both Clojure and
> its .NET port, and thus anywhere reached by either the JVM or the CLR.
You're playing the library card again, and again, any Scheme or Lisp
that runs on the JVM would give you the same access to JVM facilities
(which I don't consider a particular advantage).
Again, what does the _language_ offer that makes you choose it over,
say, SISC or Kawa?
Anywhere the JVM + Clojure runs. Right.
> Secondly, what "already existing portable libraries for CL"? It's not
> part of the language standard.
And? Does a ANSI standard forbid the user to write, use or publish
libraries for that language? I haven't heard that.
> If you need a third-party library for it
> at all you've already lost some portability.
In this case I gained portability.
Common Lisp has an independent standard. Clojure does
not have a 'standard' and is a single implementation. So you NEED
the one Clojure and you NEED the JVM (otherwise your
code would not run).
The Common Lisp library for pathnames does not need
a particular implementation and does not need
the JVM.
Result: more options for me.
> >> user=> (directory? "/bin/sh")
> >> false
> >> user=> (directory? "/bin")
> >> true
> >> user=> (directory? "/foo/xyzzy")
> >> false
>
> >> And this will work anywhere a JVM will work.
>
> >> (Of course, paths themselves tend to be system-specific. "/bin" will
> >> produce false on a Windows machine or an older Mac, for example.)
>
> > That was a nice try, but CL is used since 1984 and inherits
> > functionality
> > from before that. We found out how to how to check if a pathname is a
> > directory some time ago, even though this function is not listed in the
> > ANSI Common Lisp standard, but in some library.
>
> Admitting that this kind of basic functionality is missing from the
> language's standard library, decades after it was a known problem with a
> known solution, helps make my point for me, so thanks. :)
Come back if you have a practical problem with pathnames and file I/O
which has not long been solved by users and vendors.
'Official geek hat' and you claim that Common Lisp has no file I/O?
I can't see how this fits together. Plus you refuse to
use Google Groops, where the main Clojure discussion group
is hosted?
Strange.
> WJ <w_a_...@yahoo.com> wrote:
>> Disciples of CommodeLang are the lowest of the low, the vilest
>> of the vile, and the dumbest of the dumb.
>
> I can't tell if I should killfile you or what. You sometimes post lisp
> solutions to things, but then you foam at the mouth for a bit.
>
> Other people who I would totally have figured to have killfiled you
> haven't, so obviously they either think you provide value to the group
> or are at least amusing.
For me it is the latter. Having a jester around is usually thought to
be a royal privilege, and here you get it for free:-)
Nicolas
This is great -- it turned up a bug in my little scheme interpreter.
Do you have any more snippets that a lisp-programmer-since-1976 would
never think of?
If you go to the extreme, replace all list by a structure denoting the
instruction.
(defstruct if test then else)
(defstruct defun name args body)
(defstruct let bindings body)
(defstruct call function arguments)
...
and use the reader for literal structures:
#S(defun :name 'fact :args #(x)
:body #S(if :test #S(call :function '< :arguments #(x 1))
:then 1
:else #S(call :function '* :arguments #(x #S(call :function 'fact
:arguments #(#S(call :function '-
:arguments #(x 1))))))))
This is a sexp. This is homoiconic. This has all the syntax you want.
There's no list in obvious sight (we could substitute the reader macro
for #\' to produce #(quote x) instead of (quote x)). Everybody's happy.
Well but for the macro writers who now need to know in advance the
structures, or we need to add introspection on them, and why not
meta-information explaining which slot is to be evaluated, which won't,
which contain new variable names, etc. Now you can over-engineer all
you want.
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
Exactly. As I said elsewhere, in CL we can have all the parentheses
we want. It is clojure that cannot have less :)
Cheers
--
Marco
Someone needs to hand you a can of Raid and send you down to the
basement Milton-style. Either you're an idiot or you're just trolling
him. I hope you're not an idiot and just a bitter troll that can't
stand that Clojure has some publicity. You and the 8 Smalltalk people
should go cry in a corner together.
He asks a question. You are insulting him.
I hope you're not an idiot, but, honestly, I'm not so sure.
> On Fri, 28 Jan 2011 20:17:56 -0800, David Brown wrote:
>
>> What annoyed me the most about Clojure is that it wasn't really a
>> general-purpose language. There is an intense focuse on parallel
>> programming and immutable data, and other paradigms take back-seat and
>> are often just plain unpleasant to use.
>
> I haven't met a problem yet that Clojure's immutable data, plus a
> sprinkling of refs and atoms, couldn't easily solve. The one time you
> tend to want to do a good old-fashioned iterative loop bashing a mutable
> structure in place is when you really need speed or to limit stress on
> the GC, and then you can always use Java arrays or fall back to actual
> Java for one class.
"Couldn't easily solve" can mean quite a bit. I never said that these
problems were unsolvable. I said that when out of its domain, Clojure
becomes a lot more awkward to use than a more general purpose language,
such as Common Lisp. I suspect we write different kinds of code,
becuase there is a lot more than one time I have to resort to "loop
bashing". I use iterative constructs when that is the best way to
express what I'm trying to solve.
Since I used it, Clojure has gotten a bit better, now that protocols and
more-defined types are more readily available. If it weren't for the
fact that it forced everything to be immutable, it might be a lot more
general purpose.
>> Even the multi-threading on Clojure doesn't work very well when I/O
>> gets involved.
>
> Clojure has a good fit for concurrent I/O tasks in its agent objects. You
> can also use Java's Thread class, java.util.concurrent, and so forth.
My experiences with agents and concurrent I/O was poor. The problem
with the entire Clojure STM/agent model is that there is no way to block
to wait for something. Yes, one agent can do I/O, but nothing else has
any way to actually wait for the results. It forces to invert the
control flow of your entire program to be reactive.
Yes, you can call the Java thread stuff, but it doesn't fit well with
the rest of the language.
>> Common Lisp really is the closest thing I found to truly a general
>> purpose programming language. It's much nicer to adapt the language to
>> my problem rather than forcing the solution to fit the language.
>
> Did I mention that Clojure has a full Lisp macro capability? They're
> hygienic by default but you can escape that if you really must. ~'symbol
> will put raw non-gensym symbols in your macro's output and allow
> deliberate name capture.
You didn't need to. I've written Clojure code. I've studied the
implementation. I've helped find bugs in the compiler. I've looked at
it with expectation, because Rich Hickey is a good speaker, and a smart
man. My expectations have not been met, though. Maybe someday.
>> Also, being on the JVM is fine if you want to interface with Java
>> libraries. As soon as you want to use a library that is native, it is
>> quite a bit more work than something like CFFI.
>
> These days, there are Java libraries to fit nearly any purpose and the
> Hotspot JIT means there's rarely ever a desire to use native code purely
> for speed. And those Java libraries lack the portability issues one
> commonly encounters with C or CL libraries. Scientific computing?
> JScience will work wherever Hotspot runs. Web serving? There are native
> Clojure libraries for that, now -- compojure for one -- and ditto. There
> are even some Clojure libraries that can be used with both Clojure and
> its .NET port, and thus anywhere reached by either the JVM or the CLR.
What frustrates me most about Java is that there aren't very many
implementations. Hotspot picks one set of tradeoffs, which might be
appropriate for some applications. Code runs fast, very fast,
eventually, and as long as you can afford the ridiculous amount of RAM
that it needs. I don't really have much choice when it comes to faster
startup or lower memory footprint, or if I want to deliver an
application as an executable.
I have five free common lisp implementations that I regularly use. Most
of them take very different views on the tradeoffs. One runs on the
JVM. One compiles to byte-code and tends to have a small memory
footprint. Most of them can make executables (of varying size).
The other JVM implementations I'm aware of are generally either based
off of the Hotspot code, very slow, or make most of the same tradeoffs
as Hostspot.
BTW, I think Hotspot is an excellent piece of software. I have been
awestruck at times at how fast the generated code can be. If you stay
away from integer arithmetic, ABCL performs quite well. But, the JVM is
also a fairly specialized execution environment. It is also matched
closely to the Java language, which is dreadful. Most Java libraries I
try to use have overly complex interfaces, largely as a consequence of
how you have to do things in Java.
BTW, when I want to interact directly with the operating system, I have
no choice but to use a native interface. I don't even have to write
this for Common Lisp, since someone already has.
David
This is a very theoretical problem only.
For all practical purposes, you can use this: http://weitz.de/cl-fad/
I don't care what language you or anybody else uses. I'm only asking for
your reasons. Access to Java libraries cannot possibly a reason, because
other Lisps provide that as well (and I'm not particularly interested in
Java, for reasons I already mentioned elsewhere). If publicity is all
that you can come up with, I'm not interested. I'm not saying anything else.
From "Fight Club":
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
> On 29/01/2011 07:54, Deeyana wrote:
>> Secondly, what "already existing portable libraries for CL"? It's not
>> part of the language standard. If you need a third-party library for
>> it at all you've already lost some portability.
>
> This is a very theoretical problem only.
>
> For all practical purposes, you can use this: http://weitz.de/cl-fad/
Unfortunately CL-FAD isn't quite usable for all practical purposes.
;; Here's an unusual but valid Unix pathname:
CL-USER> (sb-ext:native-pathname "[foo]/[bar]*/")
#P"\\[foo]/\\[bar]\\*/"
CL-USER> (cl-fad:pathname-as-file *)
#P"\\[foo]/[bar]*"
The resulting pathname is broken because the [bar]* component became
unescaped and therefore it's a wild pathname component from now on. That
is, it doesn't name a file called "[bar]*".
For pathname handling I prefer IOLIB.PATHNAMES library. It replaces the
CL pathname system with a simpler one.
That's an interesting point, could you elaborate on that? I mean what are
precisely those tradeoffs for different implementations?
That seems more a problem with sb-ext:native-pathname.
* (describe (sb-ext:native-pathname #P"\\[foo]/\\[bar]\\*/"))
#P"\\[foo]/\\[bar]\\*/" is an instance of class #<STRUCTURE-CLASS
PATHNAME>.
The following slots have :INSTANCE allocation:
HOST #<SB-IMPL::UNIX-HOST {1010DAB1}>
DEVICE NIL
DIRECTORY (:RELATIVE "[foo]" "[bar]*")
NAME NIL
TYPE NIL
VERSION NIL
Then CL-FAD does what it can, but it appears to do the the right thing
when on LWM.
> For pathname handling I prefer IOLIB.PATHNAMES library. It replaces the
> CL pathname system with a simpler one.
Too simple and undocumented. Or you could work towards TRT (shameless
plug: "NAMES-AND-PATHS" on common-lisp.net)
> On 29/01/2011 00:24, Deeyana wrote:
>> On Fri, 28 Jan 2011 23:03:05 +0100, Pascal J. Bourguignon wrote:
>>
>>> "jos...@lisp.de"<jos...@lisp.de> writes:
>>>
>>>> On 28 Jan., 16:55, Alessio Stalla<alessiosta...@gmail.com> wrote:
>>>>> On Friday, January 28, 2011 3:56:37 PM UTC+1, Raffael Cavallaro wrote:
>>>>>> On 2011-01-27 21:36:06 -0500, Deeyana said:
>>>>>
>>>>>>> It's a Lisp. Prefix notation, homoiconicity, macros, lists, the
>>>>>>> works.
>>>>>
>>>>>> One of the things that makes a lisp is minimal syntax (it's the
>>>>>> minimal syntax that enables the homoiconicity). Clojure has
>>>>>> significantly more syntax (three different types of semantically
>>>>>> different parens last time I checked) than common lisp or scheme
>>>>>> which makes clojure much less lispy imho.
>>>>>
>>>>> Lisp is not about minimal syntax per se, it's about representing
>>>>> programs as trees and to have program text closely mirror the
>>>>> corresponding tree in the general case. Clojure has a syntax for lists
>>>>> - () - vectors - [] - and maps - {}, as well as numbers and strings
>>>>> and other stuff, and uses all these kinds of objects to represent
>>>>> expressions. Not that different from CL (which lacks syntax for
>>>>> vectors and maps).
>>>>
>>>> Common Lisp has 'syntax' for vectors:
>>>>
>>>> #(1 2 3 I am a vector)
>>>
>>> And happily, it would occur to no lisp programmer to use vectors eg. in
>>> a macro such as:
>>>
>>> (let. #((v 1)
>>> (u 2))
>>> (+ v u))
>>
>> And yet it did occur to at least one Lisp programmer: Rich Hickey.
>
> There have been a lot more in the past.
>
>>> There's clearly no point in doing such a thing.
>>
>> There clearly is, and it is this: Clojure makes a distinction between
>> code that's a data structure and code that's executable.
>
> Discussions about syntax are boring.
>
> Among the major reasons why people are interested in Clojure is that it somehow
> appeals to the idea that it is a "new" Lisp dialect, as if that by itself
> already meant anything; that it somehow makes parallel programming easier,
> which is only true for a narrow scope; and that it runs on top of the JVM,
> which is true for some other implementations of some other Lisp dialects as
> well. It seems to me that the latter is probably the main reason, because
> Clojure makes a few compromises in order to be able to run on the JVM - other
> Lisp dialects have a somewhat harder time to integrate smoothly with the JVM,
> if they want to stick to their original specs.
>
> I don't care at all about JVM, to the contrary, I think the JVM is a pretty bad
> set of compromises that is only relevant because it has industry adoption - but
> from a technical perspective, it's just junk.
>
> I can understand that if you absolutely must use the JVM for some non-technical
> reasons, you might as well want to do it with a layer on top that makes it
> somewhat more bearable.
>
> But why would you want to do that if you have a real choice? (Don't say
> "libraries" now... ;)
>
For me and some others I know, the fact you can use clojure and deploy
easily on the JVM is key. While I use CL for a lot of my own stuff and
for work where it doesn't need to be deployed i.e. is a tool I use,
getting enterprises to accept CL is a huge battle and one I've rarely
run.
Clojure lets me write in something much more pleasant than the
"acceptable" options and I don't get battles to have it deployed. I can
do a job for someone and deliver something they are familiar with and
which deployes using the tools they are comfortable with - often, they
don't even realise it is clojure. Management feels more comfortable as
it is running on the enterprise JVM, which they know from all the
in-flight magazines they read, is the only standard/safe/best practice
enterprise platform. I did consider things like ABCL, but as you point
out, some of the compromises made by Clojure makes the deployment on
existing JVM environments more straight-forward.
No, I don't consider the access to java libraries a major consideration,
though it is useful. I find many java libraries to be slow with overly
complex/engineered APIs and tend to avoid them. However, they are useful
when yo need to intergrate with existing applicaitons.
I would not argue it is a great soolution or even argue the merits of
clojure over something like CL, but from a pragmatic perspective it
allows me to do work with less pain and more enjoyment. Personally, I do
consider it a lisp as it has most of the features I like which are
available in other lisps. Some aspects are frustrating, but I've never
found any environment without some level of frustration.
Tim
--
tcross (at) rapttech dot com dot au
>
> Just to concentrate on the tools and not starting about the other
> points: Eclipse? Maven? Seriously? For one thing every time I've got
> to touch one of the myriads of XML files necessary to configure that
> fine piece of art, I'd rather write me a Makefile by hand (which I'm
> doing, if possible). Currently I'm wrestling with Maven, next on that
> list: merging two projects, one with some slow as hell compiling GWT
> Java-to-Javascript features. The joy.
>
> (If those are not particularly good examples, what are those good
> tools then?)
>
Oh boy do I hear you re: the java tools. Ant, maven, classpaths and all
that xml configuration is a real pain. The obsession Java has with huge,
horrible bits of xml makes me depressed whenever I have to deal with it.
I would be the first to agree that the Java environment was a nightmare.
However, to give some credit, it has been improving and the current
situation is certainly improved from what it was a few years back (don't
get me wrong, it is still overly engineered and complex IMO, but getting
better). However, one of the really nice things about Clojure is that it
does greatly remove much of that pain. For example, Leiningen makes it
almost trivial to define and deploy your Clojure application. In fact, I
found it easier to get started than I did when first using ASDF for CL.
Stil, if I could avoid the JVM and Java and deploy using CL, that would
be my first choice. However, doing so in most moderately complex
enterprises is just a huge battle. Yes, most of the obstacles are not
technical and lot of the problem is FUD, but that doesn't change the
reality. Clojure provides a path which allows me to work with something
a lot less painful than Java and with techniques and some of the
features I enjoy from CL and get paid. To some extent, it helps me
achieve the standard of living which allows me to spend time on other
more interesting projects and ideas where I can choose the technology.
That choice usually involves a more traditional lisp dialect.
Specific to Common Lisp
It would be nice to see that statement backed up by a side by side
comparison of Common Lisp code, Clojure code, and Java code, with
explanations as to how the Clojure code looks more like Java code than
Common Lisp.
> On 29/01/2011 02:00, Deeyana wrote:
>> On Sat, 29 Jan 2011 01:28:38 +0100, Pascal Costanza wrote:
>>
>>> I can understand that if you absolutely must use the JVM for some
>>> non-technical reasons, you might as well want to do it with a layer on
>>> top that makes it somewhat more bearable.
>>>
>>> But why would you want to do that if you have a real choice? (Don't
>>> say "libraries" now... ;)
>>
>> Easy, portable host interop.
>>
>> Common Lisp (other than the variant that runs on the JVM!) provides no
>> easy, portable facilities for presenting a user interface, networking,
>> threading, or even (last I checked) simply working with files. (Even C
>> has a standard facility for file I/O!)
>>
>> Anything on the JVM that can painlessly instantiate and use Java
>> objects, on the other hand, immediately gets file I/O,
>> graphics/GUI/user interface, networking, threading, and a big load of
>> other tools for free, and in a way that works without changing the code
>> on Windows/x86, MacOS/ PPC, Linux/Alpha, and a broad variety of other
>> host architecture/OS combinations.
>
> You can do all these things with any Scheme or Lisp implementation that
> runs on the JVM.
>
> What does the _language_ offer?
Is this a trick question? The Lisp core is, after all, pretty minimalist.
But ...
* Hygienic macros with an escape hatch. Does Scheme have the escape hatch?
* Software transactional memory and a primitive for atomic updates to a
single piece of mutable state.
* Agents, parallel map and reduce, and some other concurrency features.
* Convenient syntax for literal vectors and associative maps.
* Conventions that make "executable" lists like (+ 2 3) and "non-
executable" ones like let bindings look distinct.
* All of the above out-of-the-box, without third-party libraries required.
There is a difference, by the way, between something being a standard
part of the language and being not, but readily available in third-party
libraries. And that is that in the latter case it is likely to be readily
available in *more than one* third-party library, and these are likely to
do things somewhat *differently*, and a user of the language won't be
able to understand all the code using such a feature unless they know
*all* of those libraries, and there will likely be compatibility problems
reusing code that uses one with code that uses another.
Another is that every third-party library acts like a little extra bit of
"weight" on everything that uses it. It's baggage. An application, or
another library, or whatever ends up dragging behind it a chain of
dependencies and the longer and bigger and more complicated that chain
gets the more it causes headaches.
1. Install headaches, especially if end user installation isn't "download
this and run it and it will install all dependencies and run out of
the box". Of course, if it IS, every added dependency that's commonly
used will be one more thing the user ends up with six zillion copies
of cluttering up C:\Program Files or /usr/local/ or wherever and
chewing up disk space.
2. Versioning headaches. Anything built into Clojure, or the large semi-
bundled contrib library, is going to be snapshotted for each Clojure
release, and all the parts in that release will work with one another.
Imagine if some of the above features were third-party. An application
might use ZoobySTM 1.4 for transactional memory and AgentLib 2.8.2 for
agents. The developer has to keep track of all of these libs, AND the
language core, for updates, and changes that might break their app and
that might nonetheless need to be accepted because they fix security
holes or major bugs. The end-user who uses several apps may end up with
a drive cluttered with disparate versions of all of these libs. And
then of course, someone makes a lib that uses ZoobySTM 1.4 and someone
else makes another lib that uses ZoobySTM 1.6 and some developer wants
to use both libs, and the one won't work if the ZoobySTM version used
in the project is not 1.4, but the other won't work if it's not 1.6...
3. Uninstall headaches, especially if "DLL hell" problems are avoided by
making central installations of libraries. I just uninstalled
FluxCapacitor 7.5 in favor of QuantumLeap 8.1; was FC the only thing
still on my system using ZoobySTM 1.4 or will something I use stop
working if I delete the ZoobySTM 1.4 directory to free up drive space?
4. Developer project management headaches. More system search paths, more
classpaths, more -Dxxx flags to the compiler and linker, more things to
add to the project in the IDE, more knobs to twiddle in the IDE to make
those things work, more stuff to remember to bundle with the .exe or
.jar or what-have-you or it won't work out of the box on end user
systems, etc.
5. User general-aggravation headaches. Why is my word processor balking at
opening a random-looking subset of .doc files with "ZoobySTM 1.4 FATAL
ERROR! Too many retries in h_XB197C"?! What does that even *mean*?
6. Support headaches. For every library-related error message as in item 5
that can pop up on an end-user's screen there's one more FAQ to put in
the FAQ, nonetheless frequently hear over the phone, add to the scripts
the call center monkeys in India grind through each time they get a
call, etc.
7. The above goes double if the user can upgrade the library, or something
else they install can upgrade the library, separately from the
application, and their word processor suddenly craps out because it
doesn't work with ZoobySTM 1.6 unless they get a newer version of it,
too, and they don't know that that's what they need to do because all
that happens when they try to start it up now is a silent hang or
a screenful of unintelligible hex dump or something, and there were
half a dozen different things they changed between the last time the
word processor was working and now, none of which are obviously of
relevance to the word processor.
None of this is to say you should never use third-party libraries, of
course! It's just to note that there's a non-zero cost to using them,
which must be outweighed by the benefits, and also that there's a
corresponding cost to not having a piece of functionality distributed
with the language and version-locked to it, and thus a possible benefit
to including such functionality.
As for stuff Clojure gets via the Java standard library, much of that
stuff is stable these days and dependably available wherever the JVM is,
and updates much less frequently than Clojure itself.
That, actually, points to another benefit. Something that's part of the
language core or a *well-tested, widely-used* library like the JVM's will
be generally stabler and better-tested than something that's part of a
separate, third-party library.
In particular, consider Clojure's STM versus a hypothetical Clojure that
lacked it but had ZoobySTM, GnuSTM, TransactaMax and other third-party
STM libraries for it. In the real world, everyone using Clojure's STM is
using, and banging on, the same STM and the result of all that is to get
that one STM implementation debugged and optimized pretty thoroughly, for
everyone.
On the other hand, in the hypothetical world where STM users need to use
a third-party library and the lion's share of the market is divided
roughly evenly among ZoobySTM, GnuSTM, and TransactaMax, each of those
gets only about 1/3 as much testing, bug discovery, and optimization, via
only getting 1/3 as much attention; and the fruits of this in turn go on
to benefit only 1/3 as many people; so the utility generated from testing
ZoobySTM is about 1/9 of that from testing the real world built-in STM.
Adding it up, the utility generated from testing all of them adds up to
about 1/3 that in the real world. Everyone loses out. It's a classic
network effect, where the network loses value when divided into fragments
roughly in proportion to the number of fragments.
That network effect applies even more strongly to the platform choice:
the JVM and the standard Java library. Those are hammered on, and
optimized for, vast numbers of developers working in many languages
including some, like enterprise Java, with vast market share. On the
other hand, the VM and nonportable libraries for, say, Allegro Common
Lisp are hammered on and optimized for only the comparatively tiny market
share of Allegro Common Lisp among developers. It's unsurprising that the
JVM-hosted Lisps, including Clojure, are then likely to beat Allegro (and
many other CLs) in both host interop functionality and VM performance
(JIT and GC particularly).
But whereas the JVM-hosted Common Lisps and Schemes also benefit from
that platform choice, Clojure alone benefits from the in-built facilities
I listed at the top of this post, so far as I am aware, and also from
standardizing the syntax of their use for its whole developer base.
Correction: access to Java libraries cannot possibly be *the sole*
reason. It can still be *one* factor among several weighed when
evaluating different Lisps.
One of the problems I see with Clojure, is that it does not have
objects, but is interfacing with code written in a language that only
has objects. Nothing is more the domain of object oriented programming
than GUIs. To me it doesn't make sense to interface to an OO Gui
library with functions. I believe you can call Clojure from Java, so
if I was doing a desktop GUI app and I wanted to do "concurrency
stuff" in Clojure, I would do the GUI in Java and have it call Clojure
routines.
> On 29 Jan., 07:54, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> First of all, you only have to do it once, and then you can just use
>> directory? anywhere you need it.
>
> Anywhere the JVM + Clojure runs. Right.
Which is, for all practical purposes, just about anywhere these days.
Except the iPhone. And that's all Apple's fault.
>> Secondly, what "already existing portable libraries for CL"? It's not
>> part of the language standard.
>
> And? Does a ANSI standard forbid the user to write, use or publish
> libraries for that language? I haven't heard that.
Of course not. But absence of a fairly basic feature from the standard
language implementation means the proliferation of multiple different and
somewhat incompatible third-party libraries to add the functionality,
which can then clash, for instance when they turn up as second-order
dependencies (I want to use xLib and yLib in my project, and xLib uses
zLib 1.4, and yLib uses qLib 2.7, and zLib and qLib don't get along. OK,
namespaces/packages makes this not as likely now as in bygone days. But
what if xLib uses zLib 1.4 and yLib uses zLib 1.6 and xLib won't work
with any newer zLib than 1.4, nor yLib with any older than 1.6? Needless
to say both zLib versions use the same namespace. Uh-oh...)
>> If you need a third-party library for it at all you've already lost
>> some portability.
>
> In this case I gained portability.
I very much doubt that. Every added dependency to your project can reduce
its portability; none can raise it.
> Common Lisp has an independent standard. Clojure does not have a
> 'standard' and is a single implementation. So you NEED the one Clojure
> and you NEED the JVM (otherwise your code would not run).
How fortunate. That means there aren't a proliferation of slightly
different and incompatible variations to worry about -- just a linear
chain of Clojure versions, and a linear chain of Java versions for the
underlying platform. And the JVM runs almost everywhere, and clojure.jar
can be downloaded for free and used with any JVM that meets Sun's (now
Oracle's) specifications.
> The Common Lisp library for pathnames does not need a particular
> implementation and does not need the JVM.
But of course it does. If it does something the language standard doesn't
specify a portable way to do, then it must do so by using FFI to call
into an external module, likely C code. Which then has to be modified and
recompiled for every environment. Every Common Lisp probably has its own
slightly different and idiosyncratic FFI calling convention, so the C
code must be adapted for different Common Lisps. Every machine
architecture requires the C be recompiled, and every OS likewise, and in
some cases the C may also need to be tweaked. (OK, for something you can
do with C stdio that last is unlikely. If we were talking a graphics
library it would be a whole 'nother ball game -- different versions
having to be maintained for every combination of OS, machine
architecture, and Common Lisp variant!)
> Result: more options for me.
I think you misspelled a word there, perhaps "headaches".
>> Admitting that this kind of basic functionality is missing from the
>> language's standard library, decades after it was a known problem with
>> a known solution, helps make my point for me, so thanks. :)
>
> Come back if you have a practical problem with pathnames and file I/O
> which has not long been solved by users and vendors.
I have: how to do it in a manner that just means writing one little sexp
and having it work in every version, by every vendor, on every machine,
on every OS, without modification or the need to have the right version
of some little .dll or .so file sitting in the system path.
Except that I don't have that problem, because that directory? function I
wrote works on any Clojure version thus far released on any 1.5 or 1.6
JVM that meets Sun's (now Oracle's) specifications on any OS/hardware
combination that has such a JVM.
> On 29/01/2011 08:10, Deeyana wrote:
>
>> These days, there are Java libraries to fit nearly any purpose and the
>> Hotspot JIT means there's rarely ever a desire to use native code
>> purely for speed. And those Java libraries lack the portability issues
>> one commonly encounters with C or CL libraries. Scientific computing?
>> JScience will work wherever Hotspot runs. Web serving? There are native
>> Clojure libraries for that, now -- compojure for one -- and ditto.
>> There are even some Clojure libraries that can be used with both
>> Clojure and its .NET port, and thus anywhere reached by either the JVM
>> or the CLR.
>
> You're playing the library card again, and again, any Scheme or Lisp
> that runs on the JVM would give you the same access to JVM facilities
> (which I don't consider a particular advantage).
See my other post on this topic.
> Again, what does the _language_ offer that makes you choose it over,
> say, SISC or Kawa?
See my other post on this topic.
Pascal and Roswig are both hardore fagott assholes.
Both these assholes (Rawain and Pascal) are both bad actors.
Pascal Costansta and that other asshole Rainer
I just went back and reread "Beating the Averages"
http://www.paulgraham.com/avg.html
and noticed that he does say Lisp everywhere, rather than Common Lisp
(with the exception of his book title which is Ansi Common Lisp). I
remembered that story as starting with "we had an advantage using
Lisp" and ending with "we sold to Yahoo who ended up rewriting it in C+
+". But now I see that Paul Graham and his ViaWeb co-workers were not
just using Lisp, but also C and Perl??
>
> Jeffrey M. Jacobs:
> CL is a nightmare; it has effectively killed LISP
> development in this country. It is not commercially viable
> and has virtually no future outside of the traditional
> academic/defense/research arena.
What were his objections to Common Lisp, versus prior Lisp dialects?
>
> Dick Gabriel:
> Common Lisp is a significantly ugly language. If Guy and I
> had been locked in a room, you can bet it wouldn't have
> turned out like that.
What are the parts he considers ugly?
>
> Bernard Lang:
> Common Lisp did kill Lisp. Period. (just languages take a
> long time dying ...) It is to Lisp what C++ is to C. A
> monstrosity that totally ignores the basics of language
> design, simplicity and orthogonality to begin with.
>
I am gonna guess and say that a majority of the people who use
"orthogonality" when talking about a programming language, don't have
a problem with Common Lisp.
You are interacting with a Ruby programmer on a Common Lisp newsgroup
about Common Lisp and Ruby. That should not be compared with
interacting with Ruby programmers on a Ruby newsgroup about Ruby.
> On Fri, Jan 28 2011, Deeyana wrote:
>
>> On Fri, 28 Jan 2011 20:17:56 -0800, David Brown wrote:
>>
>>> What annoyed me the most about Clojure is that it wasn't really a
>>> general-purpose language. There is an intense focuse on parallel
>>> programming and immutable data, and other paradigms take back-seat and
>>> are often just plain unpleasant to use.
>>
>> I haven't met a problem yet that Clojure's immutable data, plus a
>> sprinkling of refs and atoms, couldn't easily solve. The one time you
>> tend to want to do a good old-fashioned iterative loop bashing a
>> mutable structure in place is when you really need speed or to limit
>> stress on the GC, and then you can always use Java arrays or fall back
>> to actual Java for one class.
>
> "Couldn't easily solve" can mean quite a bit. I never said that these
> problems were unsolvable. I said that when out of its domain, Clojure
> becomes a lot more awkward to use than a more general purpose language,
> such as Common Lisp. I suspect we write different kinds of code,
> becuase there is a lot more than one time I have to resort to "loop
> bashing". I use iterative constructs when that is the best way to
> express what I'm trying to solve.
Have you got a specific example?
> Since I used it, Clojure has gotten a bit better, now that protocols and
> more-defined types are more readily available. If it weren't for the
> fact that it forced everything to be immutable, it might be a lot more
> general purpose.
Even before discovering Clojure, as a Java developer I was leaning more
and more towards making most of my objects immutable and generating new,
modified instances rather than modifying-in-place. It simplifies a bunch
of things, including aliasing bugs and concurrency, and forces you to
think about when you really do need a piece of mutable state shared
between two areas of your code, and then you make a mutable thing there
and take care that its update and access semantics work properly and are
appropriately synchronized, etc. -- which you have to worry about with
any piece of shared mutable state anyway, or else you'll get bugs.
>>> Even the multi-threading on Clojure doesn't work very well when I/O
>>> gets involved.
>>
>> Clojure has a good fit for concurrent I/O tasks in its agent objects.
>> You can also use Java's Thread class, java.util.concurrent, and so
>> forth.
>
> My experiences with agents and concurrent I/O was poor. The problem
> with the entire Clojure STM/agent model is that there is no way to block
> to wait for something. Yes, one agent can do I/O, but nothing else has
> any way to actually wait for the results.
Clojure has had (await & agts) and (await-for timeout & agts) since
version 1.0. Not to mention Java's Thread.join() method if you directly
use Java's concurrency classes.
There are lots of options for both blocking and nonblocking I/O in
Clojure, including also the obvious for blocking I/O, which is to do it
in the current thread. (If you're worried about clogging up Swing's EDT,
don't be -- either just proxy SwingWorker, using that more or less the
way you would from Java, or use an agent that executes something like
(fn [state]
(do-whatever-blocking-I/O)
(SwingUtilities/invokeLater #(gui-code-goes-here))
(compute-the-new-agent-state))
Substitue SwingUtilities/invokeAndWait if you don't want the agent state
change to take place (and anything awaiting the agent to wake up) until
the GUI code has executed.
> It forces to invert the
> control flow of your entire program to be reactive.
Sometimes that isn't such a bad thing; but it's often not really the
case. If reactive is a very bad fit to your particular problem, then
agents may be a very bad fit and imperative I/O in a single thread may be
better.
> Yes, you can call the Java thread stuff, but it doesn't fit well with
> the rest of the language.
You can always create your own functions, control structures, or even
full-blown DSL to wrap the Java thread stuff and tailor that DSL to your
problem domain.
Actually, though, I think you just didn't learn enough of the language;
you didn't know about await and await-for and I have to wonder what else
was there that you also missed, and felt to be a hole in the language.
>> Did I mention that Clojure has a full Lisp macro capability? They're
>> hygienic by default but you can escape that if you really must.
>> ~'symbol will put raw non-gensym symbols in your macro's output and
>> allow deliberate name capture.
>
> You didn't need to. I've written Clojure code. I've studied the
> implementation. I've helped find bugs in the compiler. I've looked at
> it with expectation, because Rich Hickey is a good speaker, and a smart
> man. My expectations have not been met, though. Maybe someday.
Or maybe you just haven't looked hard enough.
>> These days, there are Java libraries to fit nearly any purpose and the
>> Hotspot JIT means there's rarely ever a desire to use native code
>> purely for speed. And those Java libraries lack the portability issues
>> one commonly encounters with C or CL libraries. Scientific computing?
>> JScience will work wherever Hotspot runs. Web serving? There are native
>> Clojure libraries for that, now -- compojure for one -- and ditto.
>> There are even some Clojure libraries that can be used with both
>> Clojure and its .NET port, and thus anywhere reached by either the JVM
>> or the CLR.
>
> What frustrates me most about Java is that there aren't very many
> implementations. Hotspot picks one set of tradeoffs, which might be
> appropriate for some applications. Code runs fast, very fast,
> eventually, and as long as you can afford the ridiculous amount of RAM
> that it needs. I don't really have much choice when it comes to faster
> startup or lower memory footprint, or if I want to deliver an
> application as an executable.
The JVM serves a very large and increasingly diverse market of
developers. Any widely-felt need is likely to get met, if not by future
Hotspot versions, then by other vendors at some point or another.
Whereas the VM underlying a random, particular VM-based Common Lisp
implementation is probably used by only a very small number of
developers, gets relatively little testing and attention, has relatively
little resource devoted to improving it, and is unlikely to spawn any
disparate versions that make different tradeoffs at all.
> I have five free common lisp implementations that I regularly use. Most
> of them take very different views on the tradeoffs. One runs on the
> JVM. One compiles to byte-code and tends to have a small memory
> footprint. Most of them can make executables (of varying size).
And your code has to be tweaked at least a little to be moved from one to
another.
And you can make cleanly installable binaries with Java. Programs like
Frostwire and NetBeans are easy to download and install, even for non-
developers. (Surprisingly so, in the latter case, given who its target
audience is.)
> BTW, I think Hotspot is an excellent piece of software. I have been
> awestruck at times at how fast the generated code can be. If you stay
> away from integer arithmetic, ABCL performs quite well.
Clojure has ways to even make integer arithmetic run with blazing speed.
> But, the JVM is also a fairly specialized execution environment. It is
> also matched closely to the Java language, which is dreadful.
But does this make the JVM itself dreadful in any particular way?
> Most Java libraries I try to use have overly complex interfaces,
> largely as a consequence of how you have to do things in Java.
Fortunately, you can create Clojure wrappers for these that have very
clean APIs. And someone else might have already done so, if the Java
library is particularly widely used and particularly awful to use.
> BTW, when I want to interact directly with the operating system, I have
> no choice but to use a native interface. I don't even have to write
> this for Common Lisp, since someone already has.
Java has libraries covering nearly every conceivable such need. MIDI? In
javax.sound. MP3 playback? Likewise. 3D hardware acceleration? Java 3D.
Accelerated 2D graphics? Java 2D. There are ways to get joystick and
other input. There are even game libraries. There's even at least one
*Clojure* game library. Raw I/O? Gotcha -- ByteBuffer and friends and
some of the stream classes that come with Java.
About the only things I can think of that would be problematic are:
* Creating services. Because of the RAM use, as well as the OS-dependent
nature of that sort of thing, this is a poor fit to the JVM in general.
* Minimizing to the dock/tray. Again pretty OS-dependent. Then again
Frostwire does so and is implemented in Java so it seems there's a Java
library even for that.
* Reading the funny extra keys on a lot of keyboard these days -- media
play/pause/stop buttons, Windows keys, and suchlike. Of course these
aren't reliably available even on a fixed OS/architecture pair!
* Anything that has to run in kernel mode (virus scanners, firewalls,
OS extensions of assorted kinds, device drivers...) But the JVM would
again be a poor fit to anything similar.
So, Clojure is not a silver bullet that can replace every other
programming language entirely. (What would you use to implement the VM
and compiler classes, if it were? What would the hardware CPU
instructions be?) But then, neither is anything else.
> On 29 Jan., 08:11, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> On Fri, 28 Jan 2011 19:05:12 -0800, jos...@lisp.de wrote:
>> > On 28 Jan., 01:56, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> >> Are there any Clojure users here? Or is this group specific to
>> >> Common Lisp?
>>
>> >> I just sampled a few posts and they all seem to be Common Lisp
>> >> related. Except for the EVERY TIME I COME TO THIS GROUP thread. I
>> >> don't know *what*'s up with that but it doesn't seem to have to do
>> >> with any flavor of Lisp at all. Not unless Scotty uses Lisp to
>> >> program a transporter beam that's fueled by thallium, anyway.
>>
>> > Clojure has its own group:
>>
>> >http://groups.google.com/group/clojure
>>
>> The day I resort to google groups for anything like this is the day I
>> hang up my official geek hat and pick some football team to start
>> cheering for. :)
>
> 'Official geek hat' and you claim that Common Lisp has no file I/O?
No, I claim that its standard fails to specify portable ways to do
specific, common file I/O tasks; not quite the same thing.
> Plus you refuse to use Google Groops
Lots of people do, save as an archive (and one whose search is
increasingly shoddy, to the point I've about given up on it for even
that).
> Exactly. As I said elsewhere, in CL we can have all the parentheses we
> want. It is clojure that cannot have less :)
This has been debated endlessly among Clojure users, from what I gather,
and the general consensus has apparently been that keeping the basic
syntax of the language consistent for all users is a bigger benefit than
allowing custom reader macros would be, given the small set of reader
macros already provided to cover the most pressing needs (such as compact
lambdas, quoting, etc.); clojure code is generally readable by any
proficient Clojure user.
I don't use a 'standard' to program. I use implementations +
libraries.
Clojure doesn't even have a standard.
> > Plus you refuse to use Google Groops
>
> Lots of people do, save as an archive (and one whose search is
> increasingly shoddy, to the point I've about given up on it for even
> that).
Funky, the general Clojure community doesn't seem to have a
problem with that. People ask questions, get answers,
discuss, ...
Being based on the JVM does greatly simplify cross-platform
development. But I would bet the "traction" Clojure is getting right
now is coming from the fact that people in a J2EE web development shop
can deploy Clojure apps alongside their Java apps (same for Scala/
Groovy/JRuby/Jython). And these rogrammers are increasingly interested
in concurrency and Functional Programming. It is surprising to see
Functional Programming getting so much buzz now, and at the expense of
Object-Oriented programming.
>
> > Anyway, last time I checked, programming with Swing was a nightmare. It
> > may certainly be that using it with a Lisp (or any more dynamic
> > language) and macros might decrease the pain to acceptable levels -
> > still doubting it, though.
If one were going to rate GUI APIs I don't think Java Swing would be
anywhere near the "nightmare" level. The simpler GUI programming via
Java Swing versus C++ alternatives like Microsoft's MFC caused
corporate desktop programmers to migrate to Java. But QT and
particularly FLTK have simplified C++ GUI programming these days.
Still I don't need it. I can interface the OS and
use a huge amount of libraries without the JVM.
> >> Secondly, what "already existing portable libraries for CL"? It's not
> >> part of the language standard.
>
> > And? Does a ANSI standard forbid the user to write, use or publish
> > libraries for that language? I haven't heard that.
>
> Of course not. But absence of a fairly basic feature from the standard
> language implementation
'standard language implementation'? What is that? There is no one.
The implementation I currently use has this functionality.
Portably.
> means the proliferation of multiple different and
> somewhat incompatible third-party libraries to add the functionality,
> which can then clash, for instance when they turn up as second-order
> dependencies (I want to use xLib and yLib in my project, and xLib uses
> zLib 1.4, and yLib uses qLib 2.7, and zLib and qLib don't get along. OK,
> namespaces/packages makes this not as likely now as in bygone days. But
> what if xLib uses zLib 1.4 and yLib uses zLib 1.6 and xLib won't work
> with any newer zLib than 1.4, nor yLib with any older than 1.6? Needless
> to say both zLib versions use the same namespace. Uh-oh...)
What are you talking about? You were claiming that Common Lisp has
no file I/O. I mentioned that Common Lisp has file I/O and that
missing functionality is provided in libraries.
Now you make up hypothetical problems. Why?
> >> If you need a third-party library for it at all you've already lost
> >> some portability.
>
> > In this case I gained portability.
>
> I very much doubt that. Every added dependency to your project can reduce
> its portability; none can raise it.
Right, I can get rid of the JVM and use the OS directly.
> > Common Lisp has an independent standard. Clojure does not have a
> > 'standard' and is a single implementation. So you NEED the one Clojure
> > and you NEED the JVM (otherwise your code would not run).
>
> How fortunate. That means there aren't a proliferation of slightly
> different and incompatible variations to worry about -- just a linear
> chain of Clojure versions, and a linear chain of Java versions for the
> underlying platform. And the JVM runs almost everywhere, and clojure.jar
> can be downloaded for free and used with any JVM that meets Sun's (now
> Oracle's) specifications.
If that's important, I can use ABCL. With the benefit
of a standard and a portable language.
> > The Common Lisp library for pathnames does not need a particular
> > implementation and does not need the JVM.
>
> But of course it does. If it does something the language standard doesn't
> specify a portable way to do, then it must do so by using FFI to call
> into an external module, likely C code. Which then has to be modified and
> recompiled for every environment.
No, I just need the host OS to get information about files.
> Every Common Lisp probably has its own
> slightly different and idiosyncratic FFI calling convention, so the C
> code must be adapted for different Common Lisps.
That's why there are common FFIs.
> Every machine
> architecture requires the C be recompiled, and every OS likewise, and in
> some cases the C may also need to be tweaked. (OK, for something you can
> do with C stdio that last is unlikely. If we were talking a graphics
> library it would be a whole 'nother ball game -- different versions
> having to be maintained for every combination of OS, machine
> architecture, and Common Lisp variant!)
I don't need to write any C to talk to the host OS and other
libraries in CL implementations.
> > Result: more options for me.
>
> I think you misspelled a word there, perhaps "headaches".
???
> >> Admitting that this kind of basic functionality is missing from the
> >> language's standard library, decades after it was a known problem with
> >> a known solution, helps make my point for me, so thanks. :)
>
> > Come back if you have a practical problem with pathnames and file I/O
> > which has not long been solved by users and vendors.
>
> I have: how to do it in a manner that just means writing one little sexp
> and having it work in every version, by every vendor, on every machine,
> on every OS, without modification or the need to have the right version
> of some little .dll or .so file sitting in the system path.
>
> Except that I don't have that problem, because that directory? function I
> wrote works on any Clojure version thus far released on any 1.5 or 1.6
> JVM that meets Sun's (now Oracle's) specifications on any OS/hardware
> combination that has such a JVM.
Fine for you.
The CL function I use also works on every platform I use or likely
would use.
> It is surprising to see Functional Programming getting so much buzz
> now, and at the expense of Object-Oriented programming.
Having to deal with concurrency can have that effect on you. Every
functional bit can be parallelized fairly easily, versus anything that's
heavily laden with mutable state.
> On 30 Jan., 02:52, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> On Sat, 29 Jan 2011 01:51:28 -0800, jos...@lisp.de wrote:
>> > On 29 Jan., 08:11, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> >> On Fri, 28 Jan 2011 19:05:12 -0800, jos...@lisp.de wrote:
>> >> > On 28 Jan., 01:56, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> >> >> Are there any Clojure users here? Or is this group specific to
>> >> >> Common Lisp?
>>
>> >> >> I just sampled a few posts and they all seem to be Common Lisp
>> >> >> related. Except for the EVERY TIME I COME TO THIS GROUP thread. I
>> >> >> don't know *what*'s up with that but it doesn't seem to have to
>> >> >> do with any flavor of Lisp at all. Not unless Scotty uses Lisp to
>> >> >> program a transporter beam that's fueled by thallium, anyway.
>>
>> >> > Clojure has its own group:
>>
>> >> >http://groups.google.com/group/clojure
>>
>> >> The day I resort to google groups for anything like this is the day
>> >> I hang up my official geek hat and pick some football team to start
>> >> cheering for. :)
>>
>> > 'Official geek hat' and you claim that Common Lisp has no file I/O?
>>
>> No, I claim that its standard fails to specify portable ways to do
>> specific, common file I/O tasks; not quite the same thing.
>
> I don't use a 'standard' to program. I use implementations + libraries.
>
> Clojure doesn't even have a standard.
No, it has an implementation and libraries that happen to be pretty much
write-once-run-anywhere.
Unlike your implementations + libraries. :)
There isn't a lot of trouble interfacing with Java from Clojure,
actually. Static methods are basically just functions, and instance
methods are just functions with a funny argument syntax of
arg1.function(arg2, arg3, arg4);
vs. C's
function(arg1, arg2, arg3, arg4)
or Lisp's
(function arg1 arg2 arg3 arg4)
and Clojure makes these fairly obvious transformations:
System.nanoTime() => (System/nanoTime)
Collections.sort(foo) => (Collections/sort foo)
stream.print("string") => (.print stream "string")
The "new" operator is likewise transformed into a function:
new WeakReference<Keyword>(foo) => (new WeakReference foo)
Note that Java generics disappear. Clojure is strongly and dynamically
typed, with the option to hint the expected types of arguments and other
values. This results in more efficient code, and *sometimes* (but that's
not its purpose) in error messages when there's a type error. (It also
does not have the notion of "checked exceptions". Whoopee!)
> On 30 Jan., 02:26, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> On Sat, 29 Jan 2011 01:46:47 -0800, jos...@lisp.de wrote:
>> > On 29 Jan., 07:54, Deeyana <d.awlb...@hotmail.invalid> wrote:
>> >> First of all, you only have to do it once, and then you can just use
>> >> directory? anywhere you need it.
>>
>> > Anywhere the JVM + Clojure runs. Right.
>>
>> Which is, for all practical purposes, just about anywhere these days.
>> Except the iPhone. And that's all Apple's fault.
>
> Still I don't need it. I can interface the OS and use a huge amount of
> libraries without the JVM.
Portable ones that work the same practically everywhere?
>> Of course not. But absence of a fairly basic feature from the standard
>> language implementation
>
> 'standard language implementation'? What is that? There is no one. The
> implementation I currently use has this functionality. Portably.
How portably? Will your code work for someone using a different
implementation? What if they're on a different OS?
>> means the proliferation of multiple different and somewhat incompatible
>> third-party libraries to add the functionality, which can then clash,
>> for instance when they turn up as second-order dependencies (I want to
>> use xLib and yLib in my project, and xLib uses zLib 1.4, and yLib uses
>> qLib 2.7, and zLib and qLib don't get along. OK, namespaces/packages
>> makes this not as likely now as in bygone days. But what if xLib uses
>> zLib 1.4 and yLib uses zLib 1.6 and xLib won't work with any newer zLib
>> than 1.4, nor yLib with any older than 1.6? Needless to say both zLib
>> versions use the same namespace. Uh-oh...)
>
> What are you talking about? You were claiming that Common Lisp has no
> file I/O.
No, I wasn't. I claimed that its standard fails to specify portable ways
to do specific, common file I/O tasks; not quite the same thing.
> I mentioned that Common Lisp has file I/O and that missing
> functionality is provided in libraries.
Libraries that you have to get elsewhere than with your language
implementation, and that may vary from one another.
> Now you make up hypothetical problems. Why?
No, I describe genuine problems that developers genuinely have to contend
with when the dependency trees on their projects get big and convoluted
enough, and especially when two libraries they use directly depend on
different versions of the same third library.
>> >> If you need a third-party library for it at all you've already lost
>> >> some portability.
>>
>> > In this case I gained portability.
>>
>> I very much doubt that. Every added dependency to your project can
>> reduce its portability; none can raise it.
>
> Right, I can get rid of the JVM and use the OS directly.
Getting rid of the JVM reduces portability. The JVM isn't a library; it's
an emulated platform and one with ports to nearly every substrate.
Going from JVM to non-JVM is like (though sometimes not as bad as) going
from Windows-only to Mac-only in terms of a drop in the number of
machines you can run on.
>> How fortunate. That means there aren't a proliferation of slightly
>> different and incompatible variations to worry about -- just a linear
>> chain of Clojure versions, and a linear chain of Java versions for the
>> underlying platform. And the JVM runs almost everywhere, and
>> clojure.jar can be downloaded for free and used with any JVM that meets
>> Sun's (now Oracle's) specifications.
>
> If that's important, I can use ABCL. With the benefit of a standard and
> a portable language.
How does that benefit you?
If you intend to port your code to other Common Lisps, that will not be
easy unless you avoid using any JVM interop features of ABCL to call Java
libraries, and avoid using any ABCL-specific features, and then you lose
the benefit of Java's huge standard library and a lot of the benefit of
the JVM. It becomes just another VM-hosted Common Lisp, albeit one whose
VM is better tested, better optimized, and more widely ported than most.
You lose the ability to have better-than-C-level portability of
functionality like graphics and sound and threading. And you won't have
good C FFI unlike with other Common Lisps, either, nor will you be able
to use any CL libraries that depend on C FFI.
On the other hand, if you embrace ABCL-specific features and/or Java
library FFI, you gain a lot of the things that you'd gain by using
Clojure and lose almost *everything* you'd lose by using Clojure,
including easy portability to other CL implementations.
You don't gain *everything* you'd gain by using Clojure, though. You
trade away Clojure's uniform vector/map syntax, STM, immutability, and
other benefits (mostly focused around better collection and sequence
libraries and immutability/concurrency/FP) and gain the ability to use a
large subset of the CL libraries that don't rely on FFI. And Clojure
allows superior arithmetic performance in some cases to ABCL.
Maybe that trade-off is worth it to you, but if so I'd be curious which
CL libraries you think make it worth it.
>> But of course it does. If it does something the language standard
>> doesn't specify a portable way to do, then it must do so by using FFI
>> to call into an external module, likely C code. Which then has to be
>> modified and recompiled for every environment.
>
> No, I just need the host OS to get information about files.
Which you can't access portably from Common Lisp.
>> Every machine
>> architecture requires the C be recompiled, and every OS likewise, and
>> in some cases the C may also need to be tweaked. (OK, for something you
>> can do with C stdio that last is unlikely. If we were talking a
>> graphics library it would be a whole 'nother ball game -- different
>> versions having to be maintained for every combination of OS, machine
>> architecture, and Common Lisp variant!)
>
> I don't need to write any C to talk to the host OS and other libraries
> in CL implementations.
You might not have to, but someone had to. It will be some feature of the
particular implementation you use, or some library you use. But there
won't be any standard way in Common Lisp's hyperspec to, say, make an MS-
DOS system call or read a Windows Registry key.
What would the Clojure equivalent to this look like?
_________________________________________________________________________
import javax.swing.*;
import java.awt.event.*;
public class SwingHelloWorld extends JFrame {
public static void main(String args[])
{
new SwingHelloWorld();
}
SwingHelloWorld()
{
JLabel jlbHelloWorld = new JLabel("Hello Swing World!");
add(jlbHelloWorld);
this.setSize(200, 100);
setVisible(true);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
dispose();
System.exit(0);
}
});
}
}
_______________________________________________________________________________
> (It also
> does not have the notion of "checked exceptions". Whoopee!)
I actually prefer forcing programmers to add some kind of exception
handler for exceptions that could be thrown. And hopefully those won't
be {}
>> There isn't a lot of trouble interfacing with Java from Clojure,
>> actually.
>
> What would the Clojure equivalent to this look like?
>
_________________________________________________________________________
> import javax.swing.*;
> import java.awt.event.*;
>
> public class SwingHelloWorld extends JFrame {
>
> public static void main(String args[]) {
> new SwingHelloWorld();
> }
> SwingHelloWorld()
> {
> JLabel jlbHelloWorld = new JLabel("Hello Swing World!");
> add(jlbHelloWorld);
> this.setSize(200, 100);
> setVisible(true);
> addWindowListener(new WindowAdapter() {
> public void windowClosing(WindowEvent e) {
> dispose();
> System.exit(0);
> }
> });
> }
> }
Equivalent in functionality?
(ns foo.swing-hello-world
(:import
(java.awt.event WindowAdapter)
(javax.swing JFrame JLabel))
(:gen-class))
(defn -main [& args]
(SwingUtilities/invokeLater
#(let [f (JFrame.)]
(doto f
(.add (JLabel. "Hello Swing World!"))
(.setSize 200 100)
(.setVisible true)
(.addWindowListener
(proxy [WindowAdapter] []
(windowClosing [e]
(.dispose f)
(System/exit 0))))))))
You can see that with the "doto" macro this is actually very similar to
the Java code. Of course, the further away a real application's code was
from the direct interface to Swing, the Lispier it would get, and the
more functional and less imperative.
I've also fixed the minor bug in your code, to wit, it did Swing
construction and work off of the EDT. :)
>> (It also
>> does not have the notion of "checked exceptions". Whoopee!)
>
> I actually prefer forcing programmers to add some kind of exception
> handler for exceptions that could be thrown.
I don't. It causes Java programmers all kinds of headaches, particularly
at layer boundaries, and it, along with requiring types for every
reference, is simply incompatible with decent functional programming --
look at how hairy C syntax gets when function pointers are involved, let
alone function pointers for types of function that take more function
pointers and return function pointers. Add in generics, which would be
crucial for giving types to generic functions like map and reduce, and
the need to have some way to specify that mapping a function that throws
checked exception X causes the map expression to be able to throw checked
exception X without having to simply specify that map itself can throw
anything (and so anything that uses map can throw anything) ... and
you'll get a syntax-crufted nightmare that's either as verbose as Java
and very non-Lispy or else is so full of abbreviated type warts it looks
like line noise. Otherwise known as Haskell. ;)
The lack of types and exception declarations everywhere would seem to
make catching bugs by compile time much harder, and it can do; but
catching bugs at runtime is a lot easier with a REPL and actually
tracking them down is a lot easier when much of the code is functional.
If your (foo ...) function call threw a NullPointerException and is pure
functional then either it contains a bug or it was passed a precondition
violating argument, likely nil or a collection containing a nil where the
nil shouldn't have been there. In imperative code, foo could as easily
have thrown because it removes objects from a mutable map and invokes
methods on them and a null has been lurking in that map like a ticking
time bomb since some bug in some other code put it in there hours ago.
Of course, the bits of your code that are imperative can still have that
type of problem. A lot of that is at the interface with the host, though
-- Swing code, I/O code. Swing code throws because of precondition
violations or internal bugs, for the most part, and sometimes because of
unanticipated user input. With I/O code you may have trusted data from
the disk or the wire that should have been validated.
That leaves any atoms, agents, or STM in your code. If you're keeping
this sort of mutable state to a minimum there are simply not very many
places for your error to be creeping in. And Clojure provides a debugging
tool for this: you can set a validator on anything like that that will
throw an exception eagerly as soon as an invalid value (as determined by
code you write to test it) gets put in there. If you get an NPE in foo
and it turns out it dereferenced a ref and got nil and it shouldn't ever
be nil, add a validator to that ref that throws on nil. (You can just use
identity if it should never be boolean false either, or (comp not nil?)
otherwise -- no need for even an anonymous lambda there.) Then rerun your
tests and this time you'll get an exception close to where the bug really
lies. The stack trace should lead you directly to the culprit, unless of
course the nil came from, say, an agent state that should never be nil.
And then another validator will get you another step closer to the real
culprit, and so on.
So, FP plus limited mutable state plus the ability to put validators on
the mutable bits equals much easier tracing of bugs that are not caught
by a compiler-enforced type system or by compiler-enforced exception
handling at compile time.
And really, when you look deeply into it, the checked exceptions emperor
has no clothes. Nominally, checked exceptions should represent exceptions
that can happen in bug-free code due to outside conditions, and unchecked
exceptions exceptions that mean your code has a bug, but what does that
really leave as checked exceptions? IOException, basically. In practise a
variety of parsing exceptions are checked, such as MalformedURLException,
yet sometimes the thing being parsed is external and sometimes it's a
literal in your own code. IOExceptions sometimes should never happen
without a bug, for example in a method that should see if a file already
exists, if not create it and return a reference to it, and if it already
exists or otherwise cannot be created return null. Sometimes the checked-
or-not status of an exception class seems to be been decided on a whim,
rather than from any deep reasoning. And it's the poor Java programmer
that ends up having to sort the whole mess out, often resulting in
catching and ignoring a "should never happen" exception as a lazy way of
satisfying the compiler. If a bug then causes that exception somehow, it
may be masked for some time, until it causes problems elsewhere. In
Clojure you'd just ignore the possibility of the exception if you never
expected it to actually get thrown, and if it ever did you'd get an
immediate stacktrace since you didn't bother to catch it, and then you'd
know about it and could either fix your code so it *really* couldn't
happen or add a handler so your code can deal with it if it does.
> On Jan 29, 9:42 pm, Teemu Likonen <tliko...@iki.fi> wrote:
>> Unfortunately CL-FAD isn't quite usable for all practical purposes.
>>
>> ;; Here's an unusual but valid Unix pathname:
>> CL-USER> (sb-ext:native-pathname "[foo]/[bar]*/")
>> #P"\\[foo]/\\[bar]\\*/"
>>
>> CL-USER> (cl-fad:pathname-as-file *)
>> #P"\\[foo]/[bar]*"
>>
>> The resulting pathname is broken because the [bar]* component became
>> unescaped and therefore it's a wild pathname component from now on.
>> That is, it doesn't name a file called "[bar]*".
>
> That seems more a problem with sb-ext:native-pathname.
It works fine. Let's say that a CL program gets a filename string from
command line: "[foo]/[bar]*/". That string absolutely can't be used
directly (nor through PATHNAME function) with CL functions because they
will interpret those special characters. SB-EXT:NATIVE-PATHNAME or
SB-EXT:PARSE-NATIVE-NAMESTRING convert the string to CL pathname in a
way that all components remain literal components.
The expected result in POSIX systems is that user's command-line
interpreter expands special characters and programs see only literal
pathnames. There should be an explicit action from programmer if some
characters in a pathname are to be interpreted specially.
> * (describe (sb-ext:native-pathname #P"\\[foo]/\\[bar]\\*/"))
>
> #P"\\[foo]/\\[bar]\\*/" is an instance of class #<STRUCTURE-CLASS
> PATHNAME>.
> The following slots have :INSTANCE allocation:
> HOST #<SB-IMPL::UNIX-HOST {1010DAB1}>
> DEVICE NIL
> DIRECTORY (:RELATIVE "[foo]" "[bar]*")
> NAME NIL
> TYPE NIL
> VERSION NIL
That looks good to me, in SBCL's context at least.
> Then CL-FAD does what it can, but it appears to do the the right thing
> when on LWM.
Maybe CL-FAD does what it can but I think it still does wrong things
because it turns literal pathname component to a wild component:
CL-USER> (make-pathname :directory '(:relative "foo" "*"))
#P"foo/\\*/"
CL-USER> (describe *)
#P"foo/\\*/"
[structure-object]
Slots with :INSTANCE allocation:
HOST = #<SB-IMPL::UNIX-HOST {917F521}>
DEVICE = NIL
DIRECTORY = (:RELATIVE "foo" "*")
NAME = NIL
TYPE = NIL
VERSION = NIL
; No value
CL-USER> (fad:pathname-as-file **)
#P"foo/*"
CL-USER> (describe *)
#P"foo/*"
[structure-object]
Slots with :INSTANCE allocation:
HOST = #<SB-IMPL::UNIX-HOST {917F521}>
DEVICE = NIL
DIRECTORY = (:RELATIVE "foo")
NAME = :WILD
TYPE = NIL
VERSION = NIL
; No value
I don't think anyone would expect that. But it's not completely trivial
to solve. I think the ultimate conclusion is that CL pathname system is
broken. Fortunately it can be replaced. At least for POSIX programming
IOLIB packages are quite nice. Sometimes such external pathnames need to
be converted to CL pathnames and there are implementation-specific
areas:
In SBCL, "*" as a directory component is literal:
CL-USER> (describe (make-pathname :directory '(:absolute "*")))
#P"/\\*/"
[structure-object]
Slots with :INSTANCE allocation:
HOST = #<SB-IMPL::UNIX-HOST {917F521}>
DEVICE = NIL
DIRECTORY = (:ABSOLUTE "*")
NAME = NIL
TYPE = NIL
VERSION = NIL
; No value
In CLISP it turns to a :wild component:
[33]> (describe (make-pathname :directory '(:absolute "*")))
#P"/*/" is a pathname, with the following components:
DIRECTORY = (:ABSOLUTE :WILD)
I think CLISP shouldn't convert "*" to the :wild component. In any case
it's very difficult to write really portable and reliable code with
pathnames and file processing.
This is exactly the same reason why regular Lisp-style macros are
rejected in other languages.
See for example: http://www.artima.com/forums/flat.jsp?forum=106&thread=5246
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
A comparison along the lines of
http://groups.google.com/group/comp.lang.scheme/msg/b505263f820dba29 by
somebody who knows Scheme, Common Lisp and Clojure well would be
interesting.
Erm, "other Lisps provide that as well"?
What are the other factors?
That is a very good summing up of the pathname problems. That is why
we (as in the CL mammouths [*]) need to get our act together and fix
the issues portably.
The bottom line is that you need to specify what PARSE-NAMESTRING does
for each file system. Then you need to specify the restrictions on
these operations. This is not a simple task, but it is doable, as
long as you try to specify what the results should be across
implementations. Otherwise you end up not knowing what
(parse-namestring ".lisp")
should do.
I insist. NAMES-AND-PATHS is the right start.
Cheers
--
Marco
Last time I checked, Clojure most definitely didn't have hygienic
macros. Unless there has been a major change in the macro system (and
all code that uses it) recently, I'm pretty sure that its macro system
is still not hygienic. You probably mean something else (and yes, Scheme
provides escape hatches by now - not that I particularly like Scheme's
design in that regard).
STM is the wrong solution for handling shared mutable state. See for
example
http://www.bluebytesoftware.com/blog/2010/01/0/ABriefRetrospectiveOnTransactionalMemory.aspx
and
http://www.azulsystems.com/blog/cliff-click/2008-05-27-clojure-stms-vs-locks
Having 'raw' access to assignments can be very critical in certain kinds
of parallel programming settings. I prefer to use a language that
doesn't try to behave as a babysitter in that regard, but just let's me
get my job done, because I know what I'm doing.
The concurrency features you mention can be easily implemented in
LispWorks with its excellent support for SMP (I have already implemented
several variations of the things you mention myself). In Clojure, I'm
locked into the abstractions Clojure happens to provide, in LispWorks I
can implement my own. I prefer the latter approach because it more
easily allows me to deal with situations that Clojure didn't anticipate
(and that is critical for me).
The syntactic differences don't seem substantial enough to me to worry
about. (They may be better or worse, I don't know, and I don't care.)
> There is a difference, by the way, between something being a standard
> part of the language and being not, but readily available in third-party
> libraries. And that is that in the latter case it is likely to be readily
> available in *more than one* third-party library, and these are likely to
> do things somewhat *differently*, and a user of the language won't be
> able to understand all the code using such a feature unless they know
> *all* of those libraries, and there will likely be compatibility problems
> reusing code that uses one with code that uses another.
I'm pretty sure that no matter how many default libraries you have, you
will still need more, and then you theoretically run into the same
problems that you are making up here. Only that in practice you will
probably not face them in Clojure, as little as you face them in Common
Lisp.
Of course. And INTERCAL code is as readable as Perl which is as
readable as Ada ... as Common Lisp ... as clojure :)
Whatever.
Cheers
--
Marco
On 30 Gen, 04:35, Deeyana <d.awlb...@hotmail.invalid> wrote:
> > If that's important, I can use ABCL. With the benefit of a standard and
> > a portable language.
>
> How does that benefit you?
>
> If you intend to port your code to other Common Lisps, that will not be
> easy unless you avoid using any JVM interop features of ABCL to call Java
> libraries, and avoid using any ABCL-specific features, and then you lose
> the benefit of Java's huge standard library and a lot of the benefit of
> the JVM. It becomes just another VM-hosted Common Lisp, albeit one whose
> VM is better tested, better optimized, and more widely ported than most.
Porting might not be easy but at least it's doable; see below. I agree
that using ABCL if you don't need any JVM library or infrastructure
(e.g. servlet containers, or Java WebStart, etc.) probably makes
little sense.
> You lose the ability to have better-than-C-level portability of
> functionality like graphics and sound and threading. And you won't have
> good C FFI unlike with other Common Lisps, either, nor will you be able
> to use any CL libraries that depend on C FFI.
Not true. There are patches to CFFI to make it work with JNA. I don't
know how complete the support is, and performance will be worse than
native FFIs, but still you have the option.
> On the other hand, if you embrace ABCL-specific features and/or Java
> library FFI, you gain a lot of the things that you'd gain by using
> Clojure and lose almost *everything* you'd lose by using Clojure,
> including easy portability to other CL implementations.
With ABCL you may lose *easy* portability to other CLs, but with
Clojure you lose portability altogether, since there are no conformant
implementations to port to. Programs written for Clojure version X
depend on Clojure version X + JVM; programs written for ABCL (using
Java FFI) depend on ABCL + JVM. However, with ABCL you have the
possibility to isolate those JVM-dependent bits and port the whole
program to another CL by rewriting just those bits. Sometimes it won't
be needed, sometimes it won't be practical (because those "bits" might
use a huge library underneath), but sometimes it will be both needed
and practical and you'll be able to do it. With Clojure you can't,
because it's a single-implementation language.
Note that I'm not criticizing Clojure for that: a language standard is
something which eventually only emerges after a language is stable,
has multiple implementations, and is widely used enough to justify the
effort - and that takes many years. However, you just can't say that
if you use ABCL and its Java FFI, you lose everything the CL standard
provides, because that's simply not true.
> You don't gain *everything* you'd gain by using Clojure, though. You
> trade away Clojure's uniform vector/map syntax,
CL has vector syntax, as someone pointed out upthread. And you can
write a portable reader macro for map syntax if you want to.
> STM, immutability, and
> other benefits (mostly focused around better collection and sequence
> libraries and immutability/concurrency/FP) and gain the ability to use a
> large subset of the CL libraries that don't rely on FFI. And Clojure
> allows superior arithmetic performance in some cases to ABCL.
Correctness has more value than performance. Anyway, let's avoid
language comparisons, please. It's obvious that if you need a language
with precisely the features Clojure has, then you'd better use
Clojure. But not everyone agrees that Clojure offers benefits over CL.
> Maybe that trade-off is worth it to you, but if so I'd be curious which
> CL libraries you think make it worth it.
I can speak for my experience: most of my work with ABCL has been to
use it as a DSL on top of some Java library (most notably the Spring
framework). However, in a library I've used at least CLOS, some of its
MOP, and Cells, which are specific to CL. I suspect many people don't
know it, but ABCL can integrate the Java class hierarchy in CLOS so
that you can specialize CLOS methods on Java classes, so even when
you're using Java interop, you could be using CLOS.
> >> But of course it does. If it does something the language standard
> >> doesn't specify a portable way to do, then it must do so by using FFI
> >> to call into an external module, likely C code. Which then has to be
> >> modified and recompiled for every environment.
>
> > No, I just need the host OS to get information about files.
>
> Which you can't access portably from Common Lisp.
What is Common Lisp? It's a standard. It's text on paper, or in files.
You can't *do* anything from Common Lisp. You can do many things from
an *implementation* of Common Lisp, though - including accessing the
OS. See below.
> >> Every machine
> >> architecture requires the C be recompiled, and every OS likewise, and
> >> in some cases the C may also need to be tweaked. (OK, for something you
> >> can do with C stdio that last is unlikely. If we were talking a
> >> graphics library it would be a whole 'nother ball game -- different
> >> versions having to be maintained for every combination of OS, machine
> >> architecture, and Common Lisp variant!)
>
> > I don't need to write any C to talk to the host OS and other libraries
> > in CL implementations.
>
> You might not have to, but someone had to. It will be some feature of the
> particular implementation you use, or some library you use. But there
> won't be any standard way in Common Lisp's hyperspec to, say, make an MS-
> DOS system call or read a Windows Registry key.
And that's a good thing. You, like many others, tend to ignore that CL
is a standard, but implementations provide more than the standard. If
you focus on a single CL implementation, you'll find a lot more stuff
than what's in the CL standard, such as multithreading and concurrency
facilities, access to the OS, etc. The JVM does provide a common
substrate that is bigger than CL the standard, however it has
limitations, too. How do you make a symbolic link in Java, for
example? I suspect you can easily do it with SBCL, or Clisp, or
others. Access to the Windows registry? I bet Allegro and LispWorks
allow you to do it. It's not portable? 1) do you really care? and 2)
what does portable mean?
1) Portability is generally a good thing, but portability for
portability's sake is not needed in a lot of cases.
2) Portable between OSes, or portable between different language
implementations? It's not the same thing, a single implementation can
run on multiple OSes, and a single feature can be OS-specific even if
it's portable between language implementations.
Regards,
Alessio
...
> > Still I don't need it. I can interface the OS and use a huge amount of
> > libraries without the JVM.
>
> Portable ones that work the same practically everywhere?
I don't that work the same practically everywhere.
I need libraries that work on the platforms I potentially
use and do what I want. I don't see Java stack traces
and java infrastructure as a feature.
>
> >> Of course not. But absence of a fairly basic feature from the standard
> >> language implementation
> >
> > 'standard language implementation'? What is that? There is no one. The
> > implementation I currently use has this functionality. Portably.
>
> How portably? Will your code work for someone using a different
> implementation? What if they're on a different OS?
I works fine enough for me.
> >> means the proliferation of multiple different and somewhat incompatible
> >> third-party libraries to add the functionality, which can then clash,
> >> for instance when they turn up as second-order dependencies (I want to
> >> use xLib and yLib in my project, and xLib uses zLib 1.4, and yLib uses
> >> qLib 2.7, and zLib and qLib don't get along. OK, namespaces/packages
> >> makes this not as likely now as in bygone days. But what if xLib uses
> >> zLib 1.4 and yLib uses zLib 1.6 and xLib won't work with any newer zLib
> >> than 1.4, nor yLib with any older than 1.6? Needless to say both zLib
> >> versions use the same namespace. Uh-oh...)
> >
> > What are you talking about? You were claiming that Common Lisp has no
> > file I/O.
>
> No, I wasn't. I claimed that its standard fails to specify portable ways
> to do specific, common file I/O tasks; not quite the same thing
Let me quote what you wrote:
'Common Lisp (other than the variant that runs on the JVM!) provides no
easy, portable facilities for presenting a user interface, networking,
threading, or even (last I checked) simply working with files. (Even C
has a standard facility for file I/O!)'
...
> > Now you make up hypothetical problems. Why?
>
> No, I describe genuine problems that developers genuinely have to contend
> with when the dependency trees on their projects get big and convoluted
> enough, and especially when two libraries they use directly depend on
> different versions of the same third library.
Well, and what has this to do with our discussion?
Last I looked almost every language ecosystem has libraries
which depend on other libraries.
...
> > Right, I can get rid of the JVM and use the OS directly.
>
> Getting rid of the JVM reduces portability. The JVM isn't a library; it's
> an emulated platform and one with ports to nearly every substrate.
I don't want to use the 'emulated platform'. It does things
in ways I don't need and want.
> Going from JVM to non-JVM is like (though sometimes not as bad as) going
> from Windows-only to Mac-only in terms of a drop in the number of
> machines you can run on.
I have seen a lot of cross platform applications that
run on many machines. GCC for example runs on a wide
variety of machines and does not run on top of Java.
...
> > If that's important, I can use ABCL. With the benefit of a standard and
> > a portable language.
>
> How does that benefit you?
Simply I can move code away and to a JVM based Lisp.
When I want better Lisps, faster execution, etc,
I can get rid of the JVM for example.
> If you intend to port your code to other Common Lisps, that will not be
> easy unless you avoid using any JVM interop features of ABCL to call Java
> libraries, and avoid using any ABCL-specific features, and then you lose
> the benefit of Java's huge standard library and a lot of the benefit of
> the JVM. It becomes just another VM-hosted Common Lisp, albeit one whose
> VM is better tested, better optimized, and more widely ported than most.
I have already many of the functionalities that the JVM
provides. I have no problem moving away from the JVM
unless I commit to something like SWT or other Java-specific
libraries - which I don't want anyway.
...
> You don't gain *everything* you'd gain by using Clojure, though. You
> trade away Clojure's uniform vector/map syntax, STM, immutability, and
> other benefits (mostly focused around better collection and sequence
> libraries and immutability/concurrency/FP) and gain the ability to use a
> large subset of the CL libraries that don't rely on FFI. And Clojure
> allows superior arithmetic performance in some cases to ABCL.
None of what you mention interest me much.
> Maybe that trade-off is worth it to you, but if so I'd be curious which
> CL libraries you think make it worth it.
Libraries for which Lisp has been developed. I'm not interested
in scripting Java applications, embedding Lisp in Java
or interfacing to any Java libraries. If I were, I'd use
ABCL.
> >> But of course it does. If it does something the language standard
> >> doesn't specify a portable way to do, then it must do so by using FFI
> >> to call into an external module, likely C code. Which then has to be
> >> modified and recompiled for every environment.
> >
> > No, I just need the host OS to get information about files.
>
> Which you can't access portably from Common Lisp.
Sure I can, I just need to use or provide a portability
layer. Which I do.
> >> Every machine
> >> architecture requires the C be recompiled, and every OS likewise, and
> >> in some cases the C may also need to be tweaked. (OK, for something you
> >> can do with C stdio that last is unlikely. If we were talking a
> >> graphics library it would be a whole 'nother ball game -- different
> >> versions having to be maintained for every combination of OS, machine
> >> architecture, and Common Lisp variant!)
> >
> > I don't need to write any C to talk to the host OS and other libraries
> > in CL implementations.
>
> You might not have to, but someone had to.
Not 'might', I don't have to.
When I try and run this with:
D:\code\Clojure>java -jar c:\lisp\clojure-1.2.0\clojure.jar
SwingHelloWorld.clj
I get:
Exception in thread "main" java.lang.Exception: No such namespace:
SwingUtilities (SwingHelloWorld.clj:9)
I don't know how to make that work externally, so I changed
(SwingUtilities/invokeLater
to
(javax.swing.SwingUtilities/invokeLater
The error goes away, but I'm not getting any window. The code does
exit after a several second delay.
My libraries run everywhere.
Cheers
--
Marco
I would have done it as (print stream "string") and (System.nanotime)
(Collections.sort foo)
One thing I was surprised to see was defn/def instead of defun/
defvar?
> However, in a library I've used at least CLOS, some of its
> MOP, and Cells, which are specific to CL.
Cells specific to CL? I don't think so:
http://clojure.org/libraries#Clojure%20Libraries-3rd-party%20Clojure%20L
ibraries-neman.cells
> > What does the language offer?
>
> Is this a trick question? The Lisp core is, after all, pretty
> minimalist.
Wait a minute. Not the "Lisp core". The CL core. Lisp is not
CL, despite what its hierophants would have us believe.
In CL, you can do none of the following without third-party
libraries.
user=> (flatten '(a (b (c))))
(a b c)
user=> (range 3 30 4)
(3 7 11 15 19 23 27)
user=> (.replace "fools foobarred Lisp" "oo" "u")
"fuls fubarred Lisp"
user=> (re-seq #"\d+" "1st, 2nd, or 99th")
("1" "2" "99")
user=> (use '[clojure.string
:rename {reverse str-reverse replace re-replace}])
nil
user=> (re-replace "foools foobarred Lisp" #"o+" "u")
"fuls fubarred Lisp"
user=> (split "foo,bar baz" #"[ ,]")
["foo" "bar" "baz"]
user=> (join "-" '(thrice damned CommodeLang))
"thrice-damned-CommodeLang"
And yet the CL standard is huge.
Guy L. Steele, Jr., July 1989:
I think we may usefully compare the approximate number of pages
in the defining standard or draft standard for several
programming languages:
Common Lisp 1000 or more
COBOL 810
ATLAS 790
Fortran 77 430
PL/I 420
BASIC 360
ADA 340
Fortran 8x 300
C 220
Pascal 120
DIBOL 90
Scheme 50