Study of Java
Our reference here is the Java Language Specification, 3rd Edition. Part of the goal of this lecture is for you to gain expertise in "spec reading". Some of the examples below are taken from the Java spec.
- In lecture we covered three languages which reflect the key principles of Java: FbOB, STFb, and PEFb.
- The former had objects but was untyped, the next added subtyping and the last added polymorphism.
- The language corresponding to Java is "PSTFbOB", basically putting polymorphic types and subtypes on to FbOB.
- We did not explcitly study that combination because there is not a lot of new stuff there -- subtyping on objects is like subtyping on records.
Classes and Inheritance
We either have or can easily encode in STFbOB nearly all of the features of basic Java class declarations and inheritance.- Information hiding is possible in Java via private/protected fields; information hiding in FbOB is discussed in the book but we did not cover it (basically make a separate "public view" record).
- Static fields can be encoded and were covered briefly in class and in the book.
- Java classes can have multiple constructors, we did not cover that case (but it is possible by encoding constructors as static methods in our static method encoding)
Java Public/Private/package protected/Protected and Caml Modules
- Caml allows arbitrary multiple views of the same module (different things seen by different code given the same module)
- Java has fixed forms of multiple view: subclasses may see more (protected) and within vs without a package may see more (package protected)
- Caml is more flexible, but Java approach is simpler (on the surface at least).
Constructors
- Java constructors are not that different from the encoding of constructors that we covered in the book - various convenient sugar is added.
- Java by default inserts
super();in front of the constructor if another constructor is not invoked at the start; this is a bit of a hack. - There is a default constructor w/ body
super();if none is declared. - Inner classs and generics add a whole load of complications to constructors.
Subtyping
- Subtype relationships must be declared via extends/implements, except for primitive type subtyping; even though a class clearly implements all the methods of an interface if that is not specified in the header there is no subtyping possible.
- In STFb subtyping only depended on the structure of the underlying records. STFb subtyping is thus purely structural and Java's is not.
- Used to be there was no "deep" subtyping on objects, but now
you can also refine the type in a subclass - see here.
- former is our record subtyping rule where type components must be SAME; now they support some aspects of our rule. - Summary: STFb is more expressive but Java's is easier to use due to names being given.
Inner Classes
Lets start with reviewing what FbOB had in this area:- In FbOB we had the ability to declare classes
anywhere, including inside other class methods, etc. Those
classes could also be returned as result values of methods, to
be
new-ed in a completely different context. - FbOB also has syntax for directly defining
objects:
Object Inst ... Meth ... - In general, this is an example of fully higher-order classes and objects -- no restrictions on where they can be defined, used or passed to.
- They do allow local classes to be defined just about anywhere.
- They do support something similar to the
Objectsyntax of FbOB, via anonymous local classes which are immediatelynew-ed. - They do support multiple levels of nesting: inner classes can have inner classes inside them.
- At runtime, each inner class instance holds a pointer to the instance of the class nesting it that created it; it can access fields of that class via that reference (see spec linked above for examples).
- The main lack is the ability for classes to be passed around as data items, e.g. methods returning classes.
- The JVM is not "aware" of inner classes, they are implemented
as regular classes with mangled names like
Foo$1Boofor an inner classBooinsideBoo.
- FbOB objects with just one method called
e.g.
theFunctionare a full and faithful encoding of higher-order functions. - Smalltalk takes the view of rather than having first-class objects just add higher-order functions directly; they are called blocks in Smalltalk.
- Project Lambda is a proposal to add full higher-order functions to JDK 8, and that addition is looking likely at this point.
- A closure is just a higher-order function return value
- The term "closure" comes from how they are implemented -- all variables not local to the function must be remembered
- (We didn't have this problem in our interpreters because we substituted when we did function application, but that is not very efficient)
- Caml example:
let x = 5 in let f y = x + y in (* f is at runtime a closure: a pair (f's-code, {x |-> 5}) *) let x = 22 in f 2 (* prints 7 because x was 5 in f's closure *)
Generics
(other links: their use in classes; an overview)Generics are Java's version of parametric types. These notes assume familiarity with them; read a tutorial if you are not.
The PEFb language includes both type inference and polymorphism so it is the only language we studied with polymorphism. The main idea of how generic types are handled are expressed there, but in an inference context.
Here are some comparisons with the PEFb or Caml-style parametric types that we studied:
- Caml infers generic types
'aautomatically; in Java, you must declare them as<T>. - Java generics have some features not found in Caml due to the combination of polymorphism and subtyping.
Bounded subtyping
- Recall with generics you cannot have
List<String> <: List<Object>kinds of things (see here for description) even thoughString <:Objectholds. - The root of this in subtpying theory is that
String/Objectmay occur both positively and negatively inList's signature, so it needs to be invariant. - In STFb the problem comes up in how subtyping
is defined contravariantly on function types. A list type
would at least include
addandheadso the subtyping needed for the above would be at least{ add: String -> {}; head : {} -> String } <: { add: Object -> {}; head : {} -> Object }and this relation fails because it also requiresObject <: Stringdue to theaddparameter argument contravariance. - In STFb we could in fact have such subtypings
holding for the case they were positive only -- imagine some
list which you could only get the head of, nothing else:
{ head : {} -> String } <: { head : {} -> Object }would be a legal subtyping in our STFb rules assumingString <: Object. - Java is
basically assuming that
Listwill haveTboth as argument and return type of methods and so always forces invariance here. But, for the case the list class was immutable and T was never an argument the above subtyping would hold and our STFb approach would support that.
- In generics you can write things like
<T extends C & I> void test(T t) - the "
extends C & I" meansTcan be any type which extends both classCand interfaceI. - In other words,
T <: CandT <: Iin our subtyping terminology. - This adds more flexibility,
Tneed not be any type, but from a restricted range of types which gives added flexibility later. - The constraint-based
CFbR (which we may not have covered) with let-polymorphism also allows such
sorts of types to be expressed:
test : 'a -> void \ { 'a <: C, 'a <: I } - Java also allows type variable wildcards,
?- this is a form of existential type -- the typing holds for some?.
Method Overloading
The take-home message here is brief:- Java method overloading can be viewed as concatenating all of the argument types onto the method name.
- So it is really just a form of syntactic sugar.
- We will briefly look at the examples in the above spec.
Immutable Data
One of the key lessons of Caml is the importance of known immutable data: it has universal meaning.
- Java allows fields to not mutate if qualified with
final. - Caml analogy: a
let-defined variable. - Like Caml, immutability is only shallow - the field could contain components that mutate.
- Unlike Caml the default case is swapped and this has a huge impact on expected programmer behavior.
Concurrency
The book chapter on concurrency reviews the Java concurrency model.Other issues of comparison between Java and Caml / Fb family of languages
- Java variant types analogue?
-- used to not exist but now there are enums at least; "use subtyping and dynamic dispatch instead" - Type Inference -- types are declared in Java; avoids all the glitches in the OCaml design to support inference but requires more programmer typing.
- Java Exceptions -- very similar to how we did them in TFbX but no
throwsdeclarations in our types.
Some advanced dimensions of Java we did not really study at all
- Reflection
- Dynamic class loading
- JNI - interfacing with native code