On Mon, 20 Jun 2022 at 01:37, David Mertz, Ph.D. <david.mertz@gmail.com> wrote:
Unfortunately, in relation to this PEP, I find your arguments tend to be sophistical. They ate not generally so in other threads, but for whatever reason your attachment to this has a different quality.
I've no idea what you mean by "sophistical" here. Please explain?
There's an interesting point you raise though. You seem to feel that closely related meanings should have similar looking sigils. I'm not sure my opinion is *opposite *, but it's definitely more that subtly different semantics should not be marked by easily visually confusable sigils.
Under PEP 671, a single line of a function signature might contain '=', ':=', '=>', '->', ':', and '=='. Obviously it can have other symbols as well. But those are the ones the most blur into each other visually. 4 of them have closely related meanings. You don't even need to be contrived to have such examples.
Yes, but only some of those are actually part of the signature itself. I mean, if you put a lambda function into the default value, you could have even more colons: def f(x:int=lambda x: x+1, y:object=(_default:=object())): ... But that's just what happens when syntax is nestable. We almost never restrict code to using an arbitrary subset of Python syntax just because otherwise there'd be similar symbols in the same vicinity. Even when it's a problem for the parser, the solution is often just parentheses.
I guess '>=' also looks "confusable", but it's far less common in signatures, and the meaning is further away.
It's no less valid than your other examples, nor less common (why would you have "==" in a function signature, for instance?).
Below you seem to try another unconvincing reductio ad absurdum to suggest that I must either want a language with no symbols or support this PEP.
I think the cognitive complexity of a line with sigils is somewhere around quadratic or cubic on the number of distinct sigils. But when several look similar, it quickly tends toward the higher end. And when several have related meanings, it's harder still to read.
It shouldn't need to be. Once you know how expressions are built up, it should give linear complexity. Did the introduction of the @ (matrix multiplication) operator to Python increase the language's complexity multiplicatively, or additively? Be honest now: are your programs more confusing to read because @ could have been *, because @ could have been +, because @ could have been ==, etc etc etc, or is it only that @ is one new operator, additively with the other operators? Even when syntactically it's multiplicative, it's often possible to be merely additive in cognitive burden. Augmented assignment broadly functions as a single feature - "x #= y" parallels "x = x # y" for any operator where that's legal.
When I write an expression like 'a - b * c / d**e + f' that also has a bunch of symbols. But they are symbols that:
- look strongly distinct - have meanings familiar from childhood - have strongly different meanings (albeit all related to arithmetic)
The double asterisk wasn't one that I used in my childhood, yet in programming, I simply learned it and started using it. What happens is that known concepts are made use of to teach others. It's the same with every feature, and this one is no different: if you already understand "def f(x=1)", it is only a small step to "def f(x=>[])", and everything you already know is still valid.
Yes, I probably have to think for a while about operator precedence to make sure I understand it. Probably I'll add some redundant parens if I can edit the code. But the cognitive burden of the sigils remains FAR lower than what would occur with regularity under PEP 671.
Is that simply because you already are familiar with those operators, or is there something inherently different about them? Would it really be any different?
I already dislike the walrus operator in signature context for that reason... although I think it's great for e.g. 'while a := getdata() > 0: ...'
Then don't use it in a signature. That's fine. Personally, I've never used the "def f(x=_sentinel:=object())" trick, because it has very little value - it makes the function header carry information that actually isn't part of the function signature (that the object is also in the surrounding context as "_sentinel" - the function's caller can't use that information), and doesn't have any real advantages over just putting it a line above. But that's because of what the feature does, not how it's spelled. An expression is an expression. Any competent programmer should be able to read them as such. ChrisA