Let me preface this by saying: I've already addressed the possibility of a
form that tells you up-front that it's a function
Granted it was 8 replies ago and at the end of a long-winded response, so
I'll summarize here:

A format like <PREFIX><EXPRESSION>[<SEPARATOR><SIGNATURE>] would, in my
view, be preferable to a format that puts the signature first.
An example might be:

hand = sorted(cards, by=def card.suit with card)
hand = sorted(cards, by=return card.suit from card)
hand = sorted(cards, by=(:card.suit with card))  # the happiest form!
hand = sorted(cards, by==>card.suit :: card)  # eh...
etc...

There are many possibilities.

[MRAB]

> You're complaining that it's "noise", but I think you need a bit of
> noise to tell you that it's defining a function


I feel like the pseudo code example shows that at least isn't *always*
true. Yes, the noise is neccessary for the
computer's sake, but it doesn't have to go in-front of the logic. It's
usually not that important for the reader.
The intent is to sort cards by suit, not to declare a function that gets
the suit of a card. The fact that you have
to declare a function is secondary to the intent.

If it were up to me, I'd make "by" the keyword for a key-function in
sorted, sort, min, max, etc.
and have special secondary keywords for simple, common cases:

>>> hand = sorted(cards, by_attr="suit")
>>> exam_grades.sort(by_item=-1)
etc...

[MRAB]

> otherwise you'll see an expression and think it's evaluated immediately,
> but then you'll see the
> "with" at the end telling you "oh, by the way, this is a function,
> so don't evaluate it now".


That's true of most expressions:

>>> grades = {"Sally": 92, "Jimmy": 83, "Beth": 87, "Alex": 98}
>>> best_student = max(grades, key=grades.get)
>>> print(best_student)
'Alex'

Assuming you know that grades.get is a method, you don't know that the
expression passed to 'key'
is a function until you read the whole expression. If you don't know what
grades.get is, you don't know
what kind of object is being passed to key:

>>> best_student = max(spam, key=spam.eggs)

Is it catastrophic that you don't know what ham.eggs is?
Is it something to do with card.suit with card being a literal that
makes you demand to know what type of thing is being passed before you
finish reading the expression?
Because that clearly isn't true in the case of variables.

Besides; you usually have several context clues leading up to the 'with' :

1) The function (if you're familiar with it)

2) The name of the function (if it's well named and you are familiar with
the name)
e.g. add_callback, add_handler, on_mouseover, etc..

3) The name of a keyword parameter (if it's well named and you're familiar
with the name)
e.g. key, callback, handler, event_handler, filter, etc...

4) The usage of a variable that has yet to be declared (just like in
generator/comprehension expressions)
example:

def best_hand(cards):
    hand = sorted(cards, key=card.suit with card)
    ...

My hunch is that the vast majority of cases satisfy enough of those that
reading a 'with' would rarely be all that surprising.
I also assert that some of those conditions are far more critical to
comprehending code, so if they're missing, your comprehension
ends long before you're "surprised" by the appearance of a 'with'.
All of the arguments in the following are clearly declared literals:

foo = bar.baz(100, True, ham="spam")

Can you read that? In a sense, yes. Can you comprehend it? No! What if I
asked you "where's the bug?".
Nope.

Another example (from D'Aprano):

sm = difflib.SequenceMatcher(isjunk=True)
t = threading.Thread(target="hello")

Now imagine that none of the 4 context clues above are true. Can you read
those? Can you see the bugs? Is there even a point to reading beyond where
your comprehension stops?
If you don't know anything about what's expected for "target" or "isjunk"
than reading any further isn't helpful.
Knowing that "hello" is a string right away saves you no pain. The
paramount problem is that you don't know that it's supposed to be a
function. You need to stop when you loose comprehension and read the docs.
Then when you come back, you'll know that 'isjunk' should be a function.
The counter that there may be cases where none of the 4 context clues above
exist indicates a more urgent problem than knowing the types of literals
being passed (immediately or otherwise).

Also, by the time you hit the "with" it's not like the "new information"
requires you to look back and re-examine anything. It's just new
information like any other compound statement:

>>> spam.eggs(ham)[parrot]
# it's the value of 'spam'...
# or rather the attribute 'eggs' of 'spam'...
# or rather the result of calling the method 'eggs' of 'spam' with 'ham'...
# or rather it's the 'parrot'th item of the result of calling the method
'eggs' of 'spam' with 'ham'

[MRAB]

> You gave an example in JavaScript and said that students had "very
> little trouble" with it, but notice how the function itself began with a
> reserved word.
> If you're complaining about the word "lambda", that's fine,


Yes, that was the context of the discussion I was referencing. Just the
word "lambda".
In this ongoing discussion I've declared on two separate gripes: 1) the
word itself and 2) the format.

I think a different format opens up other possible word choices, but that's
not really important.
_______________________________________________
Python-ideas mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to