The Forum for Discussion about The Third Manifesto and Related Matters

Please or Register to create posts and topics.

Java gets tuples

Quote from AntC on February 10, 2020, 1:41 pm
Quote from Dave Voorhis on February 9, 2020, 12:53 pm
Quote from AntC on February 9, 2020, 6:46 am
Quote from Dave Voorhis on February 7, 2020, 9:33 am
Quote from AntC on February 7, 2020, 6:22 am
Quote from Dave Voorhis on February 3, 2020, 10:51 am
Quote from AntC on February 3, 2020, 9:38 am
Quote from Dave Voorhis on February 2, 2020, 12:46 pm
Quote from AntC on February 2, 2020, 12:25 pm
Quote from Dave Voorhis on February 1, 2020, 12:05 pm

For those interested in Java development, see https://blogs.oracle.com/javamagazine/records-come-to-java

Notably, still nominal typing rather than structural, but this is unsurprising in the overall context of Java.

Java only has classes, which you use to create records and everything else. The new record is just a convenience for creating certain classes.

Java programmers are generally ok with classes.

the blog says

The java.lang.Record class cannot be directly extended, ...

I would have thought any data structure you might want to declare additional methods besides put/get -- for example, area() of the classic shapes or polar()  of a cartesian co-ord. (You can arbitrarily add methods for Haskell records, although it requires rather more code than for standard equal(), toString().)

You may not extend a record via inheritance. If you have a record Point and wish to define polar() for it, you'd be expected to define a class like PointOperations that either references a Point specified via the PointOperations constructor or (more likely) defines polar() as polar(Point p).

So PointOperations is a class containing only methods; whereas class Point contains only the record? This is to avoid 'bundling' methods with data? Except class Point includes methods to access the data/fields (and data without any means to access it would be useless). So what's the rationale for a separate PointOperations class?

...

The justification from the horse's mouth, so to speak, at https://openjdk.java.net/jeps/359 is:

Records are implicitly final, and cannot be abstract. These restrictions emphasize that the API of a record is defined solely by its state description, and cannot be enhanced later by another class or record.

"Implicitly final" means they can't be extended, but it looks like you may be able to define methods within the record definition which would allow the methods in (say) PointOperations to be defined inside Point.

But I'm not certain about this. When I get a moment, I'll download the Java 14 release candidate to try it.

Hmm, if the operation amounts to an alternative PossRep such as Polar() or even a read-only such as Area(), that's not interfering with the state description. Even if it's some operation that updates the visible state description, such as using Polar() as a shorthand to update Cartesian coords, I'm not seeing any harm. But I guess Java has no concept of extending a class with only methods vs bundling extra fields with methods(?)

No, in Java there is no means to allow extending a class with additional methods but disallow additional fields.

Thanks, and thank you to Erwin for more detail.

That might be a feature of other, more sophisticated Java-compatible JVM languages like Kotlin or Scala; I don't know.

I'm trying to reconcile what Java 14 provides vs the "horse's mouth" bit you quote about state description. I think Scala follows Haskell pretty closely on this point: it compiles to JVM, but its semantics are much closer to FP.

I don't see that extra methods has any effect on the state description. Erwin mentions inner classes, but again that would not have an effect if they included only methods(?)

Extra methods wouldn't have any effect on the state description, but there is no mechanism in Java to allow you to specify in a base class that derived classes may define methods but not fields. You can only either (a) disallow any and all derived classes from a base class; or (b) allow derived classes to declare methods and fields as they see fit.

Thus, to make sure derived classes can't declare fields, the Java definers prevent 'records' from having derived classes. There is an existing mechanism -- declaring a class as 'final' -- to support that.

Perhaps a future update will allow a base class to specify that derived classes may declare methods but not fields.

Given a record class's fields are declared 'final', there would be no means to update coordinates.

Ah, by "update" I meant 'update'. That is, a function that takes an existing Point instance and some delta to the Polar() values, and returns a new Point instance whose coords result from applying the deltas.

If 'record' classes allow method definitions, then that would be possible.

Nor is there multiple representations similar to Possreps. There is only one record structure, i.e., a specific set of fields.

In the past I've been dismissive of Multiple PossReps on the grounds no other language does that. And that would be true of Haskell 98 and the revised 2010 standard. But over the past decade, Haskell has grown features that come close to Multiple PossReps. Yet with a difference: the data decl is the one that gives 'the' Representation. Alternative Representations can be used for read and 'update', but need not be available for every possible value of 'the' Representation. They're aimed at representation-hiding and applying constraints beyond type-constraints.

