On Sun, Jan 19, 2020 at 8:16 PM Andrew Barnert <abarnert@yahoo.com> wrote:
On Jan 19, 2020, at 15:20, Guido van Rossum <guido@python.org> wrote:

On Sun, Jan 19, 2020 at 3:10 PM Tim Peters <tim.peters@gmail.com> wrote:
[Guido, on Pythons before 1.0.2 always printing non-None expression
 statement results]
> Heh. That was such a misfeature that I had thoroughly suppressed any
> memory of its existence. -k indeed. :-)

I prefer to think of it as a bit of genius :-)

The natural desire to avoid mounds of useless output taught all of us,
core developers and end users, to code mutating methods as procedures
(always return None) rather than functions.

The thing that amazed me at the time (and still does with hindsight!)
is how very few complaints that attracted!  Because it really was a
horrible misfeature ;-)

My guess is that method chaining wasn't in widespread use, and languages that made a distinction between functions and procedures (a la Pascal and Fortran) were more common than they are now.

One thing that we lost when we dropped this: the bug where a user wrote `foo` rather than `foo()` was caught more reliably then. Similarly, in the async world, there's a common mistake where users write `foo()` rather than `await foo()`, and that behavior would have caught such bugs.

Now we can't even flag such things statically (e.g. in mypy) because people might complain that they *meant* to write what they wrote (since it works).

Personally, I love the fact that in Python, the way to reference a function foo or a method baz on bar is just `foo` or `bar.baz`, and the way to call that thing later is just parens. There’s no `&foo`, much less `bar` and `&bar::baz` as separate arguments or passing the method name as a string (or inventing a new symbol or selector type that’s almost the same as a string but not) or wrapping it in a useless lambda or block, etc. as in Ruby, Smalltalk, JS, C++, etc.

Sure, it means you can’t have no-parens calling syntax (unless you curry all functions a la Haskell, but then it’s very hard to have variable-signature functions) or flag accidental no-parens calls as errors. But being able to refer to all things, even functions and methods, with the one and only one obvious spelling for each thing is nice.

Yes of course. :-)

And linters and analyzers do already flag the most common error case, where you just put `foo` instead of `foo()` on a like by itself (because it’s an expression that has no side effects but you don’t use its value). It’s only when you accidentally do something like `bar = foo` instead of `bar = foo()` (and then don’t use `bar` in a way that would detectably cause a TypeError) that can’t be detected.

Actually, `bar = foo` is more likely to be detected by mypy, since it is probably a type error (unless bar isn't used or is only used in an `Any` context). For mypy, flagging bare `foo` is harder, because we would have to introduce a fairly arbitrary rule that says "a top-level expression cannot have a callable type". So we haven't done this yet. (Ditto for omitting `await`, for which we would have to have a rule "a top-level expression cannot have an awaitable type".)

--
--Guido van Rossum (python.org/~guido)