• Ingen resultater fundet

In Beta and gbeta, patterns are values. This corresponds to the situation in natural language, where concepts are also in a sense values. Of course, in these matters there will never be absolute truths. However, a given concept, as designated by a spoken or written word, should be available from the appearance (sound or graphical shape) of the designation, such that understanding can proceed. The alternative view, being that the word denotes an entity with a unique identity and some internal state, does not really make sense, since there is no place to go and look up what that state is; moreover, in case of a change in the alleged state of the concept, should all the instances (mental images of phenomena in the extension) be updated to reect the changes?

From a technical point of view, the fact that patterns are values in Beta makes it natural that (variable pattern) attributes may have them as values.

These values are exclusively taken from the set of patterns known at compile-time. The patterns are organized into a partial order (the specialization order, see Sect. 3.5) which is also completely known at compile time. Because of this, there is no support for computation on patterns in Beta. Patterns may be compared for equality or inequality, but there is no way to compute a pattern by giving one or more other patterns as arguments to an operation.

However, there are cross-domain operations, like inheritance (see Sect. 3.6) which produces a pattern from another pattern and a mixin (see the next section), or like instantiation which produces an object from a pattern (see Sect. 3.9). The fact thatBetahas attributes whose values range over patterns makes (the equivalent of) classes and methods rst class entities. They may become even more rst class, though.

Ingbeta, a genuine operation on patterns is introduced, taking a number of patterns as operands and producing a new pattern. This introduces the concept of pattern computations. As an analogy, assume that we started out with a set of natural numbers, such that comparison would be almost the only supported use, and then enhanced it with an operation like `addition', such that numbers

3.1. PATTERNS ARE VALUES 41 not in the original set could be constructed. The operation in question, pattern merging, is presented in Sect. 3.7.

Since patterns are values and the merging operation is dened entirely in terms of those values, such pattern computations can be, and are, allowed at run-time ingbeta. This means that some patterns in a program execution may not be available for static analysis at compile-time, they are genuine run-time values. This makes patterns (classes and methods) even more rst class than they are in Beta. Note that the type analysis of a dynamically constructed pattern is subsumed by an already existing case, namely the case where a given pattern is not known at compile-time but it is known to be a specialization of a given pattern; this is, e.g., typically the case with virtual patterns. Run-time construction of classes is covered in more detail both in other sections of this chapter and in Sect. 7.2.

Please note that this concept is signicantly dierent from the ability in certain dynamic languages (like Self, CLOS and Smalltalk) and recently also in

Betato compile classes or other entities during a program execution, and then integrate the resulting compiled entity into the execution and continue running it. The Java dynamic class loader plays a similar role.

One important dierence between dynamic compilation and real class com-putations is that a new, dynamically compiled class would have no particular relation to existing classes in the program, though it could be created as a sub-pattern of a class which is already known in the program, and integrated by means of subpattern polymorphism [75]. In contrast, the value of a pattern merging operation is fully determined by the (existing) patterns being merged, and the type analysis takes this knowledge into consideration (using whatever information is known about the operands). Dynamic compilation or loading yields results which are not so well integrated into the language, in particular in connection with static type systems. In Java [6, p. 315++], for example, a dynamically loaded class is not a rst class entity similar to all all other classes;

it is an object, instance of the class Class, and instances of such a class are created using the method newInstance instead of using the built-in operator

new, and the new object is not recognized as having a type which is associated with the dynamically loaded class, it is just an Object, which requires a dy-namic cast in order to be useful. In contrast, dydy-namically created classes in gbeta are fully integrated; the type system does not know the complete type, but whatever is known is used, and the type-checking situation is no dierent from the case with virtual patterns.

On the other hand, only certain patterns may be computed using pattern merging. An analogy would again be the addition of natural numbers. If all the numbers available from the beginning are even numbers, then there is no way to add them up to an odd number. Similarly, if there is no pattern in a program which has, say, a printmethod then pattern computations cannot be used to obtain one. See Sect. 3.2 and 3.7 for more details.

In other languages, classes and methods are not generally considered values.

In Smalltalk where everything is an object, the consistent choice is to make classes objects, too, and this is indeed the case. Consequently, new classes are

newer computed, only compiled. A well-known result of letting classes be objects as well is that it is hard to nd a simple, understandable way to terminate the chain of objects from a given object to its class, which is then also an object, to the class of the class object, which is then also an object, to:::

This innite regress problem was actually one of the motivations for devel-oping classless languages like Self and Cecil.

One special topic, which is linked to the question of whether classes are values or (more like) objects, is the topic of shared state. In many languages, a

class may have some state which is accessible from every instance of the class by means of special attributes. These attributes are called static members in C++, static elds in Java, class variables in Smalltalk, shared slots in CLOS, and slots with class allocation in Dylan. `Once functions' in Eiel oer the functionality of on-demand initialization and (thereafter) shared state, all in all similar to the others. The motivation for this mechanism is that some tasks need to deal with all the instances of a class, e.g., counting all instances, keeping lists of them, or ensuring that at most one of them is in a special state.

It seems that this notion forces a class to be object-like, having its own state and hence having identity, such that aliasing is non-transparent and implicit copying generally not allowed. If classes are actually somewhat object-like, the natural question is why not make them into real objects like in Smalltalk?

The answer could be that those classes are not objects to any signicant degree. For instance, if the core properties of a classthe description of the structure of instanceswere actually mutable, then it would be possible to add, remove, or change attributes described by the class. That immediately raises the question already mentioned above: When the class changes, should all the existing instances automagically be updated? In CLOS it is possible to change a class in a running program, and objects will be updated by a user-dened or automatically generated version updating procedure; but this is again dynamic compilation as opposed to an integrated language feature. It would not be very easy to reconcile with static type-checking, either, as is demonstrated in the Orm system [58, 53] where this topic has been exploredonly a quite limited class of special cases can be handled without running the entire type-analysis again, and the running program execution is lost when the type-analysis must be re-done.

In other words, the identity and mutability aspect of classes associated with shared state are marginal to the class as such. Since classes in those languages are constant, global entities, a more suitable explanation of the shared attributes is that they are simply global variables whose names are made available in a special name space which is identied with the class name. This is actually also a common way to describe what static members are, in the C++ community.

Without shared state, classes in C++, Java, and Eiel become similar toBeta patterns (used as classes), because they are values, but there is no support for computation with those values.

By the way, the natural way to obtain shared state in languages with general block structure likeBetaandgbetais simply to move the declaration one level out in the block structure [71, 72].