Creating a high level Pointer API
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Jan 13 11:50:04 UTC 2020
On 12/01/2020 23:00, Ty Young wrote:
> Apologies for the wording used. In hindsight it was a bit much.
>
>
> On 1/10/20 6:36 PM, Maurizio Cimadamore wrote:
>> Can we please agree to disagree?
>
>
> IMO, this is more than just people having different opinions - there
> are negative repercussions for going this route.
I understand you are concerned, but at some point there has to be a
realization that the time we spend developing new features and the time
we spend arguing via emails all come from the same "time bucket" - so...
the less we argue, the less time we have available to actually work on
the features, and give you something you can actually try. Every email
has a *cost* - the question is - have we reached a point in the
discussion where the *cost* is not worth *paying*? It seems to me that
we have, as there's nothing can say to make you change your mind, or
let you see the angle we're coming from.
>
>
>> I've shown in the document how the fragmentation you are afraid of is
>> already the status quo, by linking at least 3 different pointer
>> implementation, with radically different properties, both at in terms
>> of the type system choices and in terms of how they are implemented.
>> Some of these libraries even have different pointer classes to denote
>> different state - e.g. pointer with size vs. unchecked pointer. I'm
>> under no illusion that "one pointer will rule them all".
>
>
> I'm a bit confused here. Java has an array of features to handle
> everything you just mentioned. Fields that might not exist? Optional.
> Entirely different interpretations of the same thing? Interface
> implementations(with abstract classes to get rid of common stuff). The
> JDK already has interfaces with half a dozen or more implementations.
> It isn't new territory.
Yes, we have all these features. This is true. That said, I'm sure that
developers will have, for each and everyone of the aspects you mention 5
or more different way to solve the same problem. How do we chose,
especially when it seems like there's no obvious winner? The
Pointer/Array/Callback API is an useful lesson, in hindsight. That API
is full of choices like that (because when you try to compress down C
into Java you have to make a lot of choices). And yet, almost every
single person who reported feedback in here was not 100% satisfied with
this or that particular aspect of the API. For instance: should pointer
be generics? Well, yes, right, as in C you have int* and char* - but
that's a surface as in C you can cast everything into everything else -
with Java generics you can't. So we had to add a manual cast method.
More 'raw' APIs would not suffer from this problem. As everything else
when it comes to model C in Java, it's a matter of trade-offs, and I'm
super-uncomfortable in setting a bunch of trade-offs in stone (e.g. by
making them available as blessed JDK APIs), when I know full well that
these trade-offs will work well in certain cases, and will work much
worse in other cases.
>
>
>>
>> My definition of higher level API is, to put it more clearly, an API
>> which captures some of the properties of a pointer in the type
>> system, perhaps through generics (e.g. Pointer<Integer>). And, some
>> sprinkle of accessor methods, so that users of the higher-level API
>> need not to worry about constructing VarHandle accessors. So, to me
>> something like roughly like this:
>>
>> class Pointer<X> {
>> MemoryAddress _addr;
>> VarHandle handle;
>>
>> Pointer(MemoryAddress addr, MemoryLayout layout) { ... init var
>> handle ... }
>>
>> X get() { return handle.get() }
>>
>> void set(X x) { return handle.set(x); }
>>
>> ...
>>
>> }
>>
>> Would constitute a possible sketch for an higher-level API.
>
>
> Right, and people are going to write that near exact code over and
> over again.
Maybe they will, maybe they won't. I'm still surprised on how you can
jump to this conclusion w/o having even tried the minimal jextract
(which is not yet available). Maybe it will be as bad as you say - or
maybe, after some necessary adjustment, developers are going to say...
well this is just... fine?
Again, please have a look at the libclang port which forms the backbone
of the recently pushed jextract API - can you spot something in which
the absence of pointer is sorely missed? Of course this is just _one_
library (although I also tried OpenGL and came up with similar conclusions).
Last point: if an abstraction such as the one above is really helpful,
there is nothing stopping us from having jextract generating it as part
of its translation strategy. That is, instead of having a 'blessed'
pointer class in the JDK, you will get a pointer class with the set of
generated files. This might seem like a small difference to you, but it
is actually a very important one - as by going down that path we will be
able to co-update jextract and the set of supporting classes it relies
upon w/o touching the JDK. If we put an API such as pointer in the JDK,
then the API becomes automatically bound by the usual JDK compatibility
constraints. Let's say that Valhalla delivers and we get value types
(first) and specialized generics (later) - can we update Pointer to take
advantage of it? Maybe, but maybe not - as making such changes will
almost surely have some source compatibility restriction (e.g. making
Pointer an inline class will mean you can no longer assign 'null' to
it). But is Pointer is co-generated when you extract a library, the
dependency remains within your extraction bubble. You want to update
your bindings to work with a better Pointer class? Just re-extract
everything with a newer JDK, and that's it.
So, I think that, by _not_ putting classes like Pointer/Struct in the
JDK, we actually have _more freedom_ to add them as extraction artifact
and update them/improve them at will.
>
>
>>
>> But we're getting ahead of ourselves - the way we will proceed will
>> be to (1) roll out the minimal extract (2) use it to rewrite the
>> existing foreign examples (3) assess its usability, and add some
>> usability boosts where needed. Here, it seems to me we're jumping to
>> discuss (3), without having even tried the thing in the first place.
>> So, I'd prefer to hold off this discussion, at least until we can
>> make it more concrete as I feel it's going in circles.
>
>
> As someone who has toyed with both the old jextract generated bindings
> and the new Memory Access API, i'm not entirely sure what "usability"
> tweaks could be done. MemoryAccess objects would, AFAIK, act very much
> the same as Pointer but just without getter/setters for the data in
> the segment. Var handle just seems like boilerplate for the most basic
> of usage.
>
>
> There are a number of API changes I would personally make like having
> ValueLayout contain everything that returns a ValueLayout(the same for
> SequenceLayout and GroupLayout interfaces).
Not getting this proposal. Can you rephrase?
> I'm doing a lot of class cycling to find what I need because it's
> scattered. More to-the-point documentation(as was brought up earlier)
> is always good too. I'm currently stuck trying to get multi-dimension
> arrays working and the MemoryAddress to the Array changes once put
> into memory gets modified with limit = 0. Presumably I need to rebase
> it or something, but it isn't working nor am I seeing anything saying
> such.
Again, please provide code and we'll see what problem you are hitting
and what documentation improvement can be applied.
>
>
>>
>> As for memory segment not exposing layouts, that's by design - memory
>> layouts are optional - you can use them, or not, depending on your
>> need. A segment doesn't carry around the layout it was used for its
>> creation, also because there might not be one in the first place
>> (e.g. MemorySegment.allocateNative(100)).
>
>
> Aren't the layouts just predefined byte sizes? Either way, again,
> Optional exists.
>
>
>> Also, when slicing and dicing a segment, it would be hard, if not
>> impossible, to keep the layout information up to date (what happens
>> if you slice in the middle of, say a 4 byte ValueLayout?).
>
>
> If the slice is completely invalid then an unchecked exception should
> be thrown(and there are exceptions, I've gotten a few). If it's valid
> then presumably you have the necessary information, otherwise it
> wouldn't be possible to begin with, right?
The idea of carrying layouts around inside segments has been considered
for a brief moment at the inception of the memory access API - then
discarded. As I said, it is way too complex to track down dependencies
between the operations you might want to do on a segment and the
underlying layout. For instance, if you have a memory segment with a
certain layout L, and you try to dereference using a certain path
expression, you might want to expect the runtime to check that the
selected layout (by the path expression) is compatible with the layout
L. This is an expensive operation which would be applied _on every
access_ thus slowing things down in critical paths.
For this (and other reasons) we arrived at the current API stacking:
memory segment and addresses are byte-oriented and layout agnostic.
Layouts are an optional cherry on top which can help you deriving all
the useful info (size, alignment, var handle) from a centralized place
_if you want to_.
Maurizio
>
>
>>
>> Maurizio
>>
>>
More information about the panama-dev
mailing list