
On 18/07/18 18:43, Steve Dower wrote:
Possibly this is exactly the wrong time to propose the next big syntax change, since we currently have nobody to declare on it, but since we're likely to argue for a while anyway it probably can't hurt (and maybe this will become the test PEP for whoever takes the reins?).
Many thanks for your work on this, Steve. Having just written a fair bit of code that would have benefited from None-coalescing, I'm +1 for "??" and "??=" and +0 for the rest.
Grammar changes ---------------
The following rules of the Python grammar are updated to read::
augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' | '??=')
power: coalesce ['**' factor] coalesce: atom_expr ['??' factor] atom_expr: ['await'] atom trailer* trailer: ('(' [arglist] ')' | '[' subscriptlist ']' | '?[' subscriptlist ']' | '.' NAME | '?.' NAME)
I was a bit worried about the priority here, but your explanations elsewhere make sense. Perhaps the PEP would benefit from being a bit more explicit about this?
From ``calendar.py``::
encoding = options.encoding if encoding is None: encoding = sys.getdefaultencoding() optdict = dict(encoding=encoding, css=options.css)
After updating to use the ``??`` operator::
optdict = dict(encoding=encoding ?? sys.getdefaultencoding(), css=options.css)
ITYM optdict = dict(encoding=options.encoding ?? sys.getdefaultencoding(), css=options.css)
From ``dis.py``::
def _get_const_info(const_index, const_list): argval = const_index if const_list is not None: argval = const_list[const_index] return argval, repr(argval)
After updating to use the ``?[]`` and ``??`` operators::
def _get_const_info(const_index, const_list): argval = const_list?[const_index] ?? const_index return argval, repr(argval)
Here's where I start to part company. To me, the updated version is markedly harder to read, even if it does (once deciphered) convey the intent of the function better than the original :-) The "?." and "?[]" operators just aren't obvious enough not to trip my internal WTF filter; either that or I'll overlook the "?" part entirely, which is probably worse.
Just use a conditional expression ---------------------------------
Another common way to initialize default values is to use the ternary operator. Here is an excerpt from the popular `Requests package <https://github.com/kennethreitz/requests/blob/14a555ac716866678bf17e43e23230...
a8149f5/requests/models.py#L212>`_::
data = [] if data is None else data files = [] if files is None else files headers = {} if headers is None else headers params = {} if params is None else params hooks = {} if hooks is None else hooks
This particular formulation has the undesirable effect of putting the operands in an unintuitive order: the brain thinks, "use ``data`` if possible and use ``[]`` as a fallback," but the code puts the fallback *before* the preferred value.
The author of this package could have written it like this instead::
data = data if data is not None else [] files = files if files is not None else [] headers = headers if headers is not None else {} params = params if params is not None else {} hooks = hooks if hooks is not None else {}
This ordering of the operands is more intuitive, but it requires 4 extra characters (for "not "). It also highlights the repetition of identifiers: ``data if data``, ``files if files``, etc.
While the four whole extra characters bothers me not one bit, the repetition is more of an issue. It's much worse if what you have is more like: item = spam.spam.spam.eggs if spam.spam.spam.eggs is not None else beans -- Rhodri James *-* Kynesim Ltd