Proposal: `PrivateSet[T]` — a type hint for externally read-only, internally writable fields

Thanks for the summary of the different AccessMode modifiers!

I’m not sure that these modes are useless at all - Java has six different modifiers (rrr, www, -rr, -ww, --r, --w) with public/protected/private x final or non-final , and I find all of them useful in different situations. I don’t see any reason not to have a few more!

A few comments on the different possible modes (making those same assumptions):

  • www: Expressable :white_check_mark:
    This is already the default in Python.
  • --w/--r: Expressable :white_check_mark:
    Expressable with __private attributes, with/without the Final qualifier.
  • rrr: Expressable :white_check_mark:
    Same as Final[T] or ReadOnly[T] (WIP) depending on the situation and semantics.
  • -ww: Inconsistently Supported :orange_square:
    This is generally how _protected attributes are treated in Python, though AccessMode could be used to more formally express this.
  • rww: Inconsistently Supported :orange_square:
    I think this is another valid interpretation of _protected attributes that could be expressed more clearly with AccessMode.
  • -rw/-rr: Not expressable :cross_mark:
    More alternative protected field designs - maybe a field is useful for overriding methods in subclasses, but not meant to be accessed publicly, and (for -rw) may not be safe to override without using some method of the superclass designed to do so.
  • rrw: Not expressable :cross_mark:
    Proposed in this threat as PrivateSet[T] or InternallyWriteable[T]. Same as ReadOnly[T] within __new__, __init__, etc. (but not for all methods).

It looks like just over half of these modes are difficult or impossible to express with the Python type system (please let me know if anything was incorrect) - so only adding InternallyWritable[T] (whilst possibly the most useful type on that list) feels like a missed opportunity.

2 Likes

I’ve always seen that typecheckers/linters interpret _field as -ww and not rww

  • rww would be field: SetProtected[T] in a non AccessMode solution
  • -rr is then _field : Final[T]
  • rrw is field: SetPrivate[T]
  • -rw is _field: SetPrivate[T]

The ‘majority’, not all cases. There might be some cases, useful for certain aspects.

If I e.g. want to make some system for a game, where a player (‘owner’ instance of a class → internal) posts something, and others vote on it, the creator should not be able to see who voted something, whilst others should see more details.

This example might be bad, but I could imagine users wanting to express more than the few ‘standart’ things.

I think one of the important things here is that supporting extra modes shouldnt significantly change the complexity of implementation. As far as type checkers are concerned, there is only: is get allowed, is set allowed, for each public and private. If set or get is allowed at all, it impacts variance (unchanged from current).

2 Likes

Yeah, the implementation itself should be straight forward. Imo though, we should first figure out how we’ll specify Access/AccessMode (given that 60% of voters voted for that in my Poll).

@gitkoi and I could try and find some typing-enthusiastic core dev, who would be willing to guide us through the process of making a Draft PEP (assuming all other parts of the spec are given).

Thanks for including me, @jobe!

Just to mention—I’m not very confident in English, so I may not be able to write much myself.
But I’m happy to help and support the effort however I can, especially around naming and examples.

1 Like