Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return value of builtins is not clearly indicated #90440

Open
snoopjedi mannequin opened this issue Jan 6, 2022 · 19 comments
Open

return value of builtins is not clearly indicated #90440

snoopjedi mannequin opened this issue Jan 6, 2022 · 19 comments
Labels
3.11 only security fixes docs Documentation in the Doc dir

Comments

@snoopjedi
Copy link
Mannequin

snoopjedi mannequin commented Jan 6, 2022

BPO 46282
Nosy @warsaw, @terryjreedy, @nedbat, @merwok, @stevendaprano, @iritkatriel, @snoopjedi
PRs
  • bpo-46282 Add return value to print() doc #30435
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2022-01-06.14:52:27.230>
    labels = ['3.11', 'docs']
    title = 'return value of builtins is not clearly indicated'
    updated_at = <Date 2022-02-12.01:20:07.186>
    user = 'https://github.com/SnoopJeDi'

    bugs.python.org fields:

    activity = <Date 2022-02-12.01:20:07.186>
    actor = 'rhettinger'
    assignee = 'docs@python'
    closed = False
    closed_date = None
    closer = None
    components = ['Documentation']
    creation = <Date 2022-01-06.14:52:27.230>
    creator = 'SnoopJeDi'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 46282
    keywords = ['patch']
    message_count = 17.0
    messages = ['409857', '409870', '409874', '409883', '409886', '410038', '410046', '411632', '411653', '411664', '411668', '411809', '411835', '412797', '412811', '412836', '412838']
    nosy_count = 8.0
    nosy_names = ['barry', 'terry.reedy', 'nedbat', 'eric.araujo', 'steven.daprano', 'docs@python', 'iritkatriel', 'SnoopJeDi']
    pr_nums = ['30435']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue46282'
    versions = ['Python 3.11']

    @snoopjedi snoopjedi mannequin added 3.11 only security fixes labels Jan 6, 2022
    @snoopjedi snoopjedi mannequin assigned docspython Jan 6, 2022
    @snoopjedi snoopjedi mannequin added docs Documentation in the Doc dir labels Jan 6, 2022
    @stevendaprano
    Copy link
    Member

    Do the print docs need to mention something so obvious?

    Functions and methods which operate by side-effect typically don't mention that they return None, see for example the docs for various builtin methods:

    https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types

    e.g. s.append, s.clear, s.extend, s.insert, s.remove, s.reverse

    and likewise for list.sort, set.add, dict.clear and many others.

    (However, dict.update is a rare exception, it does mention that it returns None.)

    We should not feel it necessary to add an explicit comment to every function or method that operates by side-effect stating that they return None.

    @snoopjedi
    Copy link
    Mannequin Author

    snoopjedi mannequin commented Jan 6, 2022

    I opened this ticket on behalf of a user who asked about print() specifically in #python on the Libera IRC network, who I assume does not find this obvious.

    I don't think it would be tenable to add this note to every built-in, but that's not the intended scope of this issue. I do think it's worth mentioning for print(), though.

    @warsaw
    Copy link
    Member

    warsaw commented Jan 6, 2022

    I think it does a better service to users to explain how Python returns None implicitly if a function doesn't have any other explicit return value. If the print() docs had this note, it would be confusing why other similar functions don't.

    It's also worth explaining that when a function is designed to explicitly return None in certain cases (e.g. dict.get()) that it shouldn't do so implicitly, but should include an explicit return None for readability.

    @stevendaprano
    Copy link
    Member

    Sure, there will always be some users who will find certain things not
    obvious. Sometimes I'm that user myself.

    What did this user think print() returned? What precisely was their
    question? Perhaps if I saw the conversation in context, I would be more
    sympathetic to this.

    I can see a difference between (for example) the questions:

    "I see that print('Hello world') returns None, but is it safe to assume
    that print will *always* return None? It is not documented anywhere as
    far as I can see."

    and

    "What does x = print('Hello world') do?"

    @snoopjedi
    Copy link
    Mannequin Author

    snoopjedi mannequin commented Jan 6, 2022

    The original question was closer to the related issue of "indicate return types for all built-ins," conversation log follows (UTC-5):

    09:33:50         ringo__ | is there a stdlib api docs which actually has *full* functions signature?                                                                                                       
    09:34:27         ringo__ | for example, https://docs.python.org/3/library/functions.html, function                                                                                                         
                             | abs(x), it returns what, int? I need to read the whole sentence to figure                                                                                                       
                             | out the return value of a function?                                                                                                                                             
    09:34:48         ringo__ | (or argument for that matter)                                                                                                                                                   
    09:35:51             bjs | ringo__: well like it says it doesn't just support int                                                                                                                          
    09:36:00             bjs | int, float, or any type that supports it                                                                                                                                        
    09:37:01             bjs | in general you can find actual type annotations for the functions in the                                                                                                        
                             | typeshed                                                                                                                                                                        
                             | https://github.com/python/typeshed/blob/master/stdlib/builtins.pyi                                                                                                              
    09:37:32             bjs | I wonder if it would be useful to include the typeshed annotation in the                                                                                                        
                             | docs, or whether it would be more confusing                                                                                                                                     
    09:37:49         ringo__ | Thanks bjs ! I'll bookmark this typeshed                                                                                                                                        
    09:38:13          SnoopJ | abs() will do whatever __abs__() on the type does, which can be different                                                                                                       
                             | for any given type. You'd expect T -> T but it's not guaranteed.                                                                                                                
    09:38:18         ringo__ | I used abs() as an example. In fact I was wondering what does print()                                                                                                           
                             | return. I *guessed* it returns None, but the docs won't say                                                                                                                     
    09:39:05         ringo__ | I could do a try-it-yourself approach but I was puzzled why the docs                                                                                                            
                             | simply won't give you full fn signature, ie print(..) -> None                                                                                                                   
    09:39:17          SnoopJ | that one is just an omission :)
    

    @terryjreedy
    Copy link
    Member

    How about following "The Python interpreter has a number of functions and types built into it that are always available. They are listed here in alphabetical order." in
    https://docs.python.org/3/library/functions.html
    with "Here and elsewhere in these docs, entries for functions (including methods) that always return None usually omit 'Return None' and just say what the function does."

    Barry: The PEP-8 'return None' recommendation could be added to the Reference entry for 'return'. But I think this should be a separate issue as 1) it is about coding rather than documentation and 2) there is the possible objection that choosing completely explicit 'return None' versus half explicit, half implicit 'return' and the latter versus completely implicit <nothing at end> should be left to the style PEP.

    @warsaw
    Copy link
    Member

    warsaw commented Jan 7, 2022

    Barry: The PEP-8 'return None' recommendation could be added to the Reference entry for 'return'. But I think this should be a separate issue as 1) it is about coding rather than documentation and 2) there is the possible objection that choosing completely explicit 'return None' versus half explicit, half implicit 'return' and the latter versus completely implicit <nothing at end> should be left to the style PEP.

    I do think it's a question of style. Section 7.6 of the language reference says:

    If an expression list is present, it is evaluated, else None is substituted.

    which is the important concept that beginners should learn.

    I agree that the admonition in PEP-8 is really trying to say "don't mix implicit and explicit return styles". Implicit None return is fine if all exit paths are implicit. But once you add an explicit value to a return path, all return paths should use explicit values, including those that return None.

    IME, while I do occasionally encounter push back on this when doing reviews, most folks come around to this p.o.v.

    @snoopjedi snoopjedi mannequin changed the title print() docs do not indicate its return value return value of builtins is not clearly indicated Jan 25, 2022
    @snoopjedi snoopjedi mannequin changed the title print() docs do not indicate its return value return value of builtins is not clearly indicated Jan 25, 2022
    @merwok
    Copy link
    Member

    merwok commented Jan 25, 2022

    The new title is puzzling; the discussion moved to advertising that all functions default to returning None, this is not related to the built-in status.

    @snoopjedi
    Copy link
    Mannequin Author

    snoopjedi mannequin commented Jan 25, 2022

    advertising that all functions default to returning None

    This is already communicated in § 4.7 ("Defining Functions") of the official tutorial.

    I think it would be a good idea to revise that section so that this property of functions is a little more clear, but that isn't the scope of this ticket.

    The title change reflects my intent to submit a PR that adds a hint to the builtins doc.

    @terryjreedy
    Copy link
    Member

    Please post your proposed change here to be discussed by participants here.

    @snoopjedi
    Copy link
    Mannequin Author

    snoopjedi mannequin commented Jan 25, 2022

    My thought was to add something like this to the top of functions.rst:

    Note that some of the functions listed here have the :ref:`default return value <tut-defining-functions> of ``None``.
    

    For reference, the builtins this applies to are:

    • breakpoint()
    • delattr()
    • exec()
    • help()
    • print()
    • setattr()

    Which makes me wonder if the hint is even worth having, since it's so few of them.

    Note that of these, exec() does what this ticket originally proposed for print() - i.e. it explicitly says that the function returns None.

    @iritkatriel
    Copy link
    Member

    "have the :ref:`default return value <tut-defining-functions> of ``None``."

    This sounds to me like "by default they return None but you can override this default".

    I don't think any change to the doc makes sense here. When you state the obvious people wonder what they're missing.

    @terryjreedy
    Copy link
    Member

    Steven, I am also inclined to close this. What do you think after the discussion? It is sometimes easier to clarify when we have a confused person present in the discussion.

    @nedbat
    Copy link
    Member

    nedbat commented Feb 7, 2022

    When you state the obvious...

    Obvious to who? New learners coming to Python don't know the same things as people with experience.

    @rhettinger
    Copy link
    Contributor

    New learners coming to Python don't know the same things
    as people with experience.

    IMO, new learners will be worse off by adding "returns None" to all of the builtins. At best it a distractor.

    I work with new learners almost every day. The issue never arises. No one writes "x = print('hello world')" and they would be worse off if shown such a possibility.

    One other consideration is that MyPy and the tools that use it (such as PyCharm) reject the idea of None as return value. Their view is that no value is returned all. We don't want the docs to contradict that world view.

      $ cat hello.py
      x = print('hello world')
      $ mypy hello.py
      hello.py:1: error: "print" does not return a value
      Found 1 error in 1 file (checked 1 source file)

    @nedbat
    Copy link
    Member

    nedbat commented Feb 8, 2022

    What we're debating here is a micro-cosm of the broader "documentation philosophy" questions that I'm hoping the Documentation WG can iron out.

    What is "obvious"? Is it obvious that print returns None when file.write does not? Why does "exec" explicitly say it returns None, and no beginners were harmed, but having "print" say it returns None would be bad?

    @iritkatriel
    Copy link
    Member

    I should have said "redundant information" rather than "obvious".

    I consider it redundant to specify that the default behavior applies to some specific case. If I read redundant information I may pause to think why it was necessary to explicitly state it, and whether I am misunderstanding something.

    (Let's not make my bad choice of word turn this into a discussion about "what is obvious". The issue will probably never be closed if we do that.)

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @SnoopJ
    Copy link
    Contributor

    SnoopJ commented May 12, 2022

    I think it would be a good idea to revise that section so that this [implicit return of None] property of functions is a little more clear, but that isn't the scope of this ticket.

    Discussion about this side issue came up again on Libera, see #92753.

    @saaketp
    Copy link

    saaketp commented Nov 25, 2022

    Instead of specifying the return type in the text, which is a bit verbose and easy to miss in a wall of text, the return types could be mentioned in the function signature (if they are not too complicated).

    This is already done in some places
    like this one specifies the return type
    https://docs.python.org/3/library/time.html#time.clock_gettime

    and this one specifies the parameter type
    https://docs.python.org/3/library/time.html#time.clock_settime

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.11 only security fixes docs Documentation in the Doc dir
    Projects
    None yet
    Development

    No branches or pull requests

    9 participants