class Box{
Int x
Int y
new make(Int x, Int y){
this.x=x
this.y=y
}
}
Short creation:
box := Box(1,2)
I used this 100s times.
But suddenly I need serialization for Box. Ok:
@Serializable
class Box{
Int x
Int y
new make(|This| f){
f(this)
}
new makeMeSad(Int x, Int y){
this.x=x
this.y=y
}
}
Adding @Serializable is breaking change. Short creation is not available. I must change it 100s times.
box := Box.makeMeSad(1,2)
Inaccessibility of short creation make me sad more than needing of replacing.
I suggest, deserialization must use special ctor makeDeserialization(|This| f) and if deserialization not found ctor makeDeserialization then use ctor make(|This| f).
Why deserialization take off short ctor which need to call by manual although deserialization call ctor by automatic?
brianWed 5 Jan 2011
You definitely have a good point about how this works.
So is it worth complicating the serialization design to specify an alternate make method to ensure that "good" make is reserved for human programmers?
If did that, I would be included to do via adding a slot literal field on the Serializable facet:
@Serializable { ctor = #makeSerialized }
class Box
{
new make() {...}
new makeSerialized() {...}
}
andyWed 5 Jan 2011
I had not considered this either - but makes sense. I don't write awhole lot of serializable code at the moment - so can't really gauge the impact one way or the other - but the ctor facet meta seems to make sense.
AkcelistoWed 5 Jan 2011
Why I should configure facet? Why makeSerialized not can be default (with fallback to make for backward compatibility)?
I want: convention over configuration.
P.S. Why deserialization require specific ctor? Java require nothing for deserialization.
DanielFathWed 5 Jan 2011
There is a solution that would bypass both, Contructor overload. Though Akcelisto's questions is good question might be simple overall.
andyWed 5 Jan 2011
I'm cool with just making makeSerialized the standard mechanism (can't see ever wanting to use that name for something else).
qualidafialThu 6 Jan 2011
I've used serialization a bit, and did a bit of grumbling about how I had to mangle my constructor to play nice with serialization.
I favor the idea but not makeSerialized. You're constructing an object using a callback init function. The fact that we're using this idiom to deserialize an object is secondary.
I propose makeFunc, since it focuses on the idiom rather than a single use case.
qualidafialThu 6 Jan 2011
Depending on how it goes, this may even be worth implementing compiler sugar for, similar to how the compiler converts Point("1,2") to Point.fromStr("1,2").
This way you can have both the regular constructor and the it-block constructor free of boilerplate:
@Serializable
class Box{
Int x
Int y
new make(Int x, Int y){
this.x=x
this.y=y
}
new makeFunc(|This| f){
f(this)
}
}
box := Box(1, 2)
box2 := Box { x = 1; y = 2 }
AkcelistoThu 6 Jan 2011
to qualidafial
I disagree with rename makeSerialized to makeFunc. I need separate ctor for deserialization and separate ctor for manual creation. Because I need to enhance obj after deserialization.
@Serializable
class Box{
Int x
Int y
new make(Int x, Int y){
this.x=x
this.y=y
}
new makeFunc(|This| f){
f(this)
}
new makeSerialized(|This| f){
f(this)
afterDeserialize
}
private Void afterDeserialize(){
// here I usually fill refs which not serialized and not deserialized
// this method not need to call when manual creation
}
}
to DanielFath
There is a solution that would bypass both, Contructor overload.
I like ctor overload. Operators already have overload. Ctors needs this too.
But ctor overload may complicate problem with deserialization ctor. Compiler say for this class: "duplicate list of args for makeMeSad and make"
@Serializable
class Box{
Int x
Int y
new makeMeSad(|This| f){
f(this)
}
new make(|This| f){
f(this)
postDeserialize
}
private Void afterDeserialize(){
// here I usually fill refs which not serialized and not deserialized
// this method not need to call when manual creation
}
}
Ideally:
ctor overload exists
deserialization not require special ctor
deserialization call method with facet AfterDeserialization if it exists in class
deserialization checks notnull fields after creation
end of list
@Serializable
class Box{
Int x
Int y
new make(Int x, Int y){
this.x=x
this.y=y
}
@AfterDeserialization
private Void fillRefs(){
// fill refs which not serialized and not deserialized
// this method not need to call when manual creation
}
}
to Bryan
Why makeSerialized? This sounds like we create serialized obj but we create de-serialized obj. May be better makeDeserialized?
qualidafialThu 6 Jan 2011
@Akcelisto: it sounds like you want the equivalent of Java's readResolve. If so we could add that while still using makeFunc as a more use-case agnostic convention.
ivanMon 10 Jan 2011
Totally agree with @qualidafial
Compiler sugar for makeFunc constructor seems to be much easier to do than constructor overloading and should cover all the cases. Plus if constructor overloading will be added later, the code won't be broken.
`http://download.oracle.com/javase/6/docs/platform/serialization/spec/input.html#5903` method is much more clear than separate deserialization constructor and gives more abilities than @AfterDeserialization private Void whatever()
brianTue 15 Nov 2011
Renamed from Deserialization take off short ctor to Overloading of constructor shortcut
brianTue 15 Nov 2011
Promoted to ticket #1370 and assigned to brian
This issue and also the discussion per #1674 presents a clear case that we should provide a more flexible mechanism to overload the constructor shortcut syntax of Type(...) to map to more than one method.
Simplest design would be to reuse the @Operator facet on any method that it prefixed with make or from. But I don't think we want to require that facet on existing make or fromStr methods. At the same time, I don't want to create an inconsistency.
Not sure yet what correct design should be.
qualidafialTue 15 Nov 2011
I've been thinking about this with regard to default constructors. If your class has no fields, or has only nullable fields, then it's ok to have the compiler inject a no-arg, no-op constructor.
However if you have any non-nullable fields, it would be nice to have the compiler inject a makeFunc(|This| f) constructor for us. The rest of the time, these callback constructors are just repetitive boilerplate.
qualidafialTue 15 Nov 2011
This could also serve as a nice compromise for #1696 (using <ObjType>.defVal for uninitialized non-nullable fields).
qualidafialMon 21 Nov 2011
Simplest design would be to reuse the @Operator facet on any method that it prefixed with make or from. But I don't think we want to require that facet on existing make or fromStr methods. At the same time, I don't want to create an inconsistency.
As far as backward-incompatible changes go, this ranks pretty low on the pain scale. If the compiler fails, just go add the missing @Operator facet and compile again. Not a big deal.
To help users make the transition, we could always do a two-phase rollout:
Phase one: Compiler begins honoring @Operator facets on from* and make* methods. Existing make and fromStr methods lacking the facet will act as if they had the facet, but will issue a compiler warning.
Phase two: Remove special case exception for make and fromStr. Only methods having the @Operator facet will receive constructor shortcut treatment from the compiler.
This way users will have a full release cycle to update their code.
MoOmWed 23 Nov 2011
I'm not fond of the @Operator facet on constructors. Constructors are not operators in my mind.
Can't we just make this the default behavior for constructors? We may not want to have that on all constructors though (I have no example in mind...). In this case, we could use an @Explicit annotation on constructors on which we don't want to allow the short syntax.
from* and to* methods might be seen as conversion operations so @Operator annotation would work for me but then we would probably want a conversion operator (like the ~ operator proposed by Jodastephen iirc). This would work well for consistency and for ease of use imho.
brianFri 25 Nov 2011
Can't we just make this the default behavior for constructors?
I was sort of thinking of this approach - basically just allowing any constructor prefixed with "make" to use shortcut approach. I am not sure it would really hurt since it would be traditional overload. But I suspect it will cause new compilation problems where existing code will have ambiguous calls to multiple constructors.
brianSat 16 Jun 2012
Ticket resolved in 1.0.62
Just going back through and this ticket was really dup of 1776 and closed out in last build.
Akcelisto Wed 5 Jan 2011
Simple class:
Short creation:
I used this 100s times.
But suddenly I need serialization for
Box
. Ok:Adding @Serializable is breaking change. Short creation is not available. I must change it 100s times.
Inaccessibility of short creation make me sad more than needing of replacing.
I suggest, deserialization must use special ctor
makeDeserialization(|This| f)
and if deserialization not found ctormakeDeserialization
then use ctormake(|This| f)
.Why deserialization take off short ctor which need to call by manual although deserialization call ctor by automatic?
brian Wed 5 Jan 2011
You definitely have a good point about how this works.
So is it worth complicating the serialization design to specify an alternate make method to ensure that "good" make is reserved for human programmers?
If did that, I would be included to do via adding a slot literal field on the Serializable facet:
andy Wed 5 Jan 2011
I had not considered this either - but makes sense. I don't write awhole lot of serializable code at the moment - so can't really gauge the impact one way or the other - but the
ctor
facet meta seems to make sense.Akcelisto Wed 5 Jan 2011
Why I should configure facet? Why
makeSerialized
not can be default (with fallback tomake
for backward compatibility)?I want: convention over configuration.
P.S. Why deserialization require specific ctor? Java require nothing for deserialization.
DanielFath Wed 5 Jan 2011
There is a solution that would bypass both, Contructor overload. Though Akcelisto's questions is good question might be simple overall.
andy Wed 5 Jan 2011
I'm cool with just making
makeSerialized
the standard mechanism (can't see ever wanting to use that name for something else).qualidafial Thu 6 Jan 2011
I've used serialization a bit, and did a bit of grumbling about how I had to mangle my constructor to play nice with serialization.
I favor the idea but not
makeSerialized
. You're constructing an object using a callback init function. The fact that we're using this idiom to deserialize an object is secondary.I propose
makeFunc
, since it focuses on the idiom rather than a single use case.qualidafial Thu 6 Jan 2011
Depending on how it goes, this may even be worth implementing compiler sugar for, similar to how the compiler converts
Point("1,2")
toPoint.fromStr("1,2")
.This way you can have both the regular constructor and the it-block constructor free of boilerplate:
Akcelisto Thu 6 Jan 2011
to qualidafial
I disagree with rename
makeSerialized
tomakeFunc
. I need separate ctor for deserialization and separate ctor for manual creation. Because I need to enhance obj after deserialization.to DanielFath
I like ctor overload. Operators already have overload. Ctors needs this too.
But ctor overload may complicate problem with deserialization ctor. Compiler say for this class: "duplicate list of args for
makeMeSad
andmake
"Ideally:
AfterDeserialization
if it exists in classend of list
to Bryan
Why
makeSerialized
? This sounds like we create serialized obj but we create de-serialized obj. May be bettermakeDeserialized
?qualidafial Thu 6 Jan 2011
@Akcelisto: it sounds like you want the equivalent of Java's
readResolve
. If so we could add that while still usingmakeFunc
as a more use-case agnostic convention.ivan Mon 10 Jan 2011
Totally agree with @qualidafial
makeFunc
constructor seems to be much easier to do than constructor overloading and should cover all the cases. Plus if constructor overloading will be added later, the code won't be broken.@AfterDeserialization private Void whatever()
brian Tue 15 Nov 2011
Renamed from Deserialization take off short ctor to Overloading of constructor shortcut
brian Tue 15 Nov 2011
Promoted to ticket #1370 and assigned to brian
This issue and also the discussion per #1674 presents a clear case that we should provide a more flexible mechanism to overload the constructor shortcut syntax of
Type(...)
to map to more than one method.Simplest design would be to reuse the
@Operator
facet on any method that it prefixed withmake
orfrom
. But I don't think we want to require that facet on existingmake
orfromStr
methods. At the same time, I don't want to create an inconsistency.Not sure yet what correct design should be.
qualidafial Tue 15 Nov 2011
I've been thinking about this with regard to default constructors. If your class has no fields, or has only nullable fields, then it's ok to have the compiler inject a no-arg, no-op constructor.
However if you have any non-nullable fields, it would be nice to have the compiler inject a
makeFunc(|This| f)
constructor for us. The rest of the time, these callback constructors are just repetitive boilerplate.qualidafial Tue 15 Nov 2011
This could also serve as a nice compromise for #1696 (using
<ObjType>.defVal
for uninitialized non-nullable fields).qualidafial Mon 21 Nov 2011
As far as backward-incompatible changes go, this ranks pretty low on the pain scale. If the compiler fails, just go add the missing
@Operator
facet and compile again. Not a big deal.To help users make the transition, we could always do a two-phase rollout:
@Operator
facets onfrom*
andmake*
methods. Existingmake
andfromStr
methods lacking the facet will act as if they had the facet, but will issue a compiler warning.make
andfromStr
. Only methods having the@Operator
facet will receive constructor shortcut treatment from the compiler.This way users will have a full release cycle to update their code.
MoOm Wed 23 Nov 2011
I'm not fond of the
@Operator
facet on constructors. Constructors are not operators in my mind.Can't we just make this the default behavior for constructors? We may not want to have that on all constructors though (I have no example in mind...). In this case, we could use an
@Explicit
annotation on constructors on which we don't want to allow the short syntax.from*
andto*
methods might be seen as conversion operations so@Operator
annotation would work for me but then we would probably want a conversion operator (like the ~ operator proposed by Jodastephen iirc). This would work well for consistency and for ease of use imho.brian Fri 25 Nov 2011
I was sort of thinking of this approach - basically just allowing any constructor prefixed with "make" to use shortcut approach. I am not sure it would really hurt since it would be traditional overload. But I suspect it will cause new compilation problems where existing code will have ambiguous calls to multiple constructors.
brian Sat 16 Jun 2012
Ticket resolved in 1.0.62
Just going back through and this ticket was really dup of 1776 and closed out in last build.