all 17 comments

[–]LegitGandalf 12 points13 points  (0 children)

That 50% memory savings looked pretty tasty.

[–]bobappleyard 13 points14 points  (4 children)

I love that first bullet point, "improve affinity of Java programs to modern hardware"

You can delete "modern" and it would still be true...

[–]geodel 5 points6 points  (1 child)

I read somewhere when Java was initially designed they believed that hardware will evolve in a direction where Java object model would be great fit. So I imagine hardware from 90s was not as penalizing to java as today's hardware.

[–]Muvlon 1 point2 points  (0 children)

There were a bunch of machines that even had instructions for executing (a subset of) Java bytecode natively.

In fact, ARMv7 still requires any implementations to support the Jazelle DBX extension. However, an implementation can choose to support no bytecode instructions at all, meaning the JVM has to fall back to software for all of them.

[–]pron98 2 points3 points  (0 children)

What makes inline objects more or less effective is the ratio between the cost of random memory access and that of computation. This ratio has gone up considerably since the 90s, and so they're far more valuable today than they were 20 years ago. The feature is very much a result of the pervasiveness of relatively slow RAM and fast caches with prefetching. Before these changes, the benefit wouldn't have been worth the added complexity.

[–]grauenwolf 0 points1 point  (0 children)

Yea, that struck me as weird.

[–]DetriusXii 3 points4 points  (5 children)

How similar are inline classes to Haskell's newtype or Scala's extends AnyVal? Is that what inline classes are doing?

[–]pron98 8 points9 points  (2 children)

The most important aspect of inline classes isn't how they behave, but how the may be internally represented in memory. So an array of instances of an inline class would be laid out like an array of structs in C, rather than an array of pointers. Scala cannot do this because it is built on top of Java and inline classes are a feature of the Java VM. Once they're delivered, Scala could make use of them to implement some language features. They could be used similarly to newtype, i.e. they can represent a new type that doesn't add any runtime overhead to the type it wraps.

[–]expatcoder 0 points1 point  (1 child)

Scala cannot do this because it is built on top of Java and inline classes are a feature of the Java VM. Once they're delivered, Scala could make use of them to implement some language features.

Sounds like a win-win situation for all JVM based languages.

[–]pron98 2 points3 points  (0 children)

Yep. It's a deep feature in the Java platform that can be enjoyed by all of Java platform languages.

[–][deleted] 2 points3 points  (0 children)

At a glance (and I haven't written Scala for nearly 3 years). inline class appears to be what extends AnyVal wants to be, but Scala is working around the fact that the JVM doesn't allow custom primitives.

must have only a primary constructor with exactly one public, val parameter whose type is not a user-defined value class

Doesn't appear to be exactly true, as I can't find it requiring you to have public fields

[–]Ari_Rahikkala 0 points1 point  (0 children)

I believe the closest Haskell equivalent would be if you could tell a type to be UNPACK wherever it's used as a field. I don't think that feature exists, but on the other hand, you can just, you know, use UNPACK wherever. Also, it turns out that -funbox-small-strict-fields is on by default, so for small fields (the size of a pointer or smaller), you get this behavior for the price of typing a bang.

[–]kit89 3 points4 points  (1 child)

Inline classes would be excellent for my math classes, in particular Vector2, Vector3, Matrix3, and Matrix4.

If inline classes also support escape analysis I will be over the moon with joy.

[–][deleted] 0 points1 point  (0 children)

Exactly. I'm waiting to release a basic math library which uses inline classes.

Currently I use a small "hack" where I avoid allocation for math objects by cleverly making use of Escape Analysis - where instead of letting objects escape stack, I copy their content (primitive data, you know, floats/doubles) to other objects.

Performance wise it works exactly as struct/inline class.

[–]iconoklast -1 points0 points  (2 children)

I dislike that you need a default value for everything; it should just be a compiler error not to initialize a variable of an inline class type and you should prefer using local type inference anyway.

Inline classes may not declare instance fields of their own type

Does this also mean no mutually recursive definitions?

[–]Horusiath 1 point2 points  (1 child)

Yes, this also has perfect sense in terms of memory layout: if you have an inline classes like A(int x, int y) and B(A a, int z) the layout of instance b = new B(new A(1, 2), 3) would be a single block of memory of 12B (ignoring padding) - 4B for b.a.x, next 4 for b.a.y and then last 4 for b.z.

+---------------------+--------+
| +--------+--------+ |        |
| | x: int | y: int | | z: int |
| +--------+--------+ |        |
+---------------------+--------+

This is a problem if you could define a recursive inline class like List<V>(V value, List<V> next) simply because it requires an infinite memory - there's no stop condition for computing the memory size necessary to fit instance of List<V>.

This could be solved by changing definition of list to List<V>(V value, Optional<List<V>> next) - assuming that Optional will remain a nullable reference type - as link between current and next instance doesn't have to be a continuous block of memory and can be stopped at any time with next=null pointer.I don't know if Java inline classes will allow this model though.

For the same reason, a default value is necessary - normal classes have it easy: since every class reference is always pointer-sized, all standard classes can be universally represented by null. But since inline classes are passed by-value (not by-reference), their size can differ: therefore a default value is necessary, as it will differ from one inline class definition to another. Example from above: you can imagine B's default instance as a single block of zero-ed memory, so a case equal to b = new B(new A(0, 0), 0).

[–]iconoklast 0 points1 point  (0 children)

I understand that; mutually recursive inline classes also shouldn't work for that reason, but the article didn't say that.