Closed sgalles closed 8 years ago
FTR : https://github.com/ceylon/ceylon-compiler/issues/2250 removed a part of the pain with late
but I'm inclined to think that AccessType.PROPERTY
is not super useful in Ceylon because the visibility of the generated getter/setters is always symetrical (I can't have a public getter and a private setter on the same field)
uhm...on second thought, something still bothers me, but I don't know how this can be solved. OK, let's say that I'm now able to declare a partial private default constructor. Now all my JPA entities looks like this :
class Foo{
abstract new(){}
shared new init(String bar, String baz){} // yuck !
}
in a perfect world, I'd like to be able to use the classes of my entities as perfectly normal classes, but the partial constructor trick leaks as this unnecessary init constructor. Actually, I'd like to write
class Foo(String bar, String baz){
abstract new(){}
}
but this obviously breaks the golden rule of constructors VS class parameters.... ...unless this was allowed provided that the private constructor is not called in the class (but I don't know if it would be sound)
AFAICT this could only be allowed on classes with a nonempty parameter list, otherwise both constructors would have the same Java signature.
yes indeed, @lucaswerkmeister but anyway if I have a class with a an empty parameter list JPA is perfectly happy with the generated public constructor and I don't need the abstract one.
What about an annotation in ceylon.interop.java
that tells the compiler to generate a no-arg constructor?
So the big question is: do we ever need this default constructor to actually do anything? If it's always empty, then I suppose an annotation in java.lang
would be the cleanest solution. Or perhaps we could even make it a side-effect of the new serializable
annotation.
But if there are some cases where we do need to do something in this constructor then that solution isn't quite good enough. Thoughts?
What about an annotation in
ceylon.interop.java
No, not there: the compiler doesn't know about ceylon.interop.java
. We would put it in java.lang
, I suppose.
Or perhaps we could even make it a side-effect of the new
serializable
annotation.
I'm not sure I understand that, assuming you mean the Ceylon serializable
annotation. To me it feels more like this is a requirement stemming from the class needing to be a JavaBean. JavaBeans are also supposed to be java.io.Serializable
, of course, so it feels more natural to make this magic happen when a class satisfies that interface.
To me it feels more like this is a requirement stemming from the class needing to be a JavaBean. JavaBeans are also supposed to be
java.io.Serializable
, of course, so it feels more natural to make this magic happen when a class satisfies that interface.
Well, no, not really.
java.io.Serializable
does not require a default constructor, since serialization bypasses constructors.Well, to solve the particular case of JPA, we could just always generate a private
default constructor.
always generate a
private
default constructor.
Well the only problem with that is bloat.
Well how much bloat is one empty constructor with no parameters?
In every class in a module though.
Also doesn't it need to be protected
to cater for subclasses?
In every class in a module though.
Well we need to measure what is the impact of that in terms of a %.
Also doesn't it need to be
protected
to cater for subclasses?
Probably.
OK, let me try
Cool, thanks.
On Thu, Oct 1, 2015 at 11:52 AM, Tom Bentley notifications@github.com wrote:
OK, let me try
— Reply to this email directly or view it on GitHub https://github.com/ceylon/ceylon-spec/issues/1405#issuecomment-144681743 .
Gavin King gavin@ceylon-lang.org http://profiles.google.com/gavin.king http://ceylon-lang.org http://hibernate.org http://seamframework.org
Problem: What about a Ceylon class with a Java superclass without a nullary constructor? We can't generate a nullary constructor in that case.
terms of a %.
0% for the SDK, to 2 d.p. at least.
Sure, there are some cases where you shouldn't generate this:
of
clausePerhaps there are some others, I'm not sure.
@tombentley aah, but what happens with final
fields? you suppressed that check? Does the VM accept that?
Or you assign Java default values?
I'm assigning default values. The suppression of javac errors is something which we're only doing in very limited circumstances.
Cool, well that's fine.
My concern about the corner cases where we don't generate such a constructor is that it might be non-obvious to the user why it suddenly doesn't work, and since it's an implicit thing there's nowhere that we can put an error to say "this isn't going to work". It just mysteriously won't work at runtime.
Oh, what about generic classes, btw: We need reified type parameters, but JPA wan't supply them. So I guess we shouldn't generate ctors in that case either.
@tombentley I don't see how they're corner cases. They're cases where it would be wrong/impossible to have a default constructor.
Oh, what about generic classes, btw: We need reified type parameters, but JPA wan't supply them. So I guess we shouldn't generate ctors in that case either.
Yes, that seems correct.
Related ceylon/ceylon-compiler/issues/2329.
This is turning out to be quite difficult because I need the constructor to initialize final
reference fields to null. To do that I need to know what those fields are, and it turns out the backend cannot readily answer the question: "what fields will this class have?". Reference attributes are not the problem: It's things like methods specified via a callable where what we generate can depend on details which are not in the model, only in the tree. (In particular there's one case where we do or do not generate a field based on that the specifier expression is).
And the javac AST you're building doesn't let you iterate over all the fields you've added to it?!
I think we should put this has-a-field information in the model, is that OK with you @gavinking? In fact if we added an int
or long
bit set to the model, it would have us having to add booleans and getters and setters for all these JVM specific things.
I would have thought this information was there in the javac AST.
That would work, @gavinking, but the transformers have always steered clear from inspecting the emitted JCTree. It would be too easy to get into ordering problems where we decide X, then something goes and adds Y which invalidates the logic for X. But maybe that's the simplest solution in this case.
I mean, while I agree that in general it might be a bad idea, it seems like it's the most correct thing here.
This constructor ends up looking an awful lot like the constructor we generate for serializable
classes, only nullary, rather than with an ignored parameter of undenoteable type. I suppose we could have the serializable
one delegate to the other one, or even not generate it at all, and figure it out at runtime.
I mean we could say that only serializable
Ceylon classes can be serialized via Java serialization, if there were some advantage to that. (I don't especially see any.)
No, I don't really see any either. It just seems like there's a small opportunity here to keep things simpler...
This should now be done.
Great, thanks!
If we could write this :
it would allow to generate a private default constructor in Java for the frameworks that need it.
For instance, currently this JPA entity with FIELD access https://github.com/sgalles/ceylon-dddsample/blob/master/source/dddsample/cargotracker/domain/model/cargo/Cargo.ceylon must have this constructor to please the compiler.
but it could simply be
abstract new(){}