[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

6. Type Definitions

The following is the syntax of type definitions.

 
type-definition ::= class-definition
        | interface-definition
        | ;

The specification of a type-definition is determined as follows. If the type-definition consists only of a semicolon (;), then the specification is empty. Otherwise the specification is that of the class or interface definition. Such a specification must be satisfied by the corresponding class or interface definition.

The rest of this chapter discusses class and interface definitions, as well as the syntax of modifiers.

6.1 Class and Interface Definitions  
6.2 Modifiers  


6.1 Class and Interface Definitions

Class and interface definitions are quite similar, as interfaces may be seen as a special kind of class definition that only allows the declaration of abstract instance methods and final static fields (in the Java code [Gosling-etal00]). Their syntax is also similar.

 
class-definition ::= [ doc-comment ] modifiers class ident
            [ class-extends-clause ] [ implements-clause ]
            class-block
class-block ::= { [ field ] ... }

interface-definition ::= [ doc-comment ] modifiers interface ident
           [ interface-extends ]
           class-block

Documentation comments for classes and interfaces may not contain JML specification information. See section 4.5 Documentation Comments, for the syntax of documentation comments.

See section 7. Class and Interface Member Declarations, for the syntax and semantics of fields, which form the essence of classes and interfaces.

The rest of this section discusses subtyping for classes and interfaces and also the particular modifiers used in classes and interfaces.

6.1.1 Subtyping for Type Definitions  
6.1.2 Modifiers for Type Definitions  


6.1.1 Subtyping for Type Definitions

Classes in Java can use single inheritance and may also implement any number of interfaces. Interfaces may extend any number of other interfaces.

 
class-extends-clause ::= [ extends name [ weakly ] ]
implements-clause ::= implements name-weakly-list
name-weakly-list ::= name [ weakly ] [ , name [ weakly ] ] ...
interface-extends ::= extends name-weakly-list

The meaning of inheritance in JML is similar to that in Java. In Java, a when class S names a class T in S's class-extends-clause, then S is a subclass of T and T is a superclass of S; we also say that S inherits from T. This relationship also makes S a subtype of T, meaning that variables of type T can refer to objects of type S. In Java, when S is a subclass of T, then S inherits all the instance fields and methods from T.

A class may also implement several interfaces, declared in its implements-clause; the class thus becomes a subtype of each of the interfaces that it implements.

Similarly, an interface may extend several other interfaces. In Java, such an interface inherits all of the abstract methods and static final fields from the interfaces it extends. When interface U extends another interface V, then U is a subtype of V.

In JML, model and ghost features, as well as specifications are inherited. A subtype inherits from its supertypes:

It is an error for a type to inherit a field x from two different supertypes if that field is declared with different types.

It is an error for a type to inherit a method with the same formal parameter types but with either different return types or with conflicting throws clauses [Gosling-etal00]. (There are other restrictions on method inheritance that apply when MultiJava is used [Clifton-etal00].)

In Java one cannot inherit method implementations from interfaces, but this is possible in JML, where one can implement a model method in an interface. It is illegal for a class or interface to inherit two different implementations of a model method.

In JML, instance methods have to obey the specifications of all methods they override. This, together with the inheritance of invariants and history constraints, forces subtypes to be behavioral subtypes [Dhara-Leavens96] [Leavens-Naumann06] [Leavens06b]. However, history constraints are not inherited from supertypes whose names are marked with weakly in the relevant clause. Such subtypes are weak behavioral subtypes, and should only be used in ways that do not permit cross-type aliasing [Dhara-Leavens94b] [Dhara97].

See the report, "Desugaring JML Method Specifications" [Raghavan-Leavens05] for more about the details of specification inheritance in JML.


6.1.2 Modifiers for Type Definitions

In addition to the Java modifiers that can be legally attached to a class or interface definition [Gosling-etal00], in JML one can use the following modifiers.
 
  pure model
  spec_java_math spec_safe_math spec_bigint_math
  code_java_math code_safe_math code_bigint_math
  nullable_by_default
See section 6.2 Modifiers, for the syntax and semantics of modifiers in general.

A type definition may be modified with the JML modifier keyword pure. The effect of declaring a type pure is that all constructor and instance method declarations within the type are automatically declared to be pure (see section 7.1.1.3 Pure Methods and Constructors, for more about pure methods). Hence, once an object of a class is created, it will be immutable, and furthermore, none of its instance methods will have any side effects. However, its static methods may still have side effects, as the pure does not apply to the static methods declared in a type. Furthermore, although an override of a pure method must be pure, instance methods declared in subtypes that do not override this supertype's methods need not be pure. Hence, such a subtype does not necessarily have immutable objects. So, in essence, declaring a class pure is merely a shorthand for declaring all of the constructors and instance methods pure.

[[[ Pure does not make a class immutable either, since a method might return a reference to an internal representation which is then modified by some non-pure method in its class. Is it sufficient if all fields are also fields of pure types (recursively)? Then there are arrays. And also all fields would need to be private to have immutability. - DRC ]]]

A type declaration that is declared with the modifier model is a specification-only type. Hence, such a type may not be used in Java code, and may only be used in annotations. It follows that the entire type definition must be contained within an annotation comment, and consequently annotations within the type definition do not need to be separately enclosed in annotation comments, as is demonstrated in the example below. The scope rules for a model type definition are the same as for Java type definitions, except that a model type definition is not in scope for any Java code, only for annotations.

[[[Model types are seldom used in JML. Since the runtime assertion checker doesn't work with them, I wonder if it would be best to get rid of them completely. You could always just define a Java type, which would be useful for runtime assertion checking.]]]

[[[ May a model type definition appear in more than one specification file of a refinement sequence, with any member declarations being combined together? I'd prefer that it only be allowed to appear once and be required to be completely defined in one spec file - easier for tools. -- DRCok ]]]

[[[Need to explain the math modifiers.]]]


6.2 Modifiers

The following is the syntax of modifiers.

 
modifiers ::= [ modifier ] ...
modifier ::= public | protected | private
        | abstract | static |
        | final | synchronized
        | transient | volatile
        | native | strictfp
        | const             // reserved but not used in Java
        | jml-modifier
jml-modifier ::= spec_public | spec_protected
        | model | ghost | pure
        | instance | helper
        | uninitialized
        | spec_java_math | spec_safe_math | spec_bigint_math
        | code_java_math | code_safe_math | code_bigint_math
        | non_null | nullable | nullable_by_default
        | extract

The jml-modifiers are only recognized as keywords in annotation comments. See section 4. Lexical Conventions, for more details.

The Java modifiers have the same meaning as in Java [Gosling-etal00].

Note that although the modifiers grammar non-terminal is used in many places throughout the grammar, not all modifiers can be used with every grammar construct. See the discussion regarding each grammar construct, which is summarized in B. Modifier Summary.

In the following we first discuss the suggested ordering of modifiers The rest of this section discusses the JML-specific modifiers in general terms. Their use and meaning for each kind of grammatical construct should be consulted directly for more details.

6.2.1 Suggested Modifier Ordering  
6.2.2 Spec Public  
6.2.3 Spec Protected  
6.2.4 Pure  
6.2.5 Model  
6.2.6 Ghost  
6.2.7 Instance  
6.2.8 Helper  
6.2.9 Monitored  
6.2.10 Uninitialized  
6.2.11 Math Modifiers  
6.2.12 Nullity Modifiers  


6.2.1 Suggested Modifier Ordering

There are various guidelines for ordering modifiers in Java [[[citations?]]]. As JML has several extra modifiers, we also suggest an ordering; although this ordering is not enforced, various tools may give warnings if the suggestions are not followed, as following a standard ordering tends to make reading declarations easier. For use in JML, we suggest the following ordering groups, where the ones at the top should appear first (leftmost), and the ones at the bottom should appear last (rightmost). In each line, the modifiers are either mutually exclusive, or their order does not matter (or both).

 
  public private protected spec_public spec_protected
  abstract static
  model ghost pure
  final synchronized
  instance helper
  transient volatile
  native strictfp
  monitored uninitialized
  spec_java_math spec_safe_math spec_bigint_math
  code_java_math code_safe_math code_bigint_math
  non_null nullable nullable_by_default
  code extract
  peer rep readonly


6.2.2 Spec Public

The spec_public modifier allows one to declare a feature as public for specification purposes. It can only be used when the feature has a more restrictive visibility in Java. A spec_public field is also implicitly a data group.


6.2.3 Spec Protected

The spec_protected modifier allows one to declare a feature as protected for specification purposes. It can only be used when the feature has a more restrictive visibility in Java. That is, it can only be used to change the visibility of a field or method that is, for Java, either declared private or default access (package visible). A spec_protected field is also implicitly a data group.


6.2.4 Pure

In general terms, a pure feature is one that has no side effects when executed. In essence pure only applies to methods and constructors. The use of pure for a type definition is shorthand for applying that modifier to all constructors and instance methods in the type (see section 6.1.2 Modifiers for Type Definitions).

See section 7.1.1.3 Pure Methods and Constructors, for the exact semantics of pure methods and constructors.


6.2.5 Model

The model modifier introduces a specification-only feature. For fields it also has a special meaning, which is that the field can be represented by concrete fields. See section 2.2 Model and Ghost.

The modifiers model and ghost are mutually exclusive.

A model field may not be declared to be final. This is because model fields are abstractions of concrete fields, and thus it would complicate JML to allow final model fields. If you feel that you want a final model field, what you should use instead is a final ghost field. See section 6.2.6 Ghost.

Note that in an interface, a model field is implicitly declared to be static. Thus if you want an instance field, you should use the modifier instance, so that the field will act as if it were a member of all objects whose type is a subtype of that interface. Conversely, in a class, a model field is implicitly declared to be instance. Thus, if you want a static field, you should use the modifier static, so that the value of the model field is shared by all instances of the class and its subclasses.


6.2.6 Ghost

The ghost modifier introduces a specification-only field that is maintained by special set statements. See section 2.2 Model and Ghost.

The modifiers ghost and model are mutually exclusive.

A ghost field declared in an interface is not final by default. If you want a final ghost field in an interface, you must declare it to be final explicitly. Ghost fields in classes are also not final by default.

In an interface, a ghost field is implicitly declared to be static. Thus if you want an instance field, you should use the modifier instance, so that the field will act as if it were a member of all objects whose type is a subtype of that interface. Conversely, in a class, a ghost field is implicitly declared to be instance. Thus, if you want a static field, you should use the modifier static, so that the value of the ghost field is shared by all instances of the class and its subclasses.


6.2.7 Instance

The instance modifier says that a field is not static. See section 2.5 Instance vs. Static.


6.2.8 Helper

The helper modifier may be used on a private method or constructor to say that its specification is not augmented by invariants and history constraints that would otherwise be relevant. Normally, an invariant applies to all methods in a class or interface. However, an exception is made for methods and constructors declared with the helper modifier. See section 8.2 Invariants. [[[ Just on private? or just on non-overridable methods? or just on non-overridden methods? - DRC]]]


6.2.9 Monitored

The monitored modifier may be used on a non-model field declaration to say that a thread must hold the lock on the object that contains the field (i.e., the this object containing the field) before it may read or write the field [Leino-Nelson-Saxe00].


6.2.10 Uninitialized

The uninitialized modifier may be used on a field declaration to say that despite the initializer, the location declared is to be considered uninitialized. Thus, the field should be assigned in each path before it is read. [Leino-Nelson-Saxe00].


6.2.11 Math Modifiers

[[[Need explanation of these.]]]


6.2.12 Nullity Modifiers

Any declaration (other than that of a local variable) whose type is a reference type is implicitly declared non_null unless (explicitly or implicitly) declared nullable. Hence reference type declarations are assumed to be non-null by default (see section 2.8 Null is Not the Default).

A declaration can be explicitly declared nullable by annotating it with the nullable modifier. A declaration is implicitly declared nullable when the (outer most) class or interface containing the declaration is adorned by the class-level modifier nullable_by_default.

Attempting to use both the non_null and nullable modifiers is a compile time error.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Gary Leavens on March, 16 2009 using texi2html