One final interaction that has not been attempted is the ability to sub-class Java classes from within Forth. This may not be necessary and will not be implemented until it is clear what the benefit is and how to do it cleanly.
Java-reference <optional-arguments> argument-count java::call method-nameor like this:
Java-class-name <optional-arguments> argument-count java::call method-nameThe argument-count can be zero.
A short example to set the size of a Java GUI component is this:
150 400 2 java::call setSizeThis example assumes that a reference to the desired Java GUI object is already on the stack. More examples appear below.
setSize
method in the java.awt.Component
class specifies that the two
arguments are passed in as width, then height. So, in Java, c.setSize(100, 200)
would specify a width of 100 and a height of 200. In Misty Beach Forth,
the call would be something like this: 200 100 2 java::call setSize
.
The 200 100 2 java::call setSize
example assumes that a
reference to a java.awt.Component
object is already on the
stack.
The reverse order of arguments was selected because Win32Forth does it this way. From the documentation:
When calling Windows procedures, you must pass all parameters to window in reverse order to the order specified by any window documentation you may have seen.There doesn't seem to be a good reason to do it either way, and LMI Forth does it the other way:
When calling Windows from Forth, the parameters for Windows API functions are pushed onto the stack from left to right, in the same order as is specified in the Microsoft Windows programming manual.If anyone can provide a compelling reason to do it one way or the other, I would like to hear it, but this seems to be shaping up a lot like the big-endian/little-endian debate between CPU families.
DUP
allows this easily. With the object reference last on the
stack, extra stack manipulation is required.
new
operator from within Java. Misty Beach Forth also allows
you to create new Java objects. This is done with
the java::new
word.
You can create a new Java object like this:
[[ <optional-arguments> <class-name> java::newSome examples are this:
Forth | Comment |
[[ java.awt.Dimension java::new |
No arguments, so the Dimension object has its default value of (0,0) |
[[ 10 20 java.awt.Dimension java::new |
Two arguments... |
[[ 75 TOSHORT java.lang.Short java::new |
Make a java.lang.Short object with a value of 75. The TOSHORT word is necessary to helpMisty Beach Forth find the right constructor for this object. |
Java works differently. Everything in Java has a type and you can't add numbers to letters without first converting the letter to a number. Because Java cares about the types of the data and Forth doesn't track this information, it is important that the Misty Beach Forth programmer supply necessary type information when calling Java methods. Misty Beach Forth integer values correspond to Java int values. Misty Beach Forth provides the utility words TOBYTE, TOSHORT, TOCHAR, TOBOOLEAN and TOSTRING to tag or convert (as needed) values on the Forth stack so that Java interaction works properly.
Forth Word | Comment |
TOBYTE |
Java byte values are signed 8-bit quantities. This word tags the word at the top of the Forth stack as having byte type. Note that the byteness is only for the benefitof Java and that the value on the Forth stack is not truncated by the TOBYTE word. Only the low 8 bits are used by Java calls after the value is converted to a byte. |
TOSHORT |
Java short values are signed 16-bit quantities. This word tags the word at the top of the Forth stack as having short type. Note that the shortness is only forthe benefit of Java and that the value on the Forth stack is not truncated by the TOSHORT word. Onlythe low 16 bits are used by Java calls after the value is converted to a short. |
TOCHAR |
Java char values are unsigned 16-bit quantities. This word tags the word at the top of the Forth stack as having char type. Note that the charness is only forthe benefit of Java and that the value on the Forth stack is not truncated by the TOCHAR word. Onlythe low 16 bits are used by Java calls after the value is converted to a char. |
TOBOOLEAN |
Java boolean values have two values: true and false. This word tags the word at the top of the Forth stack as having boolean type. Note that the booleaness is only forthe benefit of Java and that the value on the Forth stack is not changed by the TOBOOLEAN word.When calling Java, zero is considered false and every other value is considered true. |
TOSTRING |
Java String objects are not the same thing as Forth counted strings. This word takes a Forth counted string (like those created by S") and converts it to a Java String object. Note that unlike the other TOxxx words, this word does change the contents of the stack. |
[[ java.awt.Frame java::new ( Make a new Frame ) DUP 150 400 2 java::call setSize ( Set its size in pixels ) DUP 0 java::call show ( Show it )This results in a new Frame appearing on your screen. You can move this Frame around and change its size. You cannot, however, close it using the mouse because you haven't installed a close handler.
We keep an extra reference to the Frame on the stack so that we can close it from within Forth (you can open the stack view to see this). To get rid of the Frame, type this:
0 java::call dispose
[[ java.awt.Frame java::new DUP 150 400 2 java::call setSize DUP 0 java::call show : CLOSE [ DUP ] LITERAL 0 java::call dispose ; ( Make a close action ) WINDOW_ADAPTER ( Create a Window adapter. ) DUP ' CLOSE 1 java::call setClosingAction ( Set the close action on the window adapter ) 1 java::call addWindowListener ( Install the adapter )
This is the same code we used above to create a Frame, but we have added four lines that create and install code to listen for a close-window request and then close the Frame when requested. One way to write the Java language equivalent is:
class Example { public static void main(String[] args) { final Frame f = new Frame(); f.setSize (150, 400); f.show(); f.addWindowListener (new WindowAdapter() { public void setClosingAction (WindowEvent e) { f.dispose(); } } } }
Forth Adapter | Creating Word | Methods to install Forth actions |
ForthActionAdapter |
ACTION_ADAPTER |
|
ForthAdjustmentAdapter |
ADJUSTMENT_ADAPTER |
|
ForthComponentAdapter |
COMPONENT_ADAPTER |
|
ForthContainerAdapter |
CONTAINER_ADAPTER |
|
ForthFocusAdapter |
FOCUS_ADAPTER |
|
ForthItemAdapter |
ITEM_ADAPTER |
|
ForthKeyAdapter |
KEY_ADAPTER |
|
ForthMouseAdapter |
MOUSE_ADAPTER |
|
ForthMouseMotionAdapter |
MOUSE_MOTION_ADAPTER |
|
ForthTextAdapter |
TEXT_ADAPTER |
|
ForthWindowAdapter |
WINDOW_ADAPTER |
|
The mapping from the Forth action installation methods to the call-back methods in the Java adapters is, I hope, obvious. The Frame example above shows how to install actions in adapters and then how to add adapters to Java GUI components.
One caution: The GUI adapters are called on Java's AWT thread and so the installed Forth actions are called there, too. This means that GUI programs are inherently multi-threaded. Misty Beach Forth does provide a separate stack for the GUI, but has not implemented a true multi-threaded Forth (yet!). One example of this is that the GUI actions, while they run on their own thread and stack, do not have a separate dictionary. They should (and will, in the future).