The features are recent-ish, but the ideas are not (Wadler, again, mid-1990's; the delay was in figuring out how to integrate them into the type system). I'd have thought Java would want representation-hiding(?)

Multiple possreps are certainly possible in Java, and in most if not all object oriented languages. But as is typical with object oriented languages, it's up to the developer to manufacture them out of class and instance raw materials. A typical pattern would be to declare a base class (or interface) that defines methods common to all representations, and define a set of classes -- each with a different representation -- inherited from the base class. E.g., a Point base class, with Cartesian and Polar derived classes.

Quote from AntC on February 9, 2020, 7:15 am
Quote from Dave Voorhis on February 7, 2020, 9:33 am
Quote from AntC on February 7, 2020, 6:22 am
Quote from Dave Voorhis on February 3, 2020, 10:51 am
Quote from AntC on February 3, 2020, 9:38 am
Quote from Dave Voorhis on February 2, 2020, 12:46 pm
Quote from AntC on February 2, 2020, 12:25 pm
Quote from Dave Voorhis on February 1, 2020, 12:05 pm

For those interested in Java development, see https://blogs.oracle.com/javamagazine/records-come-to-java

Notably, still nominal typing rather than structural, but this is unsurprising in the overall context of Java.

Java only has classes, which you use to create records and everything else. The new record is just a convenience for creating certain classes.

...where a Java record is notionally isomorphic to Haskell's data types.

I think not. Haskell has a layering of declarations; and you can define datatypes without record-alike access; and your functions/methods can work fine with positional access. Then opting to include field names in your datatype decl amounts to defining a shorthand to the positional access.

I meant only that the new Java record feature seem to be similar to Haskell's data types -- like tuple types in general, in various languages.

Hmm. hmm. Tuple types in general do not have named access, only positional. Haskell's name-accessed data types are not Haskell "tuples". I think the differences are the sort of detail the devil inhabits. It looks like Java 14 records do not support positional access; whereas Haskell name-accessed data types must support positional access.

No, Java favours named constructs over positional access. Accessing the nth element of a record would be considered strange in Java, though if necessary it could be achieved via reflection.

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org

Hmm. hmm. Tuple types in general do not have named access, only positional.

Then you're distinguishing tuples from records (as you should).

No, Java favours named constructs over positional access. Accessing the nth element of a record would be considered strange in Java, though if necessary it could be achieved via reflection.

Those are records, not tuples, and should not be accessed positionally. C# specifically prohibits this, even via reflection. C# has things it calls tuples, but they're just classes (records), like Java.

 

Andl - A New Database Language - andl.org
Quote from Dave Voorhis on February 10, 2020, 2:44 pm

No, Java favours named constructs over positional access. Accessing the nth element of a record would be considered strange in Java, though if necessary it could be achieved via reflection.

Especially in the older versions of JDBC, a great lot of methods (e.g. obtaining column metadata) were only available using ordinal position as the attribute identifier.  So despite the 'J' in the name, that made the look & feel quite un-java-ish.  (Granted that it was quite inevitable given SQL's nature of names-not-mandatory, but it always felt like an extreme kludge.)

Quote from dandl on February 10, 2020, 11:34 pm

Hmm. hmm. Tuple types in general do not have named access, only positional.

Then you're distinguishing tuples from records (as you should).

No, Java favours named constructs over positional access. Accessing the nth element of a record would be considered strange in Java, though if necessary it could be achieved via reflection.

Those are records, not tuples, and should not be accessed positionally. C# specifically prohibits this, even via reflection. C# has things it calls tuples, but they're just classes (records), like Java.

 

(Apologies for waking up this thread after a long delay.)

The Java 14 write-up doesn't actually give an example of creating a record value; do I assume it's the same as this example for a 'Classic' class?

var order = new FXOrderClassic(1, 
                    CurrencyPair.GBPUSD, 
                    Side.Bid, 1.25, 
                    LocalDateTime.now(), 1000);

Then what I see is this is -- exactly -- positional. Presumably if I permute the sequence of those elements inside the parens, I'll get a different valued order(or more likely a type mis-match). If Java 14 records are genuinely name-access-only, I'd expect something more like

var order = new FXOrderRec(units = 1, 
                    pair = CurrencyPair.GBPUSD, 
                    side = Side.Bid, price = 1.25, 
                    sentAt = LocalDateTime.now(), ttl = 1000);

in which I could permute the sequence of the label-value pairs. (Perhaps the syntax should use braces { , , } rather than parens and/or := rather than =, or even just write the label adjacent to the value. That would look suspiciously like TTM/Tutorial D TUPLE{ }.)

With the type mis-match I can't help feel Java 14 (and Haskell) are missing a trick: although units, price, ttl are numeric (and might all be represented by the same PhysRep), they're not comparable [**] in the sense of RM Pre 8. If I squint a bit, I can see units = 1being a cast from the type of the numeric literal 1 to type units. Then a record value is denoted by a commalist-inside-brackets in which each element is of a distinct type.

[**] By "not comparable" I mean it doesn't make sense to compare (values representing) money to time. So I'm using RM Pre 8 to augment RM Pre 1's named-set-of-values, as a criterion for same-typeness.

Quote from AntC on February 21, 2020, 8:00 am
Quote from dandl on February 10, 2020, 11:34 pm

Hmm. hmm. Tuple types in general do not have named access, only positional.

Then you're distinguishing tuples from records (as you should).

No, Java favours named constructs over positional access. Accessing the nth element of a record would be considered strange in Java, though if necessary it could be achieved via reflection.

Those are records, not tuples, and should not be accessed positionally. C# specifically prohibits this, even via reflection. C# has things it calls tuples, but they're just classes (records), like Java.

(Apologies for waking up this thread after a long delay.)

The Java 14 write-up doesn't actually give an example of creating a record value; do I assume it's the same as this example for a 'Classic' class?

var order = new FXOrderClassic(1, 
                    CurrencyPair.GBPUSD, 
                    Side.Bid, 1.25, 
                    LocalDateTime.now(), 1000);

Then what I see is this is -- exactly -- positional. Presumably if I permute the sequence of those elements inside the parens, I'll get a different valued order(or more likely a type mis-match).

Yes. It's the usual C/C#/Java/etc. positional function/method/constructor invocation, but the resulting structure has no (easy) positional access.

I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org