record-like initializer for other classes

Brian Goetz brian.goetz at oracle.com
Sat Jun 20 14:37:11 UTC 2020


Thanks for inlining the attachment, now I can see what you mean.  

These are all tricks that work OK in their sweet spot, but they fall off the sweet spot pretty easily.  What you’re saying here is that you want to say that the “state description” in the class header drives a part of the representation, and all of the construction protocol.  But as soon as your superclass has some state, you’re already off the sweet spot, since you have to declare the full constructor header.  All you optimize away is the `this.x = x`.  That’s not nothing, but it doesn’t seem a very long lever.  

More interesting would be some way of disclaiming the independence of various API elements (ctor params, accessors) from fields — right now, a field `x` and an accessor `x()` and a constructor argument `x` probably all describe the same quantity, but we don’t really know it is not an accident of naming.  To the degree to which we could tie these together and say “this is not an accident”, I think there’s more leverage in that direction.  Records take this to their extreme, which is why they work well — there’s one description, from which we derive all the utterances of `x`, as well as all the protocols — representation, construction, access/deconstruction, equality, formatting.  Once you try to chart a middle ground between “none” and “all”, the temptation to devolve into a macro processor is strong, but must be resisted.


Zooming out, one of the dangers of investing in Amber features is that once you start talking about syntax, there’s no logical place to stop.  Yes, for too long we focused on “big” features (lambdas, generics) at the expense of “little” ones (records, var), and we’re trying to rebalance.  But there’s a strong force that would pull us towards the opposite imbalance, and we have to resist it, otherwise there will never be any “big” features again.  The “little” features are not so little when you add it all up.  

Cheers,
-Brian



> On Jun 20, 2020, at 10:15 AM, Mateusz Romanowski <romanowski.mateusz at gmail.com> wrote:
> 
> Hi Brian,
> Sorry about the attachment; put the content at the end of this message.
> 
> Understood, would be awaiting other goodies then.
> 
> Cheers,
> Mateusz
> 
> On Fri, Jun 19, 2020 at 9:55 PM Brian Goetz <brian.goetz at oracle.com <mailto:brian.goetz at oracle.com>> wrote:
> The attachment was dropped. 
> 
> We are interested in generalizing some of the record goodies.  This one is probably one of the weaker ones, but we have thought about it. The basic problem is that in the general case, the parameter names and the field names are essentially unrelated. With records we are able to derive both from a common description.  
> 
> In general though, I think there are much higher leverage things to work on here.
> 
> Sent from my iPad
> 
> > On Jun 19, 2020, at 5:19 PM, Mateusz Romanowski <romanowski.mateusz at gmail.com <mailto:romanowski.mateusz at gmail.com>> wrote:
> > 
> > Hi,
> > Since record classes' concept has become stable, I do hope some ideas might
> > be migrated to less-restricted classes.
> > 
> > I am, I believe, one of many programmers that need to write a lot of
> > `this.x = x;`-like assignments in constructors and therefore *used to*
> > abuse static methods' inner classes to save some characters.
> > 
> > Is there any chance to marry inner class' parameter capture with
> > record-like class initializer?
> > I.e.,  for class with explicit initializer with a _FormalParameterList_:
> > * compiler generates implicit or uses compactly declared explicit
> > constructor with identical _FormalParameterList_,
> > * for any _FormalParameter_ used outside the constructor, compiler captures
> > it into implicit final fields *with the same name as parameter*.
> > Attached please find some translation equivalencies.
> > 
> > What do you think?
> > 
> > Cheers,
> > Mateusz R.
> 
> ---
> class B(int i) extends A {
>   B {
>     super((double)(i+1));
>   }
> }
> 
> class B extends A {
>   B(int i) {
>     super((double)(i+1));
>   }
> }
> 
> ---
> 
> protected abstract class MyAction(String text, boolean visibility) extends AbstractAction {
>   MyAction {
>     super(text);
>   }
> 
>   @Override
>   public void actionPerformed() {
>     setVisible(visible);
>   }
> }
> 
> protected abstract class MyAction extends AbstractAction {
>   protected MyAction(String text, boolean visibility) {
>     super(text);
>     this.visibility = visibility;
>   }
> 
>   @Override
>   public void actionPerformed() {
>     setVisible(visible);
>   }
> 
>   private final boolean visibility;
> }
> 
> ---
> 
> public class Counter(int initialValue) {
>   private final AtomicInteger value = new AtomicInteger(initialValue);
> }
> 
> 
> 
> public class Counter {
>   public Counter(int initialValue) {
>     this.value = new AtomicInteger(initialValue);
>   }
> 
>   private final AtomicInteger value;
> }
> 
> ---
> 
> public class LocalCounter(int initialValue) {
>   int value = initialValue;
> }
> 
> public class LocalCounter {
>   public LocalCounter(int initialValue) {
>     this.value = initialValue;
>   }
> 
>   int value;
> }
> 
> ---
> 
> class Degenerated(int a, int b) {
>   void print() {
>     System.out.println("value =" + a);
>   }
> }
> 
> class Degenerated {
>   Degenerated(int a, int b) {
>     this.a = a;
>   }
> 
>   void print() {
>     System.out.println("value =" + a);
>   }
> 
>   private final int a;
> }
> 



More information about the amber-dev mailing list