;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; LL2 Talk ;; --- Ken Anderson and Tim Hickey ;; Saturday 11/9/2002 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;(define starttime (Date.)) (let ( (ses (.getSession request)) (page (.getParameter request "page")) ) ; (define starttime (Date.)) ; (tryCatch starttime (lambda(e) (Date.)))) (define (trs C rows) (map (lambda (row) {[(tds C row)]}) rows)) (define (tds C row) (map (lambda (col) {[col]}) row)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; first we define some helper procedures, used in making the slides ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (small x) {

[x]

}) (define default-style " ") (define print-style " ") (define the-style (let ((t (.getAttribute ses "the-style"))) (if (equal? t #null) default-style t))) (define (td class) (lambda(x) {[x]})) (define (tr class) (lambda(r) {[(map (td class) r)]})) (define (table class rows) {[(map (tr class) rows)]
}) (define (link page title) { [title] }) (define (linklist L) {}) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Here we begin creating the individual pages of the talk ;; They all have a common start ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (if (equal? page #null) (set! page "title")) { [page] [the-style]
[ ;(- 15 (* 0.01 (Math.round (* 100 (/ (- (.getTime (Date.)) (.getTime starttime)) 60000.0))))) " minutes left " ]
[ (case page ;; here are the individual pages, starting with the title page ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (("title") {
[(link "hypothesis" "continue")]

Leveraging Libraries in Lightweight Languages:
the Jscheme Experience; or,
How Bambi snuggles with Godzilla!


Ken Anderson(BBN)
Tim Hickey (Brandeis University)
Saturday, 11 November 2002
LL2
Goals for talk
}) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (("hypothesis") {
[(link "jscheme" "continue")]

Our Initial Hypothesis

  Small Powerful Lightweight Language (JScheme)
   +
  Huge Industrial-strength Libraries (jdk1.4 libraries)
  =
  The Ultimate Lightweight Scripting Language

[(link "jscheme" "continue")] }) (("jscheme"){
[(link "javadot" "continue")]

JScheme: (http://jscheme.sourceforge.net)

A Scheme-like language implemented in Java
[(link "javadot" "continue")] }) (("javadot") {
[(link "javadot1" "continue")]

JavaDot Notation: calling Java from Scheme using Reflection

symbols containing "." or "$" = Java methods, constructors, or fields


(.println X Y) "." at beginning ==> instance method
(Math.sin 0.0) "." in middle only ==> static method
(JButton. S)"." at end ==> constructor
System.out$ "$" at end ==> static field
(.first$ x 5)initial ".", terminal "$"instance field
// Java
System.out.println(new JButton("Hello").toString());   
;; JScheme
(.println System.out$ (.toString (JButton. "Hello")))    

[(link "javadot1" "continue")] } ) (("javadot1") {
[(link "javadot1a" "continue")]

JScheme can be more concise that Java

  //Java
  public static ResultSet readData (String url) \{
    try \{
      return (ResultSet)(new SaxHandler().read(
         new BufferedReader
           (new InputStreamReader 
              ((new URL(url)).openStream()))));
    \} catch (IOException e2) \{
      e2.printStackTrace();
      return null;    \}  \}

[(link "javadot1a" "continue")] } ) (("javadot1a") {
[(link "javadot1b" "continue")]

JScheme can be more concise that Java

  //Java
  public static ResultSet readData (String url) \{
    try \{
      return (ResultSet)(new SaxHandler().read(
         new BufferedReader
           (new InputStreamReader 
              ((new URL(url)).openStream()))));
    \} catch (IOException e2) \{
      e2.printStackTrace();
      return null;    \}  \}
;; JScheme
(define (readData url)
 (.read (SaxHandler.) 
   (BufferedReader.(InputStreamReader.(.openStream(URL. url))))))

[(link "javadot1b" "continue")] } ) (("javadot1b") {
[(link "javadot2" "continue")]

JScheme can be more concise that Java

  //Java
  public static ResultSet readData (String url) \{
    try \{
      return (ResultSet)(new SaxHandler().read(
         new BufferedReader
           (new InputStreamReader 
              ((new URL(url)).openStream()))));
    \} catch (IOException e2) \{
      e2.printStackTrace();
      return null;    \}  \}
;; JScheme
(define (readData url)
 (.read (SaxHandler.) 
   (BufferedReader.(InputStreamReader.(.openStream(URL. url))))))
no static typing
uniform syntax for methods/constructors/instance fields
optional exception handling

[(link "javadot2" "continue")] } ) (("javadot2") {
[(link "javadot2a" "continue")]

but Javadot often is as obtuse as Java

;; Java
final JFrame w = new JFrame("Test");
JButton eb = new JButton("Exit");
eb.setBackground(Color.red);
eb.addActionListener(new ActionListener()\{
      public void actionPerformed(ActionEvent e) \{
        System.exit(0);\}\});
w.getContentPane().add(eb); 
w.pack(); w.show();
;; JScheme
(import "javax.swing.*")
(define w (JFrame. "Test"))
(define eb (JButton. "Exit"))
(.setBackground eb Color.red$)
(.addActionListener eb 
   (Listener. (lambda(e) (System.exit 0))))
(.add (.getContentPane w) eb) 
(.pack w) (.show w)

[(link "javadot2a" "continue")] }) (("javadot2a") {
[(link "javadot2b" "continue")]

This is not the Ultimate Scripting Language

We had to write libraries to hide the direct Javadot access.
(load "jlib/Swing.scm") ;a little functional language for GUI creation

(define w 
  (window "Test"
    (button "exit" red 
            (action(lambda(e)(exit))))))
(.pack w) 
(.show w)
Resulting code is much simpler than straight JScheme + javadot
(import "javax.swing.*")
(define w (JFrame. "Test"))
(define eb (JButton. "Exit"))
(.setBackground eb Color.red$)
(.addActionListener eb 
   (Listener. (lambda(e) (System.exit 0))))
(.add (.getContentPane w) eb) 
(.pack w) (.show w)

[(link "javadot2b" "continue")] }) (("jlib-b"){
[(link "JLIB" "continue")]

Flexible Calling Patterns in Other Languages

# in Jython
import javax
from javax import swing

def exit(e)
    java.lang.System.exit(0)
w=javax.swing.JFrame(title="Test")
p=top_frame.getContentPane()
eb = swing.JButton(label="Exit", background=Color.red, actionperformed=exit)
p.add(eb)
w.pack()
w.visible=1
#! /usr/bin/perl5 -w
# from http://pmwww.cs.vu.nl/documentation/Tk/UserGuide.html
use strict;
use Tk;

my $main = MainWindow->new;
$main->Button(-text => 'Exit',
              -command => \[$main => 'destroy'\]
              )->pack;
MainLoop;

[(link "JLIB" "continue")] }) (("javadot2b") {
[(link "jlib" "continue")]

Our Hypothesis was wrong....

  Small Powerful Lightweight Language (Scheme)
   +
  Huge Industrial-strength Libraries (javadot+jdk1.4 libraries)
  !==
  the Ultimate Scripting Language

[(link "jlib" "continue")] }) (("jlib") {
[(link "jlib-0" "continue")]

New Hypothesis

  Small Powerful Lightweight Language (Scheme)
   +
  Huge Industrial-strength Libraries (javadot+ jdk1.4 libraries)
  +
  Little Lightweight Languages interfacing to libraries
  =
  The Ultimate Lightweight Scripting Language (???)
Oh no, not another language to learn?! Make the little languages either really powerful or really easy to learn!
[(link "jlib-0" "continue")] }) (("jlib-0"){
[(link "JLIB" "continue")]

Questions

What makes a good lightweight scripting library?
What do various scripting libraries have in common?
Where does lightness come from?

We will start the discussion with three examples from Jscheme:
JLIB for building GUIs
SERVLET for writing simple servlets
RUN for simple shell scripts

[(link "JLIB" "continue")] }) (("jlib-a") {
[(link "JLIB" "continue")]

JLIB windowing library (about 500 lines of JScheme)

Continuing with previous example of Java/JScheme GUIs:
;; JLIB
(define w 
  (window "Test"
     (button "exit" red
             (action(lambda(e)(exit))))))
(.pack w) (.show w)
instead of
;; JScheme
(define w (JFrame. "Test"))
(define eb (JButton. "Exit"))
(.setBackground eb Color.red$)
(.addActionListener eb 
   (Listener. (lambda(e) (System.exit 0))))
(.add (.getContentPane w) eb) 
(.pack w) (.show w)

[(link "JLIB" "continue")] }) (("JLIB"){
[(link "JLIB-1" "continue")]

Case Study 1: GUI building with JLIB
Flexible widget constructors lighten the code

(define b
   (button "abc"                               ;; string is button label
           (color 255 80 10)                   ;; background color
           (action (lambda(e) (.hide w)))      ;; action function
           (HelveticaBold 24)                  ;; font
           (lambda(t) (.setForeground t blue)) ;; general property setting
      )

[(link "jlib-b" "The earlier GUI example in other scripting languages")]
Jython uses variable=value pairs in arg list
Perl/TK uses -property ==> value pairs in arg list
[(link "JLIB-1" "continue")] }) (("JLIB-1"){
[(link "Strings" "continue")]

Using a Functional Language lightens code

component functions: button, label, textfield, textarea, choice, menus, ...
layout functions: border, row, col, grid, table, splitpane, scrollpane
fonts and colors ...
(load "jlib/Swing.scm")

(define w 
 (window "sorry" 
  (menubar 
    (menu "File"
      (menuitem "quit" red 
          (action (lambda(e) (.hide w))))))
  (border 
    (north 
      (label "Join Request Refused" (HelveticaBold 24)))
    (center 
     (scrollpane
      (textarea 5 30 (TimesRoman 18) yellow
        "Your request to join the group\\nhas been denied")))
   (south 
      (button "OK" 
         (action (lambda(e) (.hide w))))))))

(.pack w) (.show w)

[(link "Strings" "continue")] }) (("Strings"){
[(link "Run" "continue")]

Case Study 2: Complex String Handling
Quasi-string/Quasi-list syntax lighten code

Key Idea: Quasi-strings: \{7 * 8 = \[(* 7 8)\]\}
\{\} indicates string, \[\] escapes out to Scheme.
Easy to learn/use, clearly lightens code.
; generate HTML histogram table from results of DB query
(define (histogram field table)
   (define results
      (dbquery
          \{select \[field\],count(*) from \[table\] 
            group by \[field\], order by \[field\] asc\}))

\{<html><body> <h1>Query results</h1> The result of query <pre>\[s\]</pre> is <table> \[(trs results)\]</table> </body></html>\}) (define (trs rows) (map (lambda (row) \{<tr> \[(tds row)\]</tr>\\n\}) rows)) (define (tds row) (map (lambda (col) \{<td> \[ col \]</td>\}) row))
Similar Scheme approaches: SCRIBE (Serrano), BRL (Lewis), ...
[(link "Run" "continue")] }) (("Run"){
[(link "Run2" "continue")]

Case Study 3: Simple Shell Scripting
pattern matching, file handling, system calls

Recompile all C files below "." which have been modified after their corresponding ".o" file.
....Ruby example, from pixel@mandrakesoft.com
Dir\['**/*.c'\].each\{|c|
  o = c.sub('\.c$', '.o')
  if !FileTest.exist?(o) || File.stat(o) <= File.stat(c) then
    puts "compiling #\{c\} to #\{o\}"
    system("gcc", "-c", "-o", o, c)
  end
\}
Ruby provides support for iteration (.each\{|c|...\}), pattern matching/replacement (c.sub(P1,P2)), system calls (system(Command,A1,A2,...)), recursive file filtering (Dir\['**/*.c'\]), file property access (File.stat, FileTest).
[(link "Run2" "continue")] }) (("Run2"){
[(link "Run3" "continue")]

Naming Issues for Libraries: brevity versus clarity

Goal: Implement same procedure in Jscheme with same abstractions by building lightweight libraries on top of three java classes:
[(trs "" '( ("pattern matching/replacing" "java.util.RegEx" "(// PAT) (/// PAT REP)") ("recursive file filtering" "java.io.File" "(file** DIR FILTER)") ("system access" "java.lang.Runtime" "(run CMD . ARGS)") ))]
Library Source Lightweight access

[(link "Run2a" "Reusable version")], give descriptive names to more subexpressions
[(link "develversion" "Developer's brief version")] -- short/symbolic names for oft-used patterns
[(link "brevity" "Perl wanna-be version")] --give procedures and macros 1-character names,

The use of functional iteration (e.g. for-each and map) also lightens the code considerably.
[(link "Run3" "continue")]
}) (("develversion"){
[(link "Run2" "continue")]

Developer's version


(load "ll2.scm")  ;; JScheme version with lightweight library

(for-each 
  (lambda(f)
      (define o ((/// "\\\\.c$" "\\\\.o") f))
      (if (or (not (.exists o)) (<= (.lastModified o) (.lastModified f))))
          (begin  (display \{compiling \[f\] to \[o\]\\n\})
                (run gcc -c -o  ,o ,f)))
  (files** dir (// "\\\\.c$")))

This version uses RegEx pattern matching(//) and replacement(///), recursive file filtering(file**), and System access(run).

[(link "Run2" "back")] }) (("brevity"){
[(link "Run2" "continue")]

Simple Shell Scripting: overly concise JScheme version

Here we replaced almost all symbols with one or two character aliases (which could be defined in the library)
;; Perl wanna-be version
(@ f (**/* Dir(// "\\\\.c$"))
   (<- o((/// "\\\\.c$" "\\\\.o")f))
   (? ((||(!(Fis? o))(<=(Fmod o)(Fmod f)))
        (d \{compiling \[f\] to \[o\]\\n\})
        (run gcc -c -o  ,o ,f))))
Using
(define-macro (@ f fs . body) `(for-each (lambda(,f) ,@body) ,fs))
(define-macro (? . R) `(cond ,@R))
(define-macro (<- . R) `(define ,@R))
(define-macro (|| . R) `(or ,@R))
(define **/* files**)
(define d display)
(define ! not)
(define Fmod .lastModified)
(define Fis? .exists)
[(link "Run2" "back")] }) (("Run2a") {
[(link "Run2" "continue")]

Reusable Version of Jscheme Shell Script

;; JScheme version
(load "ll2.scm") ;; provide same support as Ruby example in 70 lines
(define (compile dir)
   (for-each  (lambda(c) 
                   (display \{compiling \[c\] to \[(c->o c)\].\\n\})
                   (run gcc -c -o  ,(c->o c) ,c))
               (files** dir needsUpdate?)))


(define isCFile? (// "\\\\.c$"))   
(define c->o (/// "\\\\.c$" "\\\\.o")) 
(define (needsUpdate? f) (and (isCFile? f) (needsRecompile f (c->o f))))
(define (needsRecompile f o)
  (or (not (.exists o)) (<= (.lastModified o) (.lastModified f))))

[(link "Run2" "back")] }) (("Run3"){
[(link "tradeoffs" "continue")]

Implementation

JLIB library = 600 lines of Jscheme code
Database library = 30 lines (to implement (dbquery STRING))
Shell Scripting lib = 70 lines

Jscheme + javadot + jdk1.4... makes it very easy to write such libraries.
e.g., Pattern matching is implemented in 4 lines using java.util.RegEx
(define (// pattern)
  (let ((p (Pattern.compile pattern)))
    (lambda (object)
      (.find (.matcher p (.toString object))))))
Similarly, file filtering is implemented in 6 lines using java.io.File methods and takes a function argument for filtering.

[(link "tradeoffs" "continue")] }) (("LL2") {
[(link "title" "restart")]

Conclusion:
Lessons from building
lightweight libraries in Jscheme

Things that lighten code: Summary: reduce cognitive load whenever possible

[(link "title" "restart talk")] }) (("tradeoffs"){
[(link "LL2" "continue")]

Tradeoffs


[(link "LL2" "continue")] }) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (("help") (linklist '( ("set-style" "Change CSS style of the talk") ("set-default-style" "Reset CSS style to the default") ("set-print-style" "Set CSS style to a printable style") ("title" "Return to talk")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (("set-style") (string-append {