Hi all,
Value classes are a good fit for small numeric-like types such as
Int16 or Half. One place they still differ from primitives is
construction: a primitive or wrapper can be written as a literal,
but a user-defined value class requires an explicit constructor call:
Int16 a = new Int16((short) 13);
I read the 2020 thread "Typed variants of primitives" (Stephen
Colebourne / John Rose):
https://mail.openjdk.org/archives/list/[email protected]/thread/I77UXUZ4VQWMWPK3QSSEDWJJS7RJAVCZ/#X4F6C3BG3MD3656Y5WPLENKWPKH3RMGK
There, conversions between user-defined primitive-like types and
int were discussed as reasonable in principle, but requiring
carefully balanced rules.
I also searched valhalla-dev for discussions of
implicit conversions, user-defined conversions, and literal
conversions. I did not find a discussion of a per-constructor
opt-in marker specifically. The closest prior art I know of is
Swift's literal protocols and C++ converting constructors.
SKETCH
The keyword "opt" is a placeholder:
value class Int16 {
private final short val;
opt Int16(short val) {
this.val = val;
}
}
Int16 a = 13;
The idea is to let a constructor explicitly opt in to a narrowly
defined form of implicit construction, rather than introduce
general user-defined conversions.
COMMON RULES
1. "opt" is allowed only on a constructor with exactly one
parameter.
2. The class opts in explicitly, so existing constructors and
code remain unaffected unless the new feature is used.
3. No conversion chaining is permitted. The source expression
must be compatible with the parameter type under the existing
assignment-conversion rules, including the constant-expression
narrowing rule that permits "short s = 13", without requiring
another conversion after that.
TWO POSSIBLE SCOPES
Option A: Constant expressions only
Int16 a = 13; // allowed
int n = 13;
Int16 b = n; // error; use new Int16((short) n)
Advantages:
- Closely follows the existing rule that permits certain constant
expressions to be assigned to narrower primitive types.
- Allows range checks for representable constants at compile time.
- Introduces fewer questions about overload resolution and
generics.
Disadvantages:
- Less useful, since variables still require explicit
construction.
- A relatively narrow feature, with the boundary between eligible
and ineligible expressions needing careful definition.
Option B: Any expression compatible with the parameter type
Int16 a = 13; // allowed
short s = 12;
Int16 b = s; // allowed
Advantages:
- More general and useful beyond literals and constant
expressions.
Disadvantages:
- Constructor invocation becomes invisible at the use site and
may throw or be expensive.
- Requires rules for method arguments, return expressions,
conditional expressions, generics, and overload resolution.
For example, what should happen when both f(Int16) and f(long)
are applicable?
- Raises the question of which parameter types may be used with
"opt". A constructor accepting a List or another reference type
could perform substantial work implicitly, so restricting the
feature to primitive parameter types, and perhaps String, might
be worth considering.
OTHER OPEN QUESTIONS
- Should this be limited to value classes, or should ordinary
classes be able to opt in as well? For example, could
BigDecimal x = 13 be supported?
- How should an int constant be handled when the constructor
parameter is short, compared with the existing special rule
for assignments such as "short s = 13"?
- Would supporting constant expressions without operators be a
useful first step, and how would that interact with future
discussions of operators for user-defined primitive-like types?
ALTERNATIVES
- Static factories such as Int16.of(13).
- Keeping construction explicit.
I understand this is outside the scope of JEP 401 and may belong
with the planned work on conversions for value classes. I also
understand why Java has generally avoided implicit conversions.
I would be interested to hear whether similar approaches have
been considered, which scope, if either, is closer to the Valhalla
team's thinking, and whether this idea is worth developing further.
Thanks,
Saurav Bhattarai