I've lately been programming a lot in Java, as Java makes provisions for many of the development needs I'm encountering, such as internet friendlyness, distributed computing, and object serialization. I want to ask questions about CL, just to see if there are people out there that can verify if CL is really antiquated or not.
1. Java has object serialization; Lisp doesn't (always)
Lisp has the ability to "serialize" certain types of objects for which it has a print method that works well enough so that (read) will read the object back. This applies, of course, to strings, lists, integers, but not to hash-tables, CLOS objects, etc.
Now, for what it's worth, there is a package out there (`save-object') which provides methods for writing all sorts of objects to a file so that they can be read again, using the standard Lisp `read' function. This is cool, but it's a very heinus piece of code, and it doesn't do what you want it to efficiently for many types, such as hash-table.
Another thing that's wierd about Lisp is that it's so big. Would it have been so bad if they had something like an `import' keyword, and somehow used the package system to simplify code, and to make adding functionality to CL simpler? In other words, you don't usually see platform-independent libraries to Lisp, that are part of the Lisp specification.
What I'm trying to say is that if the Lisp community wanted to make simple sockets part of the standard, then it might be nice to make a lisp.net package for that stuff to go into.
2. multi-threading
The way Lisp is now, there's no platform-independent way to do threads. I feel that this should be standardized, and in a way that is analogous to Java.
Instead of naming off more and more, I wish that Lisp were redesigned so that it kept all the nice things it has, like first-class functions, but also incorporated some of the Java paradigms, and maybe even compiled down to Java VM bytecode. It is still a better language syntactically than any other one I've ever used, but that's just my opinion.
Instead of starting a huge Lisp vs. Java thread here, I would much rather that someone simply answer my questions about feasibility, if CL can really grow to meet these needs, and what it will take.
David Bakhash <ca...@bu.edu> writes: > 1. Java has object serialization; Lisp doesn't (always)
This leads me to ask a question about Java, and I suspect I might get a better answer here than in a Java newsgroup (this is perhaps the best property of comp.lang.lisp!)
Say, in Java, you hace two objects whose slots point into a large set of structures which share some parts. If you serialise those objects & then unserialise them in another implementation, is that sharing preserved?
I guess this really means `is object identity preserved by serialising'? If it is, can anyone tell me *how* it is? It seems to me that the only general way to do this is to keep a permanent unique-ID for every object, although perhaps I'm being naive.
In article <nkjvhfw8qwv....@tfeb.org>, Tim Bradshaw <t...@tfeb.org> wrote:
>I guess this really means `is object identity preserved by >serialising'? If it is, can anyone tell me *how* it is? It seems to >me that the only general way to do this is to keep a permanent >unique-ID for every object, although perhaps I'm being naive.
If your objects contain open files or network sockets even that's not sufficient. Suddenly you're into hairy issues of "what does object identity actually _mean_?"
> I've lately been programming a lot in Java, as Java makes provisions > for many of the development needs I'm encountering, such as internet > friendlyness, distributed computing, and object serialization. I want > to ask questions about CL, just to see if there are people out there > that can verify if CL is really antiquated or not.
I believe the problem is different. Java developers had the luxury of including in the language standard, things that had been floating around CL for a long time.
> 1. Java has object serialization; Lisp doesn't (always)
> Lisp has the ability to "serialize" certain types of objects > for which it has a print method that works well enough so that > (read) will read the object back. This applies, of course, to > strings, lists, integers, but not to hash-tables, CLOS > objects, etc.
> Now, for what it's worth, there is a package out there > (`save-object') which provides methods for writing all sorts > of objects to a file so that they can be read again, using the > standard Lisp `read' function. This is cool, but it's a very > heinus piece of code, and it doesn't do what you want it to > efficiently for many types, such as hash-table.
So the problem is not that CL does not have "serialization". It is that there is no "standard" and "fully specified way" to do it.
> Another thing that's wierd about Lisp is that it's so big. > Would it have been so bad if they had something like an > `import' keyword, and somehow used the package system to > simplify code, and to make adding functionality to CL simpler? > In other words, you don't usually see platform-independent > libraries to Lisp, that are part of the Lisp specification.
> What I'm trying to say is that if the Lisp community wanted to > make simple sockets part of the standard, then it might be > nice to make a lisp.net package for that stuff to go into.
Fine. Let's define the "CL.NET" package (I am serious about the name). I.e. let's define what goes in there and what should not. First let's write a proposal, and then let's have a "reference" implementation. (BTW. when I write "let's" I mean: "go ahead and write it - I have not that much time" :) )
...other stuff skipped,
Cheers
-- Marco Antoniotti =========================================== PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26 http://www.parades.rm.cnr.it/~marcoxa
Marco Antoniotti <marc...@copernico.parades.rm.cnr.it> writes: > > Now, for what it's worth, there is a package out there > > (`save-object') which provides methods for writing all sorts > > of objects to a file so that they can be read again, using the > > standard Lisp `read' function. This is cool, but it's a very > > heinus piece of code, and it doesn't do what you want it to > > efficiently for many types, such as hash-table.
> So the problem is not that CL does not have "serialization". It is > that there is no "standard" and "fully specified way" to do it.
PRINT-OBJECT
MAKE-LOAD-FORM
Or am I misunderstanding?
CL also has readtables and *print-readably* which I bet is a concept foreign to Java.
I think what CL missed and what Java got right was that Java just goes ahead and claims things it doesn't have, while the Lisp community is honest about the complexity of reality. Just look at Java's "security" and ask yourself how they could have taken a very limited reading of a word like that and applied such a unqualified term to it. Now, if they'd said "type security", I might not think so dimly of them. But when they remove any hint of qualifying adjective, I have to ask myself why a "secure" language can have a way to turn itself off in the security tab of a browser.
If Lisp just said it had serialization and didn't fuss over messy little details like object identity or like intentional vs representational types, it would be fine. But because we say we only solve the problems that are easily solvable and that we held back on the harder problems, leaving them for users to solve with the help of domain knowledge that make the problems more tractable, we get in trouble.
> Marco Antoniotti <marc...@copernico.parades.rm.cnr.it> writes:
> > > Now, for what it's worth, there is a package out there > > > (`save-object') which provides methods for writing all sorts > > > of objects to a file so that they can be read again, using the > > > standard Lisp `read' function. This is cool, but it's a very > > > heinus piece of code, and it doesn't do what you want it to > > > efficiently for many types, such as hash-table.
> > So the problem is not that CL does not have "serialization". It is > > that there is no "standard" and "fully specified way" to do it.
> PRINT-OBJECT
> MAKE-LOAD-FORM
> Or am I misunderstanding?
As usual, you are right and that this is all you really need. What happens in Java is that the functionality is *packaged* much better.
> CL also has readtables and *print-readably* which I bet is a concept > foreign to Java.
All right. Java (at least in my little world :) ) now has pretty print streams as well. Guess where I copied the code from :) Write me in private if you want the package.
Cheers
-- Marco Antoniotti =========================================== PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26 http://www.parades.rm.cnr.it/~marcoxa
> I think what CL missed and what Java got right was that Java just goes > ahead and claims things it doesn't have, while the Lisp community is > honest about the complexity of reality. Just look at Java's "security" > and ask yourself how they could have taken a very limited reading of a > word like that and applied such a unqualified term to it. Now, if they'd > said "type security", I might not think so dimly of them. But when they > remove any hint of qualifying adjective, I have to ask myself why a "secure" > language can have a way to turn itself off in the security tab of a browser.
This is what I was trying to get at -- I bet that java does not deal with object identity when serialising, so serialising is really useful only for rather simple data structures. This is rather similar to the `copy constructor' thing that C++ has. It's fairly obvious that a default copy constructor is really almost never useful, because the notion of `a copy' of an object is very dependent on what the object is, and all interesting cases you need to just write a copy function which depends on intimate details of the object.
So Lisp is honest and says it doesn't have feature x because feature x is either very very hard to do right (serialising), or not actually a useful feature at all. But language comparisons are made on feature count, not on these subtle arguments, and the languages which have lots of features are winning *even though those features are useless*.
What makes it doubly bizarre is that Lisp *does* deal with object identity when serialising in the cases where there is a clear way to do it. Does Java do even that much?
* Tim Bradshaw <t...@tfeb.org> | But language comparisons are made on feature count, not on these subtle | arguments, and the languages which have lots of features are winning | *even though those features are useless*.
so true. this is why I don't want Common Lisp to win those comparisons, and _prefer_ it to be dropped by people who choose the winners in them. these people do, however, need something to "come back to" when they discover that they have been misled, and if Common Lisp caters to the popular vote, the chances are it will no longer have that quality.
it is sufficient that people continue to discover Common Lisp, the same way it is sufficient that people discover classical music and even opera, without adding techno beats and rapping the libretto. so what if young people don't get it? most of us don't die at age 20, Madison Avenue and Hollywood to the contrary notwithstanding.
"tired of useless and buggy features in the latest fad language yet? discover Common Lisp -- it has all you'll ever need, and no more."
(and in the true spirit of marketing, let's make that true before they come running. :)
David> Now, for what it's worth, there is a package out there David> (`save-object') which provides methods for writing all sorts David> of objects to a file so that they can be read again, using the David> standard Lisp `read' function. This is cool, but it's a very David> heinus piece of code, and it doesn't do what you want it to David> efficiently for many types, such as hash-table.
Inefficient or not, I wouldn't mind using it, but it seems broken in CMU CL 18b. Does anyone have a later version of save-object, or a patch? Thanks.
--ap
-- It would be difficult to construe Larry Wall, in article this as a feature. <1995May29.062427.3...@netlabs.com>
Tim Bradshaw <t...@tfeb.org> writes: > This leads me to ask a question about Java, and I suspect I might > get a better answer here than in a Java newsgroup (this is perhaps > the best property of comp.lang.lisp!)
> Say, in Java, you hace two objects whose slots point into a large > set of structures which share some parts. If you serialise those > objects & then unserialise them in another implementation, is that > sharing preserved?
Yes. From the Java serialization specification:
The writeObject method (see Section 2.3, "The writeObject Method") serializes the specified object and traverses its references to other objects in the object graph recursively to create a complete serialized representation of the graph. Within a stream, the first reference to any object results in the object being serialized or externalized and the assignment of a handle for that object. Subsequent references to that object are encoded as the handle. Using object handles preserves sharing and circular references that occur naturally in object graphs. Subsequent references to an object use only the handle allowing a very compact representation.
Reading serialized objects recreates the object graph.
I don't know enough about the subject to know whether Java handles the boundary cases and other hard stuff correctly, but the approach seems generally sound.
> I guess this really means `is object identity preserved by > serialising'? If it is, can anyone tell me *how* it is? It seems > to me that the only general way to do this is to keep a permanent > unique-ID for every object, although perhaps I'm being naive.
I think this is a different question. Java's spec says that if I write out a structure that looks like (and I love that I have a standardized Lisp way of writing this, so just imagine Java analogs):
(1 #1=(2 3 4) #1#)
when I read it in I'll get a structure that looks like
(1 #1=(2 3 4) #1#)
Now you're asking whether if the original structure will be EQ to the structure I serialized in. Or whether, if I call Java's readObject 5 times on the same thing, I'll get 5 things that are all EQ.
No.
Now that would be hard.
[ Just for fun, if Java serialization were supposed to act that way, what would be the result of evaluating (the Java analog) of the following:
> The writeObject method (see Section 2.3, "The writeObject Method") > serializes the specified object and traverses its references to > other objects in the object graph recursively to create a complete > serialized representation of the graph. Within a stream, the first > reference to any object results in the object being serialized or > externalized and the assignment of a handle for that > object. Subsequent references to that object are encoded as the > handle. Using object handles preserves sharing and circular > references that occur naturally in object graphs. Subsequent > references to an object use only the handle allowing a very > compact representation.
Can this be taken to imply that if I serialise 2 objects which share parts then that sharing is preserved? (Assuming I do so in the same stream, I suppose). That's impressive if so.
(sorry, I could read the spec, but my java is poor enough that it wouldn't help me that much!)
Tim Bradshaw <t...@tfeb.org> writes: > Can this be taken to imply that if I serialise 2 objects which share > parts then that sharing is preserved? (Assuming I do so in the same > stream, I suppose). That's impressive if so.
I just realised this morning what this means -- a stream that is used for serialising has to keep track of every non-trivial object it's ever seen (where, I think, `non-trivial' means `EQL is the same as EQ' for it (it's not just non-immediate because bignums need to not be kept track of)), so these streams grow like crazy. And even that's not enough, because there are mutable objects in Java, so it can't actually work right at all. I guess I'm asking too much of serialising (really I'm asking it to be a non-cache-coherent shared memory). I should read the java stuff to see what is actually offered.
Tim Bradshaw <t...@tfeb.org> writes: > > Can this be taken to imply that if I serialise 2 objects which share > > parts then that sharing is preserved? (Assuming I do so in the same > > stream, I suppose). That's impressive if so.
> I just realised this morning what this means -- a stream that is used > for serialising has to keep track of every non-trivial object it's > ever seen (where, I think, `non-trivial' means `EQL is the same as EQ' > for it (it's not just non-immediate because bignums need to not be > kept track of)), so these streams grow like crazy.
Yes, sharing is preserved and this is basically how it works. Once created, an ObjectOutputStream pretty much keeps track of all objects written to it.
It doesn't really have to grow like crazy (and it can certainly end up being more compact when you have lots of shared structure), and it's not a far-out technique. The basic idea seems to be less fancy than Common Lisp's output algorithm when *print-circle* is T. Apple's 3D meta file (3DMF) format can do the same sort of thing.
> And even that's not enough, because there are mutable objects in > Java, so it can't actually work right at all.
This Java doesn't even try to handle. If you call writeObject on an object A, change the object, then call writeObject on the same object with the same stream, You'll get a stream that contains the following:
<object A> <pointer to object A>
where <object A> is a serialized representation of the object before it was modified.
David Bakhash <ca...@bu.edu> writes: >1. Java has object serialization; Lisp doesn't (always)
If I'm not mistaken, what Java has is a *standard* *interface* classes must implement to be serializable. There is no "automatic" serialization of your classes unless you add the support by hand. Of course, it is extremely useful to standardizese the object's interface the serializer will use.
But when it comes to automatically support serialization for your code, Lisp is even ahead, due to Java's primitive lowlevel / user-defineable type seperation.
>2. multi-threading > The way Lisp is now, there's no platform-independent way to do > threads. I feel that this should be standardized, and in a > way that is analogous to Java.
A major part of the differences between the concurrency interfaces in commercial Common Lisp is due to it's quite differnt implementations and given strengths, especially when it comes to synchronization.
If you want to write portable code, you could take one the available implementations of a Common API: - The one from ILU (free) ftp://parcftp.xerox.com/pub/ilu/ - The one from CLIM, which is shipped with CLIM, but wrappers from commercial interfaces to the CLIM subset should come for free.
The free CL's that implement concurrency mostly implement the CLIM interface, like CMUCL and Clisp (but not ECL), so it's not really the fault of the Lisp community but just the companies not getting together, driving people to use the free alternatives.
>Instead of naming off more and more, I wish that Lisp were redesigned >so that it kept all the nice things it has, like first-class >functions, but also incorporated some of the Java paradigms, and maybe >even compiled down to Java VM bytecode.
I'm afraid I'm convinced the whole Bytecode things is complete nonsense except for Web applications.
The problems the bytecode approach of Java tried to solve are really to be attacked by standard APIs and descent crosscompiling support, such as CMUCL has or like gcc works on the free UNIX systems. Ever installed ports/devel/linux_devel on FreeBSD?
Instead, bytecodes bring you either bad performance and/or slow startup due to JIT compilation and serious bugs in compilers due to their pressure to compile fast code fast. Doing both is seriously more complicated than just compiling fact code *or* doing fast compiles. Read the factorization example from Microsoft's compiler? Ever tried to use javac (the one from the JDK) with a JIT? Ever wondered by the free software explosion we see mostly doesn't even mention Java?
Martin -- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Martin Cracauer <craca...@bik-gmbh.de> http://www.bik-gmbh.de/~cracauer/ "Where do you want to do today?" Hard to tell running your calendar program on a semi-reliable operating system, eh?
> >1. Java has object serialization; Lisp doesn't (always)
> If I'm not mistaken, what Java has is a *standard* *interface* classes > must implement to be serializable. There is no "automatic" > serialization of your classes unless you add the support by hand. Of > course, it is extremely useful to standardizese the object's interface > the serializer will use.
Actually, this isn't true. Java supports automatic serialization of your classes, but allows you to override the standard serialization for any class you define.
I once wrote a program that, given a set of Java class files, automatically wrote C++ code to serialize and deserialize Java objects of those classes. The generated code was used for communication between a client-side program written in C++ and an existing Java server that already used Java Object Serialization to communicate with another client, which had been written in Java. The fact that Java classes handled serialization automatically made this all quite easy. (Of course, the code generator was written in Lisp.)
> But when it comes to automatically support serialization for your > code, Lisp is even ahead, due to Java's primitive lowlevel / > user-defineable type seperation.
I agree wholeheartedly. Years ago, we gave MIT Scheme the ability to do FASDUMP to any I/O port. This made communicating via the network quite easy, since any type of object (except a code object, unfortunately) could be sent without any special declarations or other code. Even fixnums could be sent without a problem.
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
Discussion subject changed to "Dynamic compilation, architecture-neutral distribution... (was Re: CL missing some modernisms...)" by Christopher R. Barry
> I'm afraid I'm convinced the whole Bytecode things is complete > nonsense except for Web applications.
While I find the Java bytecode technology far from satisfactory, having an architecture neutral intermediary language between the source and machine code that can be dynamically compiled is very useful.
With the traditional approach of compiling to machine code for each target, which means possibly obtaining at a great expense either an architecture/OS/compiler combo or at the very least a cross-compiler if it exists and functions reliably, you must also perform seperate compiles for that target if you want to use an extension found in some representatives of that architecture like MMX or optimize for a specific processor of that architecture such as the PII.
Dynamic compilation will be vital to decent performance with future generations of future processors such as the Merced which no longer schedule instructions to execute in parallel in hardware but instead have the compiler do it at compile time, hardcoding what previously could be done by the processor transparently at runtime, so that your binaries are tied closer to the specific processor than ever before.
Kind of like how processors like the P6 broke a lot of older Pascal and other similarely compiled programs compiled by not-too-perfect compilers with errors like "runtime error 200", so will these types of problems be extremely difficult to avoid with processors such as the Merced, without causing a negative performance impact by not so aggresively assuming that certain latencies will always be for so many clock-ticks among other issues....
Also, more and more now PC vendors are shipping bandwidth-starved 450-500MHz Pentium II/III processor based computers with the same old crappy IDE disk drives so loading a small applet-like code packet from the disk and then dynamically compiling it to a much larger machine binary-image can even be faster than just loading the binary-image, or at the worst negligibly slower.
The major problem with the Java bytecode is that it hides too much information from the JIT. It and others like it are abstractions of machines. It is better to use abstractions of programs, or of programming languages, so that vital information needed for performing optimizations is maintained.
There are at least two architecture-neutral distribution technologies that already exist and are superior to Java's model. They are TenDRA/ANDF (only implemented for Unixes for now) <http://alph.dra.hmg.gb/TenDRA/>
At the last link you can find Dr. Franz's doctoral dissertation on SDE, the most promising of the current dynamic compilation technologies, though there is no free implementation of it.
At any rate, there's no reason why the JVM can't radically improve in the future. JDK 1.2 bytecode doesn't need to run on 1.0 JVMs, and indeed it doesn't, so in the future the JVM and the bytecode could be far, far superior, since backwards-compatibility isn't an issue.
> The problems the bytecode approach of Java tried to solve are really > to be attacked by standard APIs and descent crosscompiling support, > such as CMUCL has or like gcc works on the free UNIX systems. Ever > installed ports/devel/linux_devel on FreeBSD?
No. And most commercial companies that are supporting Linux versions of their software are not doing BSD versions, such as Allegro, Oracle, SAP, etc....
> Instead, bytecodes bring you either bad performance and/or slow > startup due to JIT compilation and serious bugs in compilers due to > their pressure to compile fast code fast.
It can only get better, and caching a JIT's output for future loads is not an infeasible concept. Some architecture-neutral distribution models do the "caching" only once.
> Ever tried to use javac (the one from the JDK) with a JIT?
Yes, the TYA JIT. I had to hack the TYA source to get rid of those retarded messages it displays though.
> Ever wondered why the free software explosion we see mostly doesn't > even mention Java?
Huh? In a well-publicized move, IBM open sourced their Jikes Java compiler. The real problem is that instead of working together there are 20 different free software Java projects and none of them have produced an implementation of the quality of the blackdown.org port of Sun's JDK (AWT/Swing/GUI stuff was horribly broken for all other implementations last I checked). And Sun's JDK is supposed to be the crappiest Java platform for Windows.
The GCJ front-end to EGCS will be real nice once it's ready for primetime.