A: The design of Bistro was driven by some very specific goals. Foremost among these are:
Goals 1 and 2 were the primary factors I had to keep in balance during language design. They provided a constant tension for many decisions. Goals 2 and 6 drove the design of the syntax for Bistro messages and methods. Goals 3 and 4 drove the development of the initial class library supplied with Bistro. Goals 5 and 7 provided support for improving performance. Goal 8 provided a bridge to the existing Smalltalk world, because the future of Smalltalk remains somewhat murky while Java continues to garner increasing market share in all industry sectors.
A: Smalltalk and Java both have their technical merits. Many of those found in Java trace their origins back to Smalltalk. Together, Smalltalk and the Java platform provide a powerful combination. From a certain point of view, their integration seems inevitable.
Smalltalk is far more expressive and readable than Java. As I indicated in Using Natural Language in Software Development, Smalltalk provides a natural way to model the elements of natural language problem descriptions by directly supporting the linguistic metaphors we use in object-oriented software design. Thus, Smalltalk can provide superior traceability from the code back to the original requirements.
Object-oriented designs often need metaprotocols for factory and registry methods. Object-oriented frameworks with metaprotocols often make polymorphic metaprotocols desirable. Java static methods support a kind of inheritance, but without full polymorphism. So, Java does not support full metadesign and metaprogramming. However, like Smalltalk, Bistro provides first-class metaclasses, which support both inheritance and full polymorphism. See the introductory paper for more details regarding how Bistro metaclasses are implemented using the underlying Java object model.
Smalltalk supports generic programming easily, partly because of its dynamic object typing. Many of the Java classes have only recently achieved a level of parity in convenience with that found in Smalltalk - e.g., the Java 2 collection class framework. However, some parts of the Java platform have exceeded those addressed by standard Smalltalk - e.g., network programming. Java is maturing at a rapid pace, with broad support from the computing and communications communities.
Smalltalk has no standardized namespace mechanism. This can produce class name conflicts and complicates the integration of class libraries from disparate software vendors. Smalltalk has no standardized binary distribution mechanism for its classes. While Smalltalk's image-based development model contributes to its agility and productivity, it complicates product deployment.
Java has grown to cover a wide variety of hardware platforms and includes support for thin clients, web applications, distributed services, embedded devices, smart cards and rings. More and more hardware and software vendors are integrating Java into their solutions. The Java platform has finally matured to the point of significant adoption by Fortune 1000 companies.
The implementation of Bistro demonstrates that Smalltalk can be hosted on the Java platform. Bistro maps the Smalltalk object model onto the Java VM, and the essential class libraries have been ported. Most of the ANSI standard Smalltalk behaviors have been implemented.
As more enterprises embrace Java and deploy mission critical applications on the Internet, the demand for mature objects and frameworks will increase, and more opportunities for the reuse of Smalltalk classes and applications that address those needs will arise. Given the foregoing factors, why would anyone want to limit their options for class reuse and deployment to a proprietary VM implementation?
A: See the performance benchmarks. Bistro supports optional type annotations and both typed and untyped method resolution. Messages sent to untyped objects use dynamic method resolution at runtime. For untyped message receivers, the Java reflection facility is used to resolve the implementation of a method based on the class of the receiver. The dynamic dispatch facility caches the result of the method resolution so that future invocations are faster. Methods invoked through the dynamic dispatch facility execute about 20-40 times slower than primitive Java methods. However, continuing advances in Java VM design and computer hardware make this performance difference insignificant. Also, Bistro provides additional mechanisms for improving performance, including compiler optimizations of some control structures, type annotations, primitive Java methods, and access through the Java Native Interface (JNI) to native methods.
Unlike Smalltalk, Bistro supports the ability to define the type of a variable or argument. The Bistro compiler retains such type information when translating code into Java. The Bistro compiler optimizes messages sent to objects whose types are known at compile time. So, messages sent to self and super are always optimized. Messages sent to variables and arguments that have type annotations are also optimized. Optimized messages perform with the same speed as primitive Java messages.
Message expressions can be cast to a specific type using a special idiom. The compiler recognizes the as: keyword message and optimizes a message sent to the expression result. For example, the message x will be optimized in the following expression:
(5 @ 6 as: Point) x
(5 @ 6) creates a
Point, but the compiler does not know
this until the
Point instance is explicitly cast to the
Bistro classes may include primitive methods written in Java. So, primitive Java methods have full and direct access to the classes included in the Java platform. Many of the classes in the Bistro library have been implemented using the underlying Java platform classes, e.g., some of the collection classes and some of the stream classes. Seamless integration with Java was one of the many design goals for Bistro, but primitive Java methods also provide a way to increase performance for the "hot spots" in a design.
Like Java, Bistro also supports the ability declare native methods. Native methods provide direct support for the Java Native Interface (JNI). The Bistro compiler translates native method definitions directly into Java native method definitions. These native methods can then be implemented using standard JNI programming techniques. So, Bistro supports the same mechanism as Java for methods that require maximum performance, or direct access to OS services. However, such methods tie a system to a specific OS platform and the code is no longer 100% pure Java.
A: Yes. Please see the notes regarding the plans for roundtrip SIF conversions.
A: There are many syntactic similarities between Bistro and Smalltalk, but there are also some differences.
To retain the expressiveness and readability of Smalltalk, Bistro uses essentially the same syntax for unary, binary, and keyword messages. However, to support seamless integration with Java, Bistro extends the keyword message syntax with anonymous argument lists. Thus, keyword messages can include arguments separated by colons, as in the following example.
(Point basicNew: 0 asPrimitive : 0 asPrimitive)
The Bistro compiler translates the above expression into the following Java code.
(new Point( 0, 0 ))
The syntax for Smalltalk blocks and methods have many similarities, but block signatures are contained within their delimiters while method signatures precede their bodies, which have no delimiters. So, while blocks have delimiters, Smalltalk method bodies do not. This was one of the factors that originally drove the design of the Smalltalk chunk file formats. When represented in a flat file, Smalltalk method definitions need some kind of delimiter - hence the use of a bang (!) to mark the end of a Smalltalk method.
"Example Smalltalk method (chunk)"
However, Bistro methods have delimiters. I chose to use the same delimiter used for blocks - square brackets.
"Example Bistro method"
In fact, square brackets are also used to delimit class scopes. The consistent use of square brackets as delimiters makes Bistro class definitions structurally similar to Java class definitions, at least with respect to scopes. It also eliminates the need for code chunks. Overall, Bistro increases the similarities between blocks and methods, while finally providing a truly declarative class and method definition syntax.
Bistro local block variables do not need to be predefined in a separate section within a block as they are in Smalltalk. Instead, they can be defined and used in-line as they are in Java.
"Example Bistro block"
[ :a :b |
max := a < b ifTrue: [ b ] ifFalse: [ a ].
Java is strongly typed at compile-time, while Smalltalk is not. Bistro variables may be typed, but type annotations are not required. When a message receiver has a type annotation, the Bistro compiler translates the message directly into a Java method invocation. When a message receiver has no explicit type information, the Bistro compiler translates the message into an appropriate perform: invocation. The perform: methods resolve the type of the message receiver at runtime and select the appropriate method based on the actual receiver type. All variable type annotations appear after a variable name in Bistro. The following code fragment provides an example.
"Example typed Bistro variable."
sampleVariable (SmallInteger) := 5.
Bistro class and type definitions use keywords in a way that
resembles Smalltalk code, but the overall structure of the definitions
resembles Java code. The following table provides a summary of the class
and type definition patterns supported by Bistro. Note that each occurrence of
] indicates where variable and method definitions may appear, and each
Type "..." indicates a list of implemented types.
Notice that Bistro supports first-class metaclasses like those found in Smalltalk. Both Smalltalk and Bistro metaclasses provide full polymorphism. However, because Bistro metaclasses are all singletons, you cannot declare metaclass methods to be abstract. See the Bistro introductory paper for a fuller discussion of metaclasses and metatypes.
Smalltalk has no standardized namespace mechanism. This can produce class name conflicts and complicates the integration of class libraries from disparate software vendors, or even different development teams within an enterprise. However, Java includes a mechanism for separating classes into packages. The Java class library makes extensive use of the package mechanism to organize the standard Java classes.
Bistro reuses the underlying Java package mechanism by supporting package and import statements prior to a class definition. The following code fragment includes examples of both a package declaration and a list of imported packages and classes.
package: third.person.util; "Identifies the current package."
import: smalltalk.collection.*; "Imports all the collection classes."
import: smalltalk.stream.*; "Imports all the stream classes."
import: smalltalk.geometry.Point; "Imports the Point class."
The Bistro compiler imports certain classes automatically, so you
need not include them explicitly. This resembles how the Java compiler
automatically includes the classes from the package named
implicit imports include all the following Bistro classes.
"All the behavior classes, especially the literals."
"All the magnitudes, especially the literals."
"The literal collection classes"
Oracle and Java™ are registered trademarks of Oracle and/or its affiliates.
SourceForge™ is a trademark of Geeknet, Inc.
Permission is granted to copy this document provided this
copyright statement is retained in all copies.
Copyright 1999-2001 Nikolas S. Boyd.