Skip to content

Commit 3851dff

Browse files
committed
Write about a bunch of potential ideas to smooth the syntax
There is a tradeoff with increased complexity and larger surface area for the changes.
1 parent 7b223ac commit 3851dff

1 file changed

Lines changed: 126 additions & 18 deletions

File tree

pep.rst

Lines changed: 126 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,33 +1303,25 @@ processing, and various smaller things.
13031303

13041304
There is a demo of a runtime evaluator as well [#runtime]_.
13051305

1306-
Rejected Ideas
1307-
==============
1306+
"Rejected" Ideas That Maybe We Should Actually Do?
1307+
==================================================
13081308

1309-
Renounce all cares of runtime evaluation
1310-
----------------------------------------
1309+
Very interested in feedback about these!
13111310

1312-
This would have a lot of simplifying features.
1311+
The first one in particular I think has a lot of upside.
13131312

1314-
TODO: Expand
1315-
1316-
Support TypeScript style pattern matching in subtype checking
1317-
-------------------------------------------------------------
1318-
1319-
This would almost certainly only be possible if we also decide not to
1320-
care about runtime evaluation, as above.
1321-
1322-
Support dot notation to access ``Members`` components
1323-
-----------------------------------------------------
1313+
Support dot notation to access ``Member`` components
1314+
----------------------------------------------------
13241315

13251316
Code would read quite a bit nicer if we could write ``m.name`` instead
13261317
of ``GetName[m]``. A general mechanism to support that might look
13271318
like::
13281319

1329-
class Member[N: str, T, Q: MemberQuals = typing.Never, D = typing.Never]:
1320+
class Member[N: str, T, Q: MemberQuals = typing.Never, I = typing.Never, D = typing.Never]:
13301321
type name = N
13311322
type tp = T
13321323
type quals = Q
1324+
type init = I
13331325
type definer = D
13341326

13351327
We considered this but rejected it due to runtime implementation
@@ -1338,7 +1330,7 @@ need to return an object that captures both the content of the type
13381330
alias while maintaining the ``_GenericAlias`` of the applied class so
13391331
that type variables may be substituted for.
13401332

1341-
We may have been mistaken about the runtime evaluation difficulty,
1333+
We were mistaken about the runtime evaluation difficulty,
13421334
though: if we required a special base class in order for a type to use
13431335
this feature, it should work without too much trouble, and without
13441336
causing any backporting or compatibility problems.
@@ -1350,7 +1342,123 @@ We wouldn't be able to have the operation lift over unions or the like
13501342
That just leave semantic and philosophical concerns: it arguably makes
13511343
the model more complicated, but a lot of code will read much nicer.
13521344

1353-
TODO: Should we do this?
1345+
Another option would be to skip introducing a general mechanism (for
1346+
now, at least), but at least make dot notation work on ``Member``,
1347+
which will be extremely common.
1348+
1349+
With dot notation, ``PropsOnly`` (from
1350+
:ref:`the query builder example <qb-impl>`) would look like::
1351+
1352+
type PropsOnly[T] = typing.NewProtocol[
1353+
*[
1354+
typing.Member[p.name, PointerArg[p.type]]
1355+
for p in typing.Iter[typing.Attrs[T]]
1356+
if typing.IsAssignable[p.type, Property]
1357+
]
1358+
]
1359+
1360+
1361+
Dictionary comprehension based syntax for creating typed dicts and protocols
1362+
----------------------------------------------------------------------------
1363+
1364+
This is in some ways an extension of the :pep:`764` (still draft)
1365+
proposal for inline typed dictionaries.
1366+
1367+
Combined with the above proposal, using it for ``NewProtocol`` might
1368+
look (using something from :ref:`the query builder example <qb-impl>`)
1369+
something like:
1370+
1371+
::
1372+
1373+
type PropsOnly[T] = typing.NewProtocol[
1374+
{
1375+
p.name: PointerArg[p.type]
1376+
for p in typing.Iter[typing.Attrs[T]]
1377+
if typing.IsAssignable[p.type, Property]
1378+
}
1379+
]
1380+
1381+
Then we would probably also want to allow specifying a ``Member`` (but
1382+
reordered so that ``Name`` is last and has a default), for if we want
1383+
to specify qualifiers and/or an initializer type.
1384+
1385+
We could also potentially allow qualifiers to be written in the type,
1386+
though it is a little odd, since that is an annotation expression, not
1387+
a type expression, and you probably *wouldn't* be allowed to have an
1388+
annotation expression in an arm of a conditional type?
1389+
1390+
The main downside of this proposal is just complexity: it requires
1391+
introducing another kind of weird type form.
1392+
1393+
Destructuring?
1394+
''''''''''''''
1395+
1396+
The other potential downside is that it suggests that we might want to
1397+
be able to iterate over ``Attrs`` and ``Members`` with an ``items()``
1398+
style iterator, and that raises more complicated questions.
1399+
1400+
First, the syntax would be something like::
1401+
1402+
type PropsOnly[T] = typing.NewProtocol[
1403+
{
1404+
k: PointerArg[ty]
1405+
for k, ty in typing.IterItems[typing.Attrs[T]]
1406+
if typing.IsAssignable[ty, Property]
1407+
}
1408+
]
1409+
1410+
This is looking pretty nice, but we only have access to the name and
1411+
the type, not the qualifiers or the initializers.
1412+
1413+
Potential options for dealing with this:
1414+
1415+
* It is fine, programmers can use this ``.items()`` style
1416+
iterator for common cases and operate on full ``Member`` objects
1417+
when they need to.
1418+
* We can put the qualifiers/initializer in the ``key``? Actually using
1419+
the name would then require doing ``key.name`` or similar.
1420+
1421+
(We'd also need to figure out exactly what the rules are for what can
1422+
be iterated over this way.)
1423+
1424+
Call type operators using parens
1425+
--------------------------------
1426+
1427+
If people are having a bad time in Bracket City, we could also
1428+
consider making the builtin type operators use parens instead of
1429+
brackets.
1430+
1431+
Obviously this has some consistency issues but also maybe signals a
1432+
difference? Combined with dictionary-comprehensions and dot notation
1433+
(but not dictionary destructuring), it could look like::
1434+
1435+
type PropsOnly[T] = typing.NewProtocol(
1436+
{
1437+
p.name: PointerArg[p.type]
1438+
for p in typing.Iter(typing.Attrs(T))
1439+
if typing.IsAssignable(p.type, Property)
1440+
}
1441+
]
1442+
1443+
(The user-defined type alias ``PointerArg`` still must be called with
1444+
brackets, despite being basically a helper operator.)
1445+
1446+
1447+
Rejected Ideas
1448+
==============
1449+
1450+
Renounce all cares of runtime evaluation
1451+
----------------------------------------
1452+
1453+
This would have a lot of simplifying features.
1454+
1455+
TODO: Expand
1456+
1457+
Support TypeScript style pattern matching in subtype checking
1458+
-------------------------------------------------------------
1459+
1460+
This would almost certainly only be possible if we also decide not to
1461+
care about runtime evaluation, as above.
13541462

13551463

13561464
Replace ``IsAssignable`` with something weaker than "assignable to" checking

0 commit comments

Comments
 (0)