I don't know if this question is appropriate, so if not, please ignore
it and accept my apologies for being off-topic.
I am setting out to add scriptability to a largish and relatively
mature, though still evolving, Java application. The application is a
theorem prover and it operates on formulas expressed in the CLIF
notation, about which it's enough to know that it's syntactically a
Lisp-like language.
Because of this I'd like to use a Lisp dialect to add scripting. Right
now, I'm looking mostly at SISC and Kawa.
So my question is this: What sort of analysis should I be making to
select between these two?
One thing I'll point out is that there will be quite a lot of
interaction across the boundary between the scripting language and the
existing Java application. I.e., there will be a lot of functions or
methods that can be invoked on the scripting side to gather information
about and manipulate the content being operated on and to initiate
problem execution on the Java side.
I mention this because if it's tedious to make any given bit of
Java-side functionality accessible to the scripting side, that will be
a negative.
Lastly, if there are other Lisp-like scripting languages that integrate
well with Java, I'd like to hear about them, too. My research suggests
that while many such projects have been created, not many are actively
developed or are very complete implementations of Lisp (or Scheme).
Thanks.
Randall Schulz
Lisp-like language in the sense of having lots of ( and ), or do you
also have macros?
> So my question is this: What sort of analysis should I be making to
> select between these two?
>
> One thing I'll point out is that there will be quite a lot of
> interaction across the boundary between the scripting language and the
> existing Java application. I.e., there will be a lot of functions or
> methods that can be invoked on the scripting side to gather information
> about and manipulate the content being operated on and to initiate
> problem execution on the Java side.
>
> I mention this because if it's tedious to make any given bit of
> Java-side functionality accessible to the scripting side, that will be
> a negative.
maybe you should simply give both a try and take what felt to be the
best. Maybe asking for help on the mailing list of these languages would
help too, especially if you describe your language and what you need. I
am sure they can tell you where a possible problem hides.
> Lastly, if there are other Lisp-like scripting languages that integrate
> well with Java, I'd like to hear about them, too. My research suggests
> that while many such projects have been created, not many are actively
> developed or are very complete implementations of Lisp (or Scheme).
how complete does it have to be?
bye blackdrag
--
Jochen "blackdrag" Theodorou
The Groovy Project Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/
CLIF is to Lisp as Java is to C++. That is, if you blur your eyes, you
can't tell them apart. Otherwise they have nothing in common.
(Actually, Java has a lot more in common with C++ than CLIF does with
Lisp.)
One reason I'm looking to Lisp or Scheme as the scripting language is
that I don't want a lot of disparate syntaxes in my system. The other
is that I'm fond of Lisp as a language.
[ As an aside, my application supports user-definable search heuristics.
They are specified in a Lisp-y manner, too, even though that's done
with a separate Lisp reader and data structure library and a
purpose-built compiler and evaluator. Unfortunately, the Lisp reader
library has no evaluator, it just reads and write (Common) Lisp lists
and atoms, so it's not an option as far as my scripting needs go. But
the nice part is that users don't know that. They just see lots of
S-Expressions. ]
> > So my question is this: What sort of analysis should I be making to
> > select between these two?
> >
> > ...
>
> maybe you should simply give both a try and take what felt to be the
> best. Maybe asking for help on the mailing list of these languages
> would help too, especially if you describe your language and what you
> need. I am sure they can tell you where a possible problem hides.
Well, we're a very small operation with more to do than we can really
accomplish, so I don't have the luxury of running competitive
implementations. I have to do my best to choose correctly up front.
> > Lastly, if there are other Lisp-like scripting languages that
> > integrate well with Java, I'd like to hear about them, too. My
> > research suggests that while many such projects have been created,
> > not many are actively developed or are very complete
> > implementations of Lisp (or Scheme).
>
> how complete does it have to be?
I'm inclined to say not very, but I have a niggling feeling that it
would be a mistake to choose something that is only a toy fragment of a
real language. SISC and Kawa both purport to be complete or
near-complete R5RS implementations, and while that's not a first-order
requirement, it is nice and I think it could turn out to be
serendipitous to have a full implementation. (Is it contradictory or
oxymoronic to antipicate serendipity?)
> bye blackdrag
Randall Schulz
Be sure to consider issues of deployment -- will you need to load
source files out of jars or as classloader resources? Does the
application use classloaders in interesting ways that might trip up
the language implementation? Do you need to create multiple
independent language runtimes, and if so, does the language
implementation support that? Some of these features, if missing,
might be easy for you to add -- ask a developer. And (of course) ask
programmers on the language's user mailing list to share their
experiences.
-David
Thanks for the feedback. Though I know you don't need or want to know
these things, I'll outline the answers in case it leads to any
secondary concerns:
> Be sure to consider issues of deployment -- will you need to load
> source files out of jars or as classloader resources?
I will probably want to bundle some scripts (in the JAR file or files)
and certainly will need to allow others to be supplied from outside the
the application proper. (More or less—in many cases scripts would come
from the content repository which in one of the two key deployment
modes is a Grails application and they whole business is bundled
together and deployed into a servlet container.)
> Does the application use classloaders in interesting ways that might
> trip up the language implementation?
My application does not, but the fact that its deployed in a servlet
container might make the answer a de facto "yes." I'm not sure.
> Do you need to create multiple independent language runtimes, and if
> so, does the language implementation support that?
I believe the answer is yes, since the Web app deployment mode is
multi-threaded with multiple concurrent users, in general.
> Some of these features, if missing, might be easy for you to add --
> ask a developer. And (of course) ask programmers on the language's
> user mailing list to share their experiences.
> -David
Thanks again.
Randall Schulz
Kawa provides very easy access to almost all of Java, and because Kawa
is compiler-based, there is little or no impedance mismatch between
your code and Kawa: You can easily call a Java method, access a Java
array, set a Java field, invoke a synchronized section, catch or throw
an exception, etc, etc. And doing so compiles into the similar bytecode
that javac generates, so there is no need to use reflection or
emulation. There is never (well, hardly ever) a need to "escape into
Java" for performance reasons or because you can't access a feature
from Kawa. (An example of one of the rare exception is annotations -
Kawa doesn't yet provide a mechanism to annotation a declaration.
It's on my to-do list ...)
Kawa also provides deployment flexibility: You can use eval, a repl,
compile your "script" into class files, compile a file on-the-fly,
create a servlet, etc. And Kawa takes care with line numbers and
other debug information, so you get useful exception stack traces.
--
--Per Bothner
p...@bothner.com http://per.bothner.com/
Thanks, Per. That's all very useful information.
I've done a little experimentation with SISC (mostly on a tangential
aspect), but I'll look into Kawa.
By the way, does Kawa rhyme with Java??
Randall Schulz
Most of the time I pronounce it that way ... But "Kawa" is based on
the Polish word for coffee, and IIRC the "w" is closer to the English
"w" than the English "v". The original Kawa 0.1 was an interpreter
started by Alex Milowski, who is of Polish heritage. I took over Kawa
early on (with Alex's blessing), implemented a compiler, and over the
years have essentially re-written it a couple of times over ...
Oh, great. Another system I have to look at...
Seriously, thanks for the information. I've heard of Clojure, but know
nothing about it (beyond what you've written). I'll definitely check it
out. At least I know how to pronounce it (I think).
> ...
>
> Rich
Randall Schulz
You might want to get Clojure listed here:
<http://www.robert-tolksdorf.de/vmlanguages.html>
RRS
[Hope you'll forgive me making this an excuse for a competitive
comparison ...]
> [Clojure] shares the Java type system. For instance Clojure strings are Java
> strings (that can't be true of any standard Lisp where strings are
> mutable).
Kawa has both constant strings (java.lang.String) and
mutable strings (gnu.lists.FString). Both implement
java.lang.CharSequence. If you specify that a variable
is a <string> (Kawa has optional type declarations),
it uses the type java.lang.CharSequence.
This gives us the best of both worlds: Java *and* Scheme
interoperability.
> Clojure collections implement java.util.Collection.
Kawa lists, vectors, mutable strings, etc all implement java.util.List.
> Clojure uses Java's calling conventions and call stack.
Kawa by default does the same. Kawa has an option to use a calling
convention that supports full tailcalls (and has some other advantages).
Of course a procedure compiled with one calling convention can
automatically an procedure compiled with the other calling convention,
or an unknown procedure compiled with an unknown calling convention.
> Clojure compiles to JVM bytecode and has excellent performance. It
> supports optional type hints and simple inference that allow it to
> avoid reflection. Clojure supports standard Java debug information.
Kawa has done all of this for a decade ...
> Clojure's math library works directly with Java's boxed Number types,
> including BigInteger and BigDecimal, adding only a Ratio type of its
> own.
Kawa does use its own bignum implementation gnu.math.IntNum - partly
because it precedes java.lang.BigInteger! I continue using IntNum
partly because it is more efficient that BigInteger - it especially
wins when most integers are "small" as is almost always the case.
Another reason for gnu.math.* is that actually implements the
Scheme numeric tower - but extended to support quantities.
For example, Kawa has length (3cm) and time (2.5s) literals,
which are useful for GUIs etc.
Of course Kawa can also convert to and from the standard
subclasses of java.lang.Number and (mostly) supports "mixed-mode"
arithmetic between the standard number and java.math classes
and the gnu.math.* classes (which extend java.lang.Number).
> Clojure has a clean and intuitive Java call interface:
>
> user=> (def s "foobar")
> #'user/s
>
> user=> (s.replace "o" "e")
> "feebar"
$ kawa
#|kawa:1|# (define s "foobar")
#|kawa:2|# (s:replace "o" "e")
feebar
> The net result is much more of an integrated feel than one language
> bridging to another.
>
> You can find out more at:
>
> http://clojure.org
http://www.gnu.org/software/kawa/
D'Oh! I recently installed the regular-expression search extension
(called /Find Bar/) to Firefox, and had the case-sensitive option on.
Sorry...
> Rich
RRS
I'm very supportive of this kind of abstraction, and I've been
playing with these issues for more years than I care to admit ...
Kawa has some attempts in this direction, though not as
completely or consistently as I'd like. I.e. the 'map'
function implements the Scheme map function over Scheme-type lists,
rather than a general map over java.util.List.
I actually don't think this enhancement would be difficult to retrofit
to Kawa. I've already "planned" (i.e. it's on my wish-list) making
<pair> an abstract class. (One benefit is it would make it easier
to write hygienic macros.) And as mentioned <pair> already implements
java.util.List.
> Clojure is a functional language. Its data structures are immutable
> and persistent. It extends the core Lisp data types to (immutable,
> persistent) vectors, hashed and sorted maps and sets, all with deep
> code-as-data support. The sequence library, in addition to being
> abstraction based, is lazy and obviates add-on stream libraries.
You might find the gnu/lists package of Kawa interesting.
> It has a software transactional memory and agent system, metadata,
> pervasive destructuring binding, list comprehensions, regexes etc.
These all sound like nice features - the kind I'd like to have
in Kawa.
> I'm happy to let the rest of this 'competition' play out in the
> marketplace of users.
Perhaps a friendly merger might be possible?
I don't know if the author(s) of SISC are following this list--I don't
recall them speaking up or presenting SISC--an invitation to them
might be in order.
Patrick
I haven't programmed servlets in a long time, but I seem to remember
that they use classloaders to isolate different components so that
sharing of class libraries between components is limited to classes
loaded by the framework. Code from one component must be executed
using the appropriate classloader for that component, or you'll get
class incompatibility errors (or more insidiously, class compatibility
errors, where components that are supposed to be isolated interact
through a class library's global state.) A language implementation
that insists on using a single classloader for executing all code
might not work in that environment, or it might force all users of the
language to cooperate and share class libraries.
At first glance, the classloader-level isolation provided by a servlet
container (or other application framework) should enable you to load
two completely independent instances of the same language
implementation, each with its own base classloader, but I don't know
if that holds true in the face of all the techniques used by JVM
language implementors. If it doesn't hold true for a given language
implementation, then the implementation violates a widespread
assumption about how software components act on the Java platform, and
it is unlikely to play well with existing Java application frameworks.
-David
Sounds like there's a story there. As I understand it, Scala's .NET
support has been mostly abandoned too. Care to elaborate? Was it just
one too many platforms to support, or were there any technical reasons
you stuck to the Java side?
- Charlie
I did send out an invitation when the group was started, but perhaps
someone closer to the project could give it another go?
- Charlie
Thanks everyone for the feedback, especially for being made aware of
Clojure.
I'll be looking into these three languages (in alphabetic order, of
course):
- Clojure
- Kawa
- SISC
Randall Schulz
Rich Hickey wrote:
> Java has greater platform reach.
Undoubtedly, and I think the work we're all doing will help keep it
strong and extend it further.
> Java is more dynamic. Java's dynamic loading heritage pervades the
> platform in many subtle ways.
Interesting...would you care to elaborate? I agree, but for mostly
intangible reasons. I have not worked in an environment that did not
support dynamic loading of code (or not as dynamic as Java) for a long
time. But I remember my C and C++ days, and whenever I look at C/C++
projects now I can't imagine being that statically bound. My impression
is that C#/.NET has similar (if perhaps slightly lessened) restrictions.
> Java has much more open source activity, many more libraries to
> leverage. Java itself becoming open source clinched the deal of it
> becoming the open-source target platform of choice.
I was also very excited about the open-sourcing. I think as a result
we'll see JDKs on a lot more systems, more pervasively distributed, and
the platform will grow tremendously. And I think this will be a big year
for OpenJDK in general, what with DVM and the OpenJDK Challenge.
> Java's core data structure library and concurrency stuff is much
> better, and its memory model better defined (a big issue once I got
> into STM).
>
> Java has a simpler VM architecture, greatly easing interop. Things
> like CLR value types and the way they do generics might provide a 10%
> perf advantage (or might not), but definitely double the complexity.
> Java's generics via erasure are a blessing for dynamic languages.
AMEN. From Java, I sometimes lament erasure because it limits how
intelligently the language can work with generic types. But as a dynlang
implementer...I see the contortions IronRuby and IronPython need to do
because they're *forced* to support full generic type instantiation, and
it makes me weep. Whatever happens with "erasing erasure" the
non-parameterized fallback *MUST* remain.
> I eventually decided to generate bytecode on-the-fly and found ASM
> much nicer than anything on the CLR side, and, again, a better dynamic
> loading story. Differences in bytecode between the platforms are much
> bigger than between C#/Java source code, so maintaining a port would
> have been much harder still.
I have not looked at CLR IL generation, but I do like ASM a lot. JRuby
uses ASM extensively for generating method handles and obviously for the
compiler itself.
What bytecode-level differences do you think would have been the largest
issues? I understand that CLR has statically-typed local variables at
the bytecode level too, so that's probably one (JRuby is *very* liberal
about what it stuffs in local variables). And I would imagine IL
reflects the much-more-static nature of CLR. Having investigated it
yourself, I'd be interested in hearing your take.
> Having dropped the CLR, I've never regretted it. Progress on Clojure
> proceeded rapidly. I'm very happy with HotSpot, on-the-fly
> compilation, library availability, community, portability etc.
Well I'm very glad you're on the group. You may want to join the MLVM
list as well, since the Da Vinci Machine patches are starting to fly there.
- Charlie
Assemblies are not subject to garbage collection.
A powerful distinction...classloaders can load arbitrary code and go
away when that code and the classloader itself are dereferenced. If they
couldn't we'd have a *devil* of a time supporting a JIT mode in JRuby.
How does the DLR get around this when generating DynamicSites?
- Charlie
> How does the DLR get around this when generating DynamicSites?
AFAIK, the DLR makes heavy use of DynamicMethod, which are a kind of
methods that are not bound to a particular assembly and can be garbage
collected freely.
ciao,
Anto