-
Notifications
You must be signed in to change notification settings - Fork 360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inline classes #104
Comments
This is an awesome idea and I can definitely see myself using this feature in different scenarios. I just have a small question. From an implementation perspective, inline classes feel more like interfaces than actual classes (mainly due to their stateless nature). The only reason I can think of that justifies the use of classes instead of interfaces is instantiation: instances can be "created" by calling the constructor. But I feel like there could be another mechanism to accomplish this. What do you think? |
There was a discussion about allowing Since inline classes support autoboxing just like primitives, this could be possible to use inline sealed classes and do |
@gabrielhuff Do you mean that inline classes are similar to something like "newtype" or "strict typealiases"? And they can be used like this:
? It's interesting, but we believe that current form to declare members/types is suited for us better |
@LouisCAD
All subclasses must have different runtime underlying representation. And you're right that in current design autoboxing will occur even on the simplest cases:
Basically, yes, currently this is a major reason to prohibit inline sealed classes for now |
I wonder if |
@udalov Interesting! In other case, for
Here .class file also is not needed |
I think |
Current spec seems to not cover annotations on inline classes. It seems that annotations are pretty much useless since class gets erased after compilation. Moreover they might be even dangerous as they might trick user into thinking that they'll make difference: inline class UserId(@SerializedName("user_id") private val id: String) However I guess you could give compiler plugins a chance to introspect them (which might be very useful). WDYT? |
Due to nature of |
Since inline classes can't have For example, suppose I create a Username class:
And I want to throw an exception at run time if somebody tries to create a Username that contains spaces:
Will this be possible? |
@RaisedByTheInternet This is also true for Data classes. |
@artem-zinnatullin Yes, annotations on underlying value should be prohibited, thanks for pointing this out! Moreover, there might be inconsistent behaviour for boxed/unboxed representation. It's hard to say about compiler plugins for now, could you please elaborate more about use cases? |
@sakno As I see, const data classes can use very restrictive set of types as an underlying value to ensure constant Yes, we're closely watching the project Valhalla and probably will try to use their mechanism for value/inline classes in future |
@RaisedByTheInternet No, currently this is impossible. Unfortunately, the current restrictions are made in a such way to avoid any initialisation (validation) for inline classes. Seems that it's impossible to have consistent behaviour and Java interop if we'll allow to have |
In such case we should consider also |
@fvasco What's the point of |
Hmm, if we can't do validation then this feature seems very limited. For example, we have this UInt inline class:
If anyone can simply say |
Hi @RaisedByTheInternet The following statement is invalid
C has the same issue. Inline classes miss of encapsulation. Have you some proposal for this feature? |
@RaisedByTheInternet You are right and yes, this is one of the most controversial restriction. As @fvasco mentioned, |
It sounds like I may have misunderstood, as I didn't realise that But how will that work? Something like |
I wish bring to your attention another common use case, I hope that considering a bit more complex problem can help us to understand the simpler one. I want to define a I can use a single inline class Point private constructor(private val long: Long) {
constructor(x: Int, y: Int): this(wrap(x, y))
val x: Int get() = ...
val y: Int get() = ...
compantion object {
fun wrap(x: Int, y: Int): Long = ...
}
} In such case, as @gildor said, we have "private constructor + factory function". In inline class UInt private constructor(private val int: Int) {
constructor(value: Long): this(wrap(value))
fun toLong() = ...
compantion object {
fun wrap(value: Long): Int = ...
}
} |
@fvasco |
I see. Thanks for the examples. I guess one problem with the UInt example is that we need to pass a Long, and so something like this won't work: val value: Int = getValueFromSomewhere()
UInt(value) // error: a Long is expected and we tried to pass an Int Passing |
That isn't a problem with this proposal. All Kotlin behaves like that. |
Why should annotations be prohibited on properties? In the previous example
The annotation could simply be inlined as well. This would allow for use with existing APIS/frameworks like JPA, and it seems to me like it is the expected behavior. |
Inlined where? Idea of ie: inline class UserId(@SerializedName("user_id") private val id: String)
fun test(userId: UserId) {
} ^ after compilation So… where should we put information from annotations? (I mean, you can create a meta registry of inline-classes and then annotate all functions that use them thus allowing runtime reflection, but I doubt it's useful) |
It could be inlined on the filed/parameter that resulted from inlining the class.
becomes
|
@trevorhackman Because they are still experimental and not all use cases are supported yet. There's an open issue here for that feature: https://youtrack.jetbrains.com/issue/KT-25915 |
Why is it that inline classes permit only a single property? Is it a "for now" restriction because it's easier to implement (which I believe), or are there fundamental problems with admitting multiple properties? |
I believe inline classes were designed so that you can wrap "primitives"
inside an object so that you have type safety when passing those values
around, without the overhead
inline classes might become val classes according to the Kotlin Conf
from yesterday in which case they might allow more than one property
…On 2020/10/14 10:49, Raphael wrote:
Why is it that inline classes permit only a single property? Is it a
"for now" restriction because it's easier to implement (which I
believe), or are there fundamental problems with admitting multiple
properties?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#104 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AARLC5TVZZSUUAK63NGAMXLSKVQ3PANCNFSM4EYZPJTA>.
|
@janvladimirmostert which talk are you talking about exactly? |
Kotlin Online Event (not KotlinConf @janvladimirmostert), the one named "A Look Into the Future" by Roman Elizarov: https://youtu.be/0FF19HJDqMo |
It would be great if we use the inlined class without having to access the internal value, like a delegate.
|
@nschwermann Can you elaborate on how that's going to be different from a |
@nschwermann, are you suggesting that an accidental How handle |
It should be a compiler error unless you have defined the operator to add
uint to int.
…On Wed, Dec 2, 2020, 2:44 AM Francesco Vasco ***@***.***> wrote:
@nschwermann <https://github.com/nschwermann>, are you suggesting that an
accidental Password("abc123_secure!!!").toString() should reveal the
actual secret?
How handle unit plus uint?
UInt is a wrapper of Int, therefore should be translated to int plus int,
with a Int result, or should be translated to int plus uint, so a
compiler error?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#104 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGZSBKYHLRRPLPYRW2AAW3SSX45RANCNFSM4EYZPJTA>
.
|
@nschwermann
There is already an issue for that KT-27435 |
Thanks @quickstep24 yes that is exactly what I am talking about, but I don't think you should even have to use the delegate syntax. Should be automatic. |
FWIW, I disagree with that. An automatism would preclude us from ever having incline classes for multiple values, which I'm more interested in than avoiding the few symbols to make delegation explicit. Never mind that delegation requires an interface (or does it?) which you don't get from a field with a class type. |
Also would prevent us from encapsulating / hiding functions or values we do not want to expose. Allowing to implement an interface by delegating to the actual value would be great and probably enough. |
@reitzig ticket linked says they are considering allowing the delegate syntax even when its not an interface or open class. I don't think inline class with multiple values is even on the table. What would be the point of that? No longer could compiler replace the inlined class with actual implmentation if there were multiple values. @sollecitom giving the auto delegate doesn't solve the problem of hiding implmentation of inlined class. You can still can (but have to) call .value and do anything you want to the inlined class. In that case, better to just have a privately backed class. That gives me an idea! If you make inline class value public you get this feature, if its private you dont! |
@nschwermann
Case 1 you should use typealias instead Tying inheritence to visibility would mean mixing two otherwise unrelated aspects. Moreover, the signature of 'inherited' methods is completely unclear. |
@quickstep24 you are missing my point. My only complaint is you should not go through the burden of Still |
@nschwermann you are right, I do not get your point. Please rethink on your expectations. Why should |
@quickstep24 my thoughts are String does not have defined plus operator with User so it should not work. Type should be kept, api of inlined class exposed. 'Password("abc") + User("name")' It's not a delegate, it's similar to one. |
@nschwermann |
@quickstep24 that is fine, the meta data that the argument is a |
Is the prohibition on vararg parameters of inline classes likely to be revisited before inline classes come out of beta? I experimented with using inline classes to wrap
And of course when I change I understand the implementation complexity involving arrays of inline classes makes this a tough problem to solve. If the restriction is going to remain in place, then the right fix will be to change the code generator, since I expect wrapping database IDs will be a pretty common use case for inline classes. I use jOOQ as an example here but of course the same would apply to any other code generator that can produce functions with vararg parameters of user-defined types. |
I wanted to use inline class before for IDs, but since it was still beta and many issues with it, I changed to use data class with single field. |
I've used inline classes extensively for more type-safety (e.g. At some point I was annoyed that I couldn't do something like After a while however I came to the conclusion that that's not good. Such types typically have values that are narrower than the types they wrap. E.g. all
The remaining cases can be implemented selectively on your type.
It's a little different with numeric types, e.g. an |
Unfortunately, no. Support for varargs of inline classes will be added later. They will not be available in the initial release. |
Good point. I'm not sure if they are legal for inline classes already, but interface conformance by delegation seems to be a decent solution here. Write an interface with the methods you want, delegate the implementation to the wrapped value, done. |
I don't get the point of inline (non reified) classes.. if the compiler map them to the upper bound, what's the point to prefer them against traditional classes? |
As I know (To tell the truth, I think they are a very good and bright idea but imho not worth the amount of work put to developing them by the Jetbrains team...) |
Not with generics, apparently. If this:
compiles to:
then the whole purpose to use an inline class fails |
Maybe I don't understand something. What would be a better solution in your opinion? |
Discussion of the proposal:
https://github.com/Kotlin/KEEP/blob/master/proposals/inline-classes.md
The text was updated successfully, but these errors were encountered: