On Thu, 2002-03-14 at 03:50, Peter Zelezny wrote:
> > --- BEGIN CODE SNIPPET ---
> > XChat xchat; // defined elsewhere
> > DCC[] dcc = xchat.getDCCList();
> >
> > for (int i = 0; i < dcc.length; i++)
> > System.out.println("File: " + dcc[i].getFile());
> > --- END CODE SNIPPET ---
> >
> > Notice how much shorter and cleaner my code is.
>
> The problem here is that you have to implement a new method (getDCCList)
> everytime a new list is added to plugin.c. Also, if the user tries to use
> a new list that wasn't available in earlier versions, their java won't
> even compile.
I don't necessarily have to add a new method for each list; getDCCList
is just a convenience method. I also intend to have a 'generic' getList
method that returns a list by name. This way, if someone wants their
code to compile on an earlier version that doesn't have that list, they
may use the generic method instead.
That one's Java code will not compile on an earlier version is probably
not a problem anyway; remember that Java binaries are very portable, so
Java plugins will probably be distributed with pre-compiled binaries. In
this case, the Java code that tries to access the nonexistent list will
throw an exception (which is what would happen if it used a generic
method, anyway). Of course, if the Java code is _changed_ it has to be
recompiled.
The generic method would be used like this:
--- BEGIN CODE SNIPPET ---
XChat xchat; // defined elsewhere
DCC[] list = (DCC[]) xchat.getList("dcc");
--- END CODE SNIPPET ---
If the list 'dcc' does not exist, an exception is thrown. Otherwise, an
array of the correct type (DCC[]) is returned. Or perhaps it would be
Object[] with only DCC elements. I'll have to figure that out when I go
to implement this.
> > > If it can be implemented like this, I don't see a need for a function that
> > > returns a list of available fields and types. The implementation of
> > > xchat.list_str would simply call the C-plugin xchat_list_str and give the
> > > result direct (or converted to a Java String). For that, I might remove
> > > that "context" field that was causing some confusion.
> >
> > And how can I be absolutely sure it's a string and not, say, an integer?
>
> Because xchat_list_str always returns strings, and xchat_list_int
> always returns ints. The plugin author knows that "file" is a string,
> and "cps" is an int, so they'll call the right function to retreive it.
But surely that can be exploited maliciously. What if the plugin author
calls xchat_list_str on "cps"? (Hint: Segmentation fault. Or worse.)
Remember that, unlike C code, Java code is _not_ considered trusted, and
so mustn't be allowed to do anything that could compromise the system's
security.
> I'm not completely hardline on that, I just don't want to repeat the
> same mistakes of not making the interfaces extendable.
> When I said the interface should all be the same, it doesn't mean you
> can't take advantage of some the languages features. But most things should
> be the same, for example, I assume you've providing something like
> xchat.hook_command/server/print right? It would be best if these functions at
> least had the same name as in the C-interface, and roughtly the same args.
> No point in calling it xchat.add_command in Java, xchat_hook_command in C
> and xchat.add_cmd_handler in python etc.
How about 'hookCommand'?
> As for the list API, I think you're example above has potential problems:
>
> 1) When new lists are available, Java coders won't see them immediately.
> 2) When new fields are available, ""
> 3) Accessing unsupported lists will probably cause javac to bomb out.
>
> Maybe something like this would solve these three:
>
> {
> xchat_list list;
>
> list = xchat.listGet("dcc");
> if(list)
> {
> for(int i = 0; i < list.length; i++)
> {
> System.out.println("File: " + list[i].getStr("file"));
> System.out.println("Size: " + list[i].getInt("size"));
> }
> list.free(); // or use garbage collection? *shrug*
> }
> }
>
> I think the indexing using 'i' is unimplementable though.
Because it's a singly linked list?
In this case, I'd provide an Iterator, which can only iterate forwards,
as for a singly linked list. Like so:
--- BEGIN CODE SNIPPET ---
XChat xchat; // defined elsewhere
for (Iterator i = xchat.getList("dcc"); i.hasNext();)
System.out.println("File: " + ((DCC) i.next()).getFile();
--- END CODE SNIPPET ---
To address your concerns about there being a DCC class, I suggest that
all of these classes (DCC, etc) implement an interface that provides a
'getField' method, to generically fetch fields out of it without calling
it by its specific class name. Like so:
--- BEGIN CODE SNIPPET ---
XChat xchat; // defined elsewhere
for (Iterator i = xchat.getList("dcc"); i.hasNext();)
System.out.println("File: " +
((XChatListElement) i.next()).getField("file"));
--- END CODE SNIPPET ---
As before, this would throw an exception if the field doesn't exist.
In this configuration, we can have a DCC class (like the previous
example), but we don't reference this class by name. That way it gets
past the compiler.
One last thing. In Java, it is possible to access a class, method, etc
that doesn't exist at compile time but does exist at run time, using the
Reflection API.
--- BEGIN CODE SNIPPET ---
XChat xchat; // defined elsewhere
for (Iterator i = xchat.getList("dcc"); i.hasNext();) {
Object o = i.next();
System.out.println("File: " +
o.getClass().getMethod("getFile", new Class[] {}).invoke(o, new
Object[] {});
}
--- END CODE SNIPPET ---
This way, you can get it past the compiler. It's harder than having a
generic way of getting fields, like above, but it's still possible.
Regards,
Alex.
--
PGP Public Key: http://aoi.dyndns.org/~alex/pgp-public-key
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS d- s:++ a18 C++(++++)>$ UL+++(++++) P--- L+++>++++ E---- W+(+++) N-
o-- K+ w--- !O M(+) V-- PS+++ PE-- Y+ PGP+(+++) t* 5-- X-- R tv b- DI
D+++ G e h! !r y
------END GEEK CODE BLOCK------
This is a digitally signed message part