-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Having spent some time thinking about this (see #1 and #2), my conclusion is that we need a mapping to Java which produces something as close to "normal" Java as possible. My proposed mapping is thus:
- Primitives.
boolas JVMboolean.byteas JVMbyte.u8andi8as JVMbyte. Foru8, this requires jiggery pokery using& 0xFFin places.u16as JVMchar,i16as JVMshort. This works since JVMcharis unsigned 16-bit.u32as JVMlong,i32as JVMint. Potentially could try to map u32 to JVMintwith jiggery pokery.u64unmapped,i64as JVMlong. Here,u64is just treated asint.intmapped to JVMBigInteger.
- Arrays.
T[]mapped to JVM arrayT[]. This works, though requires external method for array generators[v;n]. - Records mapped to JVM classes of same name. These classes are implemented as structs, but include obvious methods:
equals(),hashCode(),clone(). - Unions, Intersections and Negations mapped to
Object. An interesting question is whether or not we want tags of some kind. Also, a union of the formT|nullcan be mapped to reference type forT(e.g.i32|nullmaps toInteger). - References.
- Function / Methods.
This is a pretty decent mapping in general, and should make interoperation with Java relatively easy. In particular, mapping records to Java classes means that external code can create and use them. However, there remain a number of questions:
- Representation. The used of specific representations (particularly for integer primitives) means that appropriate casts must be introduced. The following example illustrates:
u16 x = 1 u32 y = x // need to cast here. u32 z = x+y
In addition, there are complications arising from the typing of arithmetic. For example, inx+yabove, the calculated return type will beint. We need to back propagate fromzto determine the appropriate type for the expression and its arguments. - Anonymous Records. For example, the following is difficult to translate efficiently as its unclear what type to construct for
{x: 1, y:2}?Point p = {x: 1, y: 2}We can resolve this in two ways. Firstly, anonymous records can be represented using e.g.HashMap<String,Object>, or a type from the Whiley Runtime. Secondly, we can use type inference to back propagate the typePointinto the expression{x: 1, y: 2}. This does get tricky though, as it's not always clear what the right type is. For example,null|Point p = {x: 1, y: 2}, well we need to figure out the intended type to construct isPoint. Another possibility here would be to introduced named record construction, to allowPoint p = Point{x: 1, y: 2}. This syntax is similar to Rust, and I don't believe it would cause any ambiguity in the grammar. - Ownership. Here, we will avoid reference counting. The reason being simply that we cannot retro-fit reference counting onto Java array types. Therefore, a live variables analysis will be used to determine when a variable must be copied, versus when it must be moved. For copying of non-primitive types, we employ
clone(). However, care must be taken to minimise this as much as possible. For example, in the expressionx == y, we do not need to clone eitherxory(even if they are still live). This is somehow similar to Rust's notion of "reference lvals". - Runtime Type Tests. The current JVM backend uses the Whiley runtime to handle runtime type tests. Specifically, traversing their structure to exhaustively determine what they are. This is not exactly idea. An alternative solution would be to translate union types using a specialised
Unionobject which contains the necessary type tag. This makes the FFI harder though, since the user needs to then manually specify tags. - Whiley Runtime. A small runtime library is almost certainly required here. In particular, for implementing array generators, and also presumably for runtime type tests.
Metadata
Metadata
Assignees
Labels
No labels