JDK-4820062 : Provide "struct" syntax in the Java language
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 1.4.1,5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2003-02-18
  • Updated: 2011-10-31
  • Resolved: 2011-10-31
Related Reports
Duplicate :  
Relates :  
Description
Name: rmT116609			Date: 02/18/2003


DESCRIPTION OF THE PROBLEM :
The Java language lacks "structs".

The lack of structs gives rise to serious code complexity
when dealing with external systems, and serious performance
implications for code that performs a large amount of I/O
with external systems.

Because of the way Java and Objects are intertwined it would
probably not be entirely practical to insist on the same
struct semantics that are found in C. In particular the lack
of pointers and pass-by-value semantics for a trivial
implementation of structs makes an apples-to-apples theft
from the C language impossible.

However, as the particular problem I am trying to crack is
dealing with high-performance I/O operations (in fact,
OpenGL graphics rendering in this case), I believe there is
an elegant solution based on NIO buffers which should
provide wonderful syntax, high performance, and 100% robust
operation with minimal impact.

The solution I propose is to associate a "struct" with a
Buffer. The buffer's primitive type then becomes the struct,
i.e a position(n) command on the buffer moves the buffer to
access the nth struct in a buffer of these structs.

A struct should syntactically accessed the same as a normal
object, ie. passed by reference, and so on. Struct field
assignments and reads take place directly to and from memory
with no intermediate copy.

A struct should be defined in Java using simple C-like
syntax, and generate a .class file like any other Java class
construct. The difference is that the fields may only be
primitive Java types or themselves structs. Each field is
not stored in an instance of the object itself; instead they
are mapped to offsets in memory from a Buffer. A struct
therefore must have a reference to its parent Buffer to
prevent the buffer from being garbage collected and structs
being allowed to access unmanaged memory.

public struct Vertex {
private float x, y, z, nx, ny, nz;
private byte r, g, b, a;

void normalize() {
//etc
}

};

A struct descends from the class javax.nio.Struct, which has
a package-visible constructor which takes the parent
StructBuffer as a parameter:

public abstract class Struct {

private final Buffer buffer;
private final int position;

Struct(Buffer buffer) {
this.buffer = buffer;
}

}

The usage of the new "struct" keyword, which is
syntactically similar to "class" and "interface", instructs
the runtime not to reserve space for the structs' fields
because they will instead be referenced directly from a
buffer at the specified position.

Then a buffer of this struct should be initialized, perhaps
using the new generics feature to simplify the syntax:

// Allocates a struct buffer with 10 structs in it at the
specified address, which can be a long
StructBuffer<Vertex> buf = new StructBuffer<Vertex>(10,
address);

// or from a ByteBuffer, which will check that the
bytebuffer's capacity is an exact multiple of the struct's size
StructBuffer<Vertex> buf = new StructBuffer(byteBuf);

Then values from the buffer can be referenced directly as
Vertexes:

Vertex v0 = buf.get(0);
v0.normalize();
Vertex v1 = buf.get(1, v1); // Constructs v1 if necessary

The underlying implementation in Java should be identical in
speed to C for the common case (with bounds check
elimination and native byte ordering), yet because a struct
can only be constructed by an existing StructBuffer, it will
have all the safety of bounds-checking and garbage
collection which will prevent illegal writes to memory.

The two problems solved by this RFE would be the sheer
complexity of maintaining multiple buffers to access
different parts of a struct with different primitive types;
and the massive increase in performance afforded by being
able to reference memory directly and bracket accesses to
members of a struct with one bounds check.

You will understand if you do graphics programming; it is a
key requirement of games programmers to have greatly
simplified and efficient access to these operations or the
benefits of C++ simply outweigh the extra complexity and
overhead inherent in Java.

(Review ID: 181371) 
======================================================================

Comments
EVALUATION Proposals for new features in the Java programming language are no longer being accepted or maintained in the bug database at http://bugs.sun.com/. This also applies to proposals for new features in the Java Virtual Machine (that is, in the abstract JVM, as opposed to a JVM implementation like HotSpot). All proposals for new features should be made through the "JDK Enhancement - Proposal & Roadmap Process" described at http://openjdk.java.net/jeps/1. Consequently, this specific request to change the Java programming language will not be considered further. The bug database continues to accept and maintain submissions about technical errors in the design and specification of the Java programming language and the Java Virtual Machine.
31-10-2011

EVALUATION Apparently, my previous evaluation could be misunderstood. I was responding to this SDN comment: "I'm for structs. Classes are way too expensive to create in many situations, and are sometimes semantically invalid in various contexts." So just to be clear: * We are considering addressing the requirement of accessing low-level data structures in Java. * We are not considering adding C-like structs to Java at this time. * If you're interested in C-like structs, vote for other bugs. (But don't get your hopes up). * If you don't think the @Struct proposal will solve your problem, please let us know. A precondition for the @Struct proposal is support from NIO, for example, as Cas suggests, "memory mapped objects as a sliding window over ByteBuffers".
22-02-2006

EVALUATION Responding to SDN comments: We are considering this RFE as a request to access low-level/native data structures as can be done with C structs (and C++ classes). If you're looking for stack allocated objects or value types, you should vote for RFE 4213096 or RFE 4809540. Clearly performance will be paramount to the success of any solution (library based or language syntax) but claiming that it can't be done with classes is unfounded. Modern JVMs, such as HotSpot, are very good at optimizing Java byte code. The only real difference between a class and a C struct is who generates the code for accessing members. Consider a C struct like this: struct Foo { int a; int b; } Foo; If you have an array of Foo, foos, then a C compiler can compile an expression like: foos[6].b to i386 machine code like: movl foos, %edx movl 52(%edx), %eax where 52 = 6*sizeof(Foo)+sizeof(int) You can accomplish something similar in Java: static int SIZEOF_FOO = 2; static int SIZEOF_INT = 1; int getFoo_b(IntBuffer foos, int index) { return foos.get(index*SIZEOF_FOO+SIZEOF_INT); } The expression similar to foos[6].b would be: getFoo_b(foos, 6) HotSpot can inline this: foos.get(6*SIZEOF_FOO+SIZEOF_INT) which can be further optimized: foos.get(13) This then all boils down to how efficiently HotSpot can handle IntBuffer.get. However, as always, C has a performance advantage over Java: no range checks. This means that the best we can hope for in Java is something like this: cmpl $56, size jbe .OUT_OF_BOUNDS_FAILED movl foos, %edx movl 52(%edx), %eax If the Java platform can't handle foos.get(13) efficiently, then you will get bad performance no matter what solution you dream up. I don't see how saying "structs" solves this problem. The really tedious part of accessing low-level data structures is writing methods like getFoo_b and constants like SIZEOF_FOO. This can be automated. The proposal with @Struct is to have an annotation processor generate such methods and constants based on a higher abstraction. So do us a favor and let us know what is wrong with the performance of the java.nio buffers if it doesn't meet your needs. That is a realistic way of solving your problems. Asking for C structs is not.
17-02-2006

EVALUATION Response to SDN comment from Cas: you're right about the category. I have moved this RFE to java.nio.
14-02-2006

EVALUATION We are currently considering if this should be addressed in Dolphin. A combination of library methods and annotation processors should make it possible to write something like this: @Struct interface CK_SLOT_INFO { @PaddedString(' ', "utf8", 64) String getSlotDescription(); @PaddedString(' ', "utf8", 32) String getManufacturerID(); @Unsigned(32) int getFlags(); CK_VERSION getHardwareVersion(); CK_VERSION getFirmwareVersion(); } (Using an example from PKCS#11)
10-02-2006

EVALUATION There are some interesting ideas in this proposal, however, we do not see the need for a new language feature. We believe this can be solved as a library without changes to the language and VM. As a consequence, we have moved this RFE from specification to java.util. We are currently investigating various solutions and if it should be part of the JDK. In any event, it will not be in time for Mustang. More details will follow.
29-09-2005