As with the previous mail, this is one of those where we have to trade off between what is ideal for the purpose and not introducing gratuitous new variations between similar looking entities, which add to the developer's complexity load and create migration challenges.

We've already discussed making the default accessibility for mandated members match that of the class, rather than "public." What you're asking for is: when someone explicitly specifies a mandated member, they not have to say the access modifier.

I sympathize, but I think this would be a mistake.  First, the idea is that most of the time, you don't have to explicitly specify the mandated members.  But more importantly, this is a string that you can pull on arbitrarily long.  Suppose the default accessibility for explicit mandated members were the "right thing" (either public, or matching the class -- the difference is purely aesthetic.)  Now there's a gap between these members and others, that sucks.  So suppose all members had that access mode by default (as you propose in B).  This at least has the benefit that it is like interfaces, rather than a new thing, but ... interfaces cannot use certain accessibilities (no protected, no private fields or member classes), so its not exactly the same.  But more importantly, this creates (a) friction between records and classes (I disagree that records are more like interfaces -- and more importantly, I think most users will think of them as compact classes), and (b) migration friction.  All to save a few "publics" -- but only a vanishingly small percentage of the publics in a typical code base.

I think we're back in the "aha, a chance to fix mistakes of the past" trap.

On 1/10/2020 1:40 AM, John Rose wrote:
6. Default access modes in records.  (See above. )

I specifically want to make sure we are doing the best thing on
access defaults (what happens when you don’t mention *any*
access mode).  I suppose that’s a separate item, related to this
one.  Even though we have a decision of record on this, I’m
calling it out here and now because we are stuck with the final
decision we make this time around.  (Maybe like a mandatory
appeal for a capital case.)

Choices:  A. Package scope like classes, B. public like interfaces,
C,D,… something new for records.

A. Records are concise classes which represent a state vector
of components, plus optional additional behavior.  If a record
member is declared with no access mode, it is given the package
access mode.  Just like classes.  The word “public” must be
reaffirmed for every API in the record; just like classes, the
presumption is that API points should be private by default,
and only made public via explicit mark-up.

B. Records are state vectors of components, plus optional
additional behavior.  They are not general classes, but rather
constrained types, much like interfaces are behavior vectors
of abstract API points, plus optional behavior.  If a record
member is declared with no access mode, it is given the
public access mode.  Just like an interface, a record is a
restricted type, whose contracts with the outside world
are mainly public, and which has a limited capacity for
non-public contracts.

C. Records are state vectors of components, plus optional
additional behavior.  The parts of their API which are
intended to be mostly public are public by default, at least
if the record type as a whole is public.  The precedent for
this variability is the implicit empty nullary constructor
supplied to every class, whose access mode is copied
from the class itself.  The parts of a record API that are
expected to be public are the factory (canonical constructor)
and the accessors (component projection methods).
So those guys are public by default (if the record is public).
(If the record isn’t public those other guys are the same.)

At present I prefer “B”, because I now think that, regarding
the access expectiations of API points, records are *far more
similar to interfaces* than they are to random run of the mill
classes.  We started with random classes, but after applying
enough constraints we now have API elements which are
closely analogous to interfaces:  Bundles of state, bundles
of operations.  And, for wide use; i.e. few or no secrets.
In both cases, “public” is the sane default.

An advantage of “B” is there’s nothing new to teach. “You
know how interfaces have their own default access?  Well,
records use the same rules.”

— John

Reply via email to