New in this Release
-------------------
This release is a maintenance release, fixing a number of bugs since
the previous stable release. The following fixes were made since
the last announced 1.8.5 release:
* Remove accidental dependencies on Java 1.4.
* Fixed bugs in the implementations of SRFIs 13, 18, and 19.
* Fixed problems when calling SISC from Java when SISC is in
strict R5RS compliance mode.
* Fixed a space leak in the value serialization.
* Deserialization now constant rather than linear in memory usage.
* Fixed minor error handling and inexactness contagion bugs in the
numeric library.
* Failure continuations weren't wind safe, fixed.
* Bug fixes in a few primitive functions.
* Fixed a copy-propogation bug in the optimizer.
* Workaround for a bug in the IBM JVM v1.3 in numeric parsing.
About SISC
----------
SISC is an extensible heap-based interpreter of Scheme running on
the Java VM, with an aggressively optimized, lightweight (<200k)
Scheme engine. SISC handily outperforms all existing Java
interpreters (often by more than an order of magnitude).
In addition, SISC is a complete implementation of the language.
The entire R5RS Scheme standard is supported, no exceptions. This
includes a full number tower including complex number support,
arbitrary precision integers and floating point numbers, as well as
hygienic R5RS macros, proper tail recursion, and first-class
continuations (not just the escaping continuations as in many
limited Scheme systems). SISC also attempts to implement the
standard as correctly as possible, while still providing
exceptional performance.
Finally, SISC provides many useful real-world extensions, such as
networking, threading, elegant exception handling, generic
procedures, an object system, SLIB and comprehensive SRFI support, a
scope-friendly module system, a Scheme and Java object system
with a clean foreign-function interface and more.
Downloads and More Information
------------------------------
Source code, binaries, a comparison of Java Scheme systems, and
SISC documentation can be found on the web at:
Licensing
---------
SISC is Free Software. It is released simultaneously under the GNU
General Public License (for free-software projects), and the Mozilla
Public License (for commercial entities). The documentation is
available under the GNU Free Documentation License.
> SISC handily outperforms all existing Java interpreters (often by more
> than an order of magnitude).
It's fast even though all its numbers contain *all* 6 fields?
- int type
- int value
- float/double/BigDecimal
- float/double/BigDecimal for the imaginary part
- BigInteger
- BigInteger for the denominator
I guess wasting memory is cheaper than type casts which most other
implementations use to determine the kind of a number.
Strange. I haven't used a Java implementation of Scheme, but I imagine
that other Java interpreters must be horribly slow.
Would it be better in .NET? It doesn't seem to provide any better way
of representing numbers; structs don't help. While the virtual machine
provides tail calls, I think they can't be used from C#, and of course
they don't provide first-class continuations, so the call stack must be
managed explicitly anyway.
--
__("< Marcin Kowalczyk
\__/ qrc...@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Firstly, we don't claim to be fast in numeric processing, despite still
outerperforming the other interpreters.
> - int type
> - int value
> - float/double/BigDecimal
> - float/double/BigDecimal for the imaginary part
> - BigInteger
> - BigInteger for the denominator
> I guess wasting memory is cheaper than type casts which most other
> implementations use to determine the kind of a number.
>
We've tried three ways of representing numbers:
1) An OO approach, with a Number type and subclasses for
each subtype in the hierarchy. You get killed on the
method dispatch.
2) The current approach, which is basically an impoverished
union with a table dispatch on the type. This wastes memory and
requires slightly uglier code, but avoids allocation, full fledged
type checking, and OO dispatch.
3) A container method where a generic Object field holds
the numeric data. You get killed on the typecasts.
> Strange. I haven't used a Java implementation of Scheme, but I imagine
> that other Java interpreters must be horribly slow.
The competing interpreters loose primarily on their slower overall
performance executing Scheme expressions. If for example an interpreter
was competitive in its main loop, it would probably beat us in numerics
simply because we try to do the entire tower.
> Would it be better in .NET? It doesn't seem to provide any better way
> of representing numbers; structs don't help. While the virtual machine
> provides tail calls, I think they can't be used from C#, and of course
> they don't provide first-class continuations, so the call stack must be
> managed explicitly anyway.
Our biggest limitation in Java is the lack of tail calls and the lack of
a good union type. With the former, we could use CPS instead of a heap
representation of continuations and a faster main loop. With the
latter, we could have support for stack allocated Scheme values. But
the heap representation works well for us in Java. It gives us tail
recursion, and with proper recycling of call frames (see the paper), we
outperform virtually every Scheme system out there on continuations.
Scott
> We've tried three ways of representing numbers:
>
> 1) An OO approach, with a Number type and subclasses for
> each subtype in the hierarchy. You get killed on the
> method dispatch.
> 2) The current approach, which is basically an impoverished
> union with a table dispatch on the type. This wastes memory and
> requires slightly uglier code, but avoids allocation, full fledged
> type checking, and OO dispatch.
> 3) A container method where a generic Object field holds
> the numeric data. You get killed on the typecasts.
Have you considered special cases for fixnums and doubles, and then
promoting to the more general form as necessary? I don't know how
aggresively you try and do any kind of type inference with your compiler.
Or does that simply give you bloated memory AND object dispatch? Worse of
both worlds :-).
Regards,
Will Hartung
(wi...@msoft.com)
I'd love to try that, but its not possible. The call frame cell which
can hold a Scheme value must be a subclass of Value, and thus must be an
object. We could add both a fixnum and double field in the call
frame, but that would waste even more storage, and we'd need an explicit
type field in the callframe, and tests in a lot more places to determine
which field to use. All problems because of a lack of union type in
Java. That said, numeric operations aren't really the bottleneck in the
implementation.
Scott
Kawa included? Or don't you count Kawa as an interpreter?
Lauri Alanko
l...@iki.fi
SISC is never more than twice as slow as Kawa though, and in the current
CVS tree, peforms within 30% of Kawa with primitive inlining enabled.
And again, its no contest if the code uses continuations. Enough
plugging though! :)
Scott
Sorry, but I don't see the point of this distinction. The fact that
Kawa compiles to JVM bytecode internally is an implementation detail
and not visible to the user, when it is used interactively. So you are
essentially saying that "SISC outperforms all JVM-Schemes that don't
use a faster implementation technique than SISC". And sorry, but that
does not sound particularly impressive. :)
The points about R5RS compliance etc. are of course still valid.
Lauri Alanko
l...@iki.fi
Posting to a newsgroup that "SISC handily outperforms all existing
Java interpreters" is not a comparison with Java Scheme compilers
doesn't sound particularly impressive either, but that didn't stop you.
Let others have the same freedom that you give yourself.
But the above points are inseparable. We didn't choose to write an
interpreter because we are too lazy to write a compiler. An interpreter
was chosen in order to fully implement R5RS in the face of the
limitations of the JVM. A fast but 'broken' Scheme is useless to me and
many others. The fact that it does outperform many JVM Schemes with
limited functionality is just a bonus, not the main selling point.
Scott
> An interpreter was chosen in order to fully implement R5RS in the face
> of the limitations of the JVM.
What does the interpreter/compiler distinction have to do with R5RS
compliance?
Oh, come on. That was uncalled for. Firstly, I didn't restrict
anyone's freedoms. And secondly, I don't think my point was as vacuous
as you make it sound.
All right, I'll elaborate. We all know that the distinction between a
compiler and an interpreter is hazy at best. Any sensible
"interpreter" will translate the source program into some internal
representation format before executing it. I can think of only two
meaningful usages of the word "compiler" as opposed to "interpreter",
though I don't think either is, technically, _quite_ appropriate.
The first usage for "compiler" is something that translates into
native code which is executed directly by the hardware, instead of
some intermediate format that still needs to be "interpreted" by
software.
The second usage is that a "compiler" is something that is given
entire source code files, and it produces object code files, which
then need to be linked and run and whatever, whereas an "interpreter"
is something that provides an interactive toplevel that evaluates
expressions immediately.
Now, as it happens, Kawa and SISC are both interpreters by both of
these counts. Both provide an interactive toplevel, and both translate
Scheme internally into another, non-native format, which is then
executed by software. In Kawa, the format is JVM bytecode which is
executed by the JVM, whereas in SISC the format is an internal syntax
tree which is executed by code in SISC itself, which, of course, is
usually executed by the JVM.
So the point is simply that saying "SISC is an interpreter and
Kawa is a compiler" means drawing an entirely arbitrary line which is
more misleading than informative.
And, of course, compiling to bytecode by no means inherently precludes
R5RS compliance. For example, continuations could be handled by
turning everything into CPS. I'm not claiming it would make much
sense, but it's possible.
And as far as efficiency is concerned, to my mind _all_ Scheme-on-JVM
implementations are doomed to be horribly slow, simply because JVM is
such an unsuitable platform for functional languages.
Lauri Alanko
l...@iki.fi
Cheers,
Michael
Of course, but that is a different problem, and one that has to be
handled in any case, CPS or no CPS. And it _can_ be handled.
Trampolines are one way, or one could check the recursion depth at
every application, and jump up with an exception when the stack gets
too deep.
Anyway, these problems are really mostly orthogonal to the issue of
whether Scheme expressions are translated into JVM bytecode or into
something object trees or whatever. The architectural limitations of
the JVM are the same in any case.
Lauri Alanko
l...@iki.fi
> Isn't it that you get problems due to the lack of guaranteed tail call
> optimization, then?
No. Many techniques solve the problem without requiring proper tail-call
treatment from the host language/environment. Trampolining is one such
technique:
* Steven E. Ganz, Daniel P. Friedman and Mitchell Wand. "Trampolined Style".
International Conference on Functional Programming (ICFP 99). September 1999.
Available online
http://www.cs.indiana.edu/hyplan/sganz/publications/icfp99/paper.pdf
Yes, you can compile to bytecode and get continuations using CPS and
trampolining. The problem is that since the JVM provides neither tail
recursion optimization or any sort of stack manipulation features beyond
exceptions, you're limited to either catching StackOverFlowException, or
explicitly checking the recursion depth and either throwing an exception
to the lower level or returning some special value which must be
checked all the way to the root.
All three mechanisms are tremendously slow.
So if you want to compile Scheme to the JVM, you I strongly doubt one
can meet all three of:
- Efficient general, tail recursive performance
- Efficient continuations
- Correct first-class continuations and tail recursion
Once again, though, performance is hardly the main issue when doing
software development, particularly in the areas Java is applied. SISC
is typically used in web applications and systems scripting, where
having first-class, serializable continuations and being able to program
in a natural recursion style are far more valuable than a few extra
percentage points of speed.
Scott
Sure, but so was yours: people seldom post "call for insults".
> And secondly, I don't think my point was as vacuous
> as you make it sound.
Maybe, but I don't think the OP was as silly as you made it sound.
Your compiler/interpreter discrimination seems buggy if you don't
consider Kawa a compiler in any way, especially given the description
by its maintainer. Generally, it doesn't seem like you thought things
through before throwing linguistic fireworks at SISC.
--
MJR/slef
I'm not an expert on this but I believe that the JVM limitations mean
that it is extremely difficult if not impossible to implement
multi-shot continuations just using the JVM. None of the current Java
Scheme compilers feature multi-shot continuations for example, they
only support once off escaping continuations. Bigloo supports full
continuations except when you are using the JVM backend. I believe
Kawa and the other Java-Scheme compilers also suffer from this. This
means that to be fully R5RS compliant on the JVM you need to run your
Scheme on an additional layer (the interpreter) in order to make up
for the JVM limitations. I'm fairly certain that the .Net CLR also
currently suffers from the same problems.
Mark.
The term "compiler" is very well defined. Compilers translate code in a
source language to code in a target language. Hardware or native code has
nothing to do with the actual definition of "compiler", and nor does whether
it produces object code files. These are just different target languages,
and in the case of object code files, something even less relevant, a
persistent output format for the target language. There are contexts in
which the term "compiler" is assumed to imply that the target language is
native code - the first usage quoted above - but that's just a specific
application of the same meaning of the term. For most compilers, both
source and target languages are usually either well-known or explicitly
stated, e.g. we say that a compiler compiles to native code, or that it
compiles to Java bytecode, etc.
As for "interpreter", the technically useful definition is a program which
executes another program. There's a secondary common usage which comes from
the historically typical behavior of interpreters, that of an "interactive
toplevel", as quoted above. But when contrasting compilers with
interpreters, it's the former definition that is used, since that sense of
the term is mutually exclusive with "compiler".
Descriptions of Kawa make it clear that it is a compiler to Java bytecode.
When Scott Miller writes "SISC is an extensible heap-based interpreter of
Scheme running on the Java VM", it's clear that he's describing something
other than a compiler to Java bytecode. Use of the terms "interpreter" and
"compiler" in this context are clearly relative to the Java VM, and the
distinction is as useful here as it is in any context.
As it happens, SISC could be said to contain two distinct compilers: the
syntax-case system, and the translator to SISC's syntax tree representation.
But the end result of these compilation phases is still a format that has to
be executed by an interpreter (provided by SISC), which in turn is executed
by the JVM. Kawa doesn't need an interpreter at that level, which reflects
its status as a compiler, relative to the JVM. The JVM itself contains its
own compilers and/or interpreters, but that's a constant factor when you're
talking about languages which target the JVM.
> So the point is simply that saying "SISC is an interpreter and
> Kawa is a compiler" means drawing an entirely arbitrary line which
> is more misleading than informative.
In light of the above, this is only true if the reader doesn't have
sufficient context to correctly interpret the statements. Perhaps the real
critique here is that more context needs to be provided.
> And as far as efficiency is concerned, to my mind _all_ Scheme-on-JVM
> implementations are doomed to be horribly slow, simply because JVM is
> such an unsuitable platform for functional languages.
That's true, although it doesn't mean that Scheme on JVM isn't useful. In
many applications, things like database performance may be the limiting
factor. That's a big reason why server-side Java was successful in the
first place - it was somewhere where Java's performance wasn't necessarily a
bottleneck. Scheme on Java is quite viable in these server-side scenarios,
both as a scripting language for Java, and for performing primary work.
Anton
Cheers,
Michael
There are some limits to what a pure compile-to-bytecodes scheme
implementation can do
--
Sander
+++ Out of cheese error +++
> > So the point is simply that saying "SISC is an interpreter and
> > Kawa is a compiler" means drawing an entirely arbitrary line which
> > is more misleading than informative.
>
> In light of the above, this is only true if the reader doesn't have
> sufficient context to correctly interpret the statements. Perhaps the real
> critique here is that more context needs to be provided.
The required context is the boundaries of software components. So SISC
is an interpreter because it "itself" executes the code (after some
internal translations), whereas Kawa is a compiler because it defers
the execution to a "separate" component, the JVM?
This position is sensible, but just as well one could say that the JVM
dynamic loader (ClassLoader.defineClass()) is a library that Kawa
uses, and thus part of a single software component. This is what one
would say of any scheme implementation that used a virtual machine
library.
I don't claim that one couldn't find technical justifications for
saying that Kawa is not an interpreter while SISC is. I'm just saying
that it is not a meaningful distinction to the end user, and not
something to advertise.
Suppose I wrote an O'Caml interpreter in O'Caml. A simple, very
straightforward interpreter. Then I would announce it by saying "this
is the fastest O'Caml interpreter available". Once someone says, "what
about the standard O'Caml toplevel?", I'd answer, "A-ha! But it is a
compiler, not an interpreter. It compiles to stack-machine bytecode
and lets the virtual machine execute the code, whereas my interpreter
executes the code _directly_."
Technically justifiable, perhaps, but still pretty pointless.
I don't really understand why this became such a heated topic. I
merely criticized a single phrase in an announcement. I am in no way
insulting anyone, or criticizing SISC. In fact, I'm in no position to
make value judgements about it, since I'm not very familiar with it.
I quite agree that efficiency is not paramount with JVM-Schemes, since
if you wanted efficiency, you wouldn't be using JVM in any case. :)
For what it's worth, I think that the technology inside Kawa is pretty
neat, since I'm fond of run-time code generation. But I don't think of
Kawa as a particularly good Scheme implementation. In fact, I think of
it more as an alternative syntax for Java, than as a "Scheme" per se.
So I have nothing against SISC. I'm sure its merits don't depend on
whether or not it outperforms every other JVM-based Scheme
interpreter.
Lauri Alanko
l...@iki.fi
> All your points are valid. It boils down to this:
>
> > > So the point is simply that saying "SISC is an interpreter and
> > > Kawa is a compiler" means drawing an entirely arbitrary line which
> > > is more misleading than informative.
> >
> > In light of the above, this is only true if the reader doesn't have
> > sufficient context to correctly interpret the statements. Perhaps the
real
> > critique here is that more context needs to be provided.
>
> The required context is the boundaries of software components. So SISC
> is an interpreter because it "itself" executes the code (after some
> internal translations), whereas Kawa is a compiler because it defers
> the execution to a "separate" component, the JVM?
Yes. Keeping in mind that Scott called SISC an "interpreter of Scheme
running on
the Java VM", which gives some indication as to the boundaries being
referred to.
> This position is sensible, but just as well one could say that the JVM
> dynamic loader (ClassLoader.defineClass()) is a library that Kawa
> uses, and thus part of a single software component. This is what one
> would say of any scheme implementation that used a virtual machine
> library.
Right, but the comparison in all cases here is to other Schemes that run on
the JVM, so the JVM is a constant point of reference.
You could just as reasonably say that in the context of languages running on
the JVM, Java bytecode is the equivalent of native code, which would give
the same SISC=interpreter, Kawa=compiler result, by the first definition you
previously gave for "compiler".
> I don't claim that one couldn't find technical justifications for
> saying that Kawa is not an interpreter while SISC is. I'm just saying
> that it is not a meaningful distinction to the end user, and not
> something to advertise.
Languages implemented on the JVM are often being used at least in part
precisely because they run on the JVM, and the details of how that works may
be relevant to the end user.
In the Scheme case, there's the question of how well continuations and tail
recursion work. Kawa's continuations are restricted, whereas SISC has
unrestricted continuations with, according to Scott, very good performance.
That's a direct practical result of the interpreter/compiler distinction
relative to the JVM.
> Suppose I wrote an O'Caml interpreter in O'Caml. A simple, very
> straightforward interpreter. Then I would announce it by saying "this
> is the fastest O'Caml interpreter available". Once someone says, "what
> about the standard O'Caml toplevel?", I'd answer, "A-ha! But it is a
> compiler, not an interpreter. It compiles to stack-machine bytecode
> and lets the virtual machine execute the code, whereas my interpreter
> executes the code _directly_."
>
> Technically justifiable, perhaps, but still pretty pointless.
I agree this can *seem* pointless, without the proper context, and the SISC
blurb takes that context for granted. But in the context of languages
running on the JVM, the above example would be more like writing a Java
interpreter in Java. If you were comparing your interpreted OCaml
implementation of some other language, to another implementation of that
language which is compiled directly to the OCaml bytecode, the same
interpreter/compiler distinction relative to the OCaml VM could be relevant.
> I don't really understand why this became such a heated topic.
> I merely criticized a single phrase in an announcement.
Slow news day, I guess. For my part, I like precise definitions. :)
Anton
The implications of that divide on all present Java Schemes seem pretty
meaningful. In any case, it's called emphasising the positive.
> I don't really understand why this became such a heated topic. I
> merely criticized a single phrase in an announcement.
..with unnecessary linguistic fireworks. All you got from me was a
comment that your post wasn't so great either. The SISC team are doing
good work. Let them bask in whatever glories they can. No need for you to
get the flamethrower out because one is "fastest Java Scheme interpreter".
Now, if that was actually not true, you'd have reason to object.
It's worth reminding the reader (as well as myself) to check the references
cited in papers for prior related work. Trampolining is described thuroughly
in the very readable paper:
David Tarditi , Peter Lee , Anurag Acharya, No assembly required:
compiling standard ML to C, ACM Letters on Programming Languages
and Systems (LOPLAS), v.1 n.2, p.161-177, June 1992
http://citeseer.ist.psu.edu/tarditi90no.html
Althought the paper did not mention the term `Trampoline', it nontheless
described the technique (the same way van Wijngaarden did not use the term
CPS in 1966).
Aziz,,,
PS. Thanks to Shriram for directing me to Tarditi's paper.