From: Ken A. <kan...@bb...> - 2004-02-02 22:10:58
|
I tried sending an earlier version of this message, but i got hints that it is in mail limbo somewhere. Constructing an object can be verbose in Java, because often you need a temporary variable followed by a raft of setter calls. The raft grows even larger if some fields have values that must be constructed the same way. Here's an example from the JabberBeans API (though you can probably find bigger examples in uses of Swing): IQAuthBuilder iqa = new IQAuthBuilder(); iqa.setUser(user); iqa.setPassword(password); iqa.setResource(resource); InfoQueryBuilder iqb = new InfoQueryBuilder(); iqb.setType("set"); iqb.setIdentifier("set-1"); iqb.addExtension(iqa); Some languages, like Python and Common Lisp, lets you construct an object and initialize it with keyword value pairs. Tim's JLIB even does this one better by bypassing the keyword altogether and just allowing extra arguments to be assigned to the "most appropriate" field. For example you can make a red Quit button with (Button "Quit" Color.red$) or (Button Color.red$ "Quit"). Unfortunately this requires you to come up with a different API than the underlying Java, and there may not be a good choice of "most appropriate" field, if for example, all the fields are Strings. Here's a procedure (with object .method val ... .method val ...) that generalizes keyword value pairs. The keywords are Javadot methods and they can take more than on value: (define (with what . kvs) (define (method? x) (instanceof x JavaMethod.class)) (define (op kvs) (if (null? kvs) what (if (method? (car kvs)) (args (car kvs) '() (cdr kvs)) (error {expected operator, but got [(car kvs)]})))) (define (args method sofar kvs) (if (null? kvs) (begin (apply method what (reverse sofar)) what) (if (method? (car kvs)) (begin (apply method what (reverse sofar)) (op kvs)) (args method (cons (car kvs) sofar) (cdr kvs))))) (op kvs)) Here's what the above Java code might look like in JScheme: (with (InfoQueryBuilder.) .setType "set" .setIdentifier "set-1 .addExtension (.build (with (IQAuthBuilder.) .setUsername user .setPassword password .setResource resource)))))) Here's another example constructing an FTP client using an API from http://www.enterprisedt.com/downloads.html: (define (ftpClient user password remoteMachine directory) (define ftpc (with (FTPClient. remoteMachine) .debugResponses #t .login user password)) (if (not (or (not directory) (isNull directory) (equal? directory ""))) (.chdir ftpc directory)) ftpc) The .login method takes two arguments. The nice thing about this idiom is that objects can be initialized where they're needed and remain anonymous in many cases. We could gain some performance by writing this as a macro, but this hasn't been an issue so far. k